Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / ncp / ncp_mod.c
1 /*
2  * Copyright (c) 1999, Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD: src/sys/netncp/ncp_mod.c,v 1.2 1999/10/12 10:36:59 bp Exp $
33  */
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/sysproto.h>
37 #include <sys/sysent.h>
38 #include <sys/proc.h>
39 #include <sys/kernel.h>
40 #include <sys/sysctl.h>
41 #include <sys/malloc.h>
42 #include <sys/uio.h>
43
44 #include <netncp/ncp.h>
45 #include <netncp/ncp_conn.h>
46 #include <netncp/ncp_subr.h>
47 #include <netncp/ncp_ncp.h>
48 #include <netncp/ncp_user.h>
49 #include <netncp/ncp_rq.h>
50 #include <netncp/ncp_nls.h>
51
52 int ncp_version = NCP_VERSION;
53
54 static int ncp_sysent;
55
56 SYSCTL_NODE(_net, OID_AUTO, ncp, CTLFLAG_RW, NULL, "NetWare requester");
57 SYSCTL_INT(_net_ncp, OID_AUTO, sysent, CTLFLAG_RD, &ncp_sysent, 0, "");
58 SYSCTL_INT(_net_ncp, OID_AUTO, version, CTLFLAG_RD, &ncp_version, 0, "");
59
60 static int
61 ncp_conn_frag_rq(struct ncp_conn *conn, struct proc *p, struct ncp_conn_frag *nfp);
62
63 /*
64  * Attach to NCP server
65  */
66 struct sncp_connect_args {
67         struct ncp_conn_args *li;
68         int *connHandle;
69 };
70
71 static int 
72 __P(sncp_connect(struct proc *p, struct sncp_connect_args *uap)){
73         int connHandle = 0, error;
74         struct ncp_conn *conn;
75         struct ncp_handle *handle;
76         struct ncp_conn_args li;
77
78         checkbad(copyin(uap->li,&li,sizeof(li)));
79         checkbad(copyout(&connHandle,uap->connHandle,sizeof(connHandle))); /* check before */
80         li.password = li.user = NULL;
81         error = ncp_conn_getattached(&li, p, p->p_ucred, NCPM_WRITE | NCPM_EXECUTE, &conn);
82         if (error) {
83                 error = ncp_connect(&li, p, p->p_ucred, &conn);
84         }
85         if (!error) {
86                 error = ncp_conn_gethandle(conn, p, &handle);
87                 copyout(&handle->nh_id, uap->connHandle, sizeof(uap->connHandle));
88                 ncp_conn_unlock(conn,p);
89         }
90 bad:
91         p->p_retval[0]=error;
92         return error;
93 }
94
95 struct sncp_request_args {
96         int connHandle;
97         int fn;
98         struct ncp_buf *ncpbuf;
99 };
100
101 static int ncp_conn_handler(struct proc *p, struct sncp_request_args *uap,
102         struct ncp_conn *conn, struct ncp_handle *handle);
103
104 static int
105 __P(sncp_request(struct proc *p, struct sncp_request_args *uap)){
106         int error = 0, rqsize;
107         struct ncp_conn *conn;
108         struct ncp_handle *handle;
109         DECLARE_RQ;
110
111         error = ncp_conn_findhandle(uap->connHandle,p,&handle);
112         if (error) return error;
113         conn = handle->nh_conn;
114         if (uap->fn == NCP_CONN)
115                 return ncp_conn_handler(p, uap, conn, handle);
116         error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
117         if (error) return(error);
118         error = ncp_conn_lock(conn,p,p->p_ucred,NCPM_EXECUTE);
119         if (error) return(error);
120         ncp_rq_head(rqp,NCP_REQUEST,uap->fn,p,p->p_ucred);
121         if (rqsize)
122                 error = ncp_rq_usermem(rqp,(caddr_t)uap->ncpbuf->packet, rqsize);
123         if (!error) {
124                 error = ncp_request(conn, rqp);
125                 if (error == 0 && rqp->rpsize)
126                         ncp_rp_usermem(rqp, (caddr_t)uap->ncpbuf->packet, 
127                                 rqp->rpsize);
128                 copyout(&rqp->cs, &uap->ncpbuf->cs, sizeof(rqp->cs));
129                 copyout(&rqp->cc, &uap->ncpbuf->cc, sizeof(rqp->cc));
130                 copyout(&rqp->rpsize, &uap->ncpbuf->rpsize, sizeof(rqp->rpsize));
131         }
132         ncp_rq_done(rqp);
133         ncp_conn_unlock(conn,p);
134         return error;
135 }
136
137 static int
138 ncp_conn_handler(struct proc *p, struct sncp_request_args *uap,
139         struct ncp_conn *conn, struct ncp_handle *hp)
140 {
141         int error=0, rqsize, subfn;
142         struct ucred *cred;
143         
144         char *pdata;
145
146         cred = p->p_ucred;
147         error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
148         if (error) return(error);
149         error = 0;
150         pdata = uap->ncpbuf->packet;
151         subfn = *(pdata++) & 0xff;
152         rqsize--;
153         switch (subfn) {
154             case NCP_CONN_READ: case NCP_CONN_WRITE: {
155                 struct ncp_rw rwrq;
156                 struct uio auio;
157                 struct iovec iov;
158         
159                 if (rqsize != sizeof(rwrq)) return (EBADRPC);   
160                 error = copyin(pdata,&rwrq,rqsize);
161                 if (error) return (error);
162                 iov.iov_base = rwrq.nrw_base;
163                 iov.iov_len = rwrq.nrw_cnt;
164                 auio.uio_iov = &iov;
165                 auio.uio_iovcnt = 1;
166                 auio.uio_offset = rwrq.nrw_offset;
167                 auio.uio_resid = rwrq.nrw_cnt;
168                 auio.uio_segflg = UIO_USERSPACE;
169                 auio.uio_rw = (subfn == NCP_CONN_READ) ? UIO_READ : UIO_WRITE;
170                 auio.uio_procp = p;
171                 error = ncp_conn_lock(conn,p,cred,NCPM_EXECUTE);
172                 if (error) return(error);
173                 if (subfn == NCP_CONN_READ)
174                         error = ncp_read(conn, &rwrq.nrw_fh, &auio, cred);
175                 else
176                         error = ncp_write(conn, &rwrq.nrw_fh, &auio, cred);
177                 rwrq.nrw_cnt -= auio.uio_resid;
178                 ncp_conn_unlock(conn,p);
179                 p->p_retval[0] = rwrq.nrw_cnt;
180                 break;
181             } /* case int_read/write */
182             case NCP_CONN_SETFLAGS: {
183                 u_int16_t mask, flags;
184
185                 error = copyin(pdata,&mask, sizeof(mask));
186                 if (error) return error;
187                 pdata += sizeof(mask);
188                 error = copyin(pdata,&flags,sizeof(flags));
189                 if (error) return error;
190                 error = ncp_conn_lock(conn,p,cred,NCPM_WRITE);
191                 if (error) return error;
192                 if (mask & NCPFL_PERMANENT) {
193                         conn->flags &= ~NCPFL_PERMANENT;
194                         conn->flags |= (flags & NCPFL_PERMANENT);
195                 }
196                 if (mask & NCPFL_PRIMARY) {
197                         error = ncp_conn_setprimary(conn, flags & NCPFL_PRIMARY);
198                         if (error) {
199                                 ncp_conn_unlock(conn,p);
200                                 break;
201                         }
202                 }
203                 ncp_conn_unlock(conn,p);
204                 break;
205             }
206             case NCP_CONN_LOGIN: {
207                 struct ncp_conn_login la;
208
209                 if (rqsize != sizeof(la)) return (EBADRPC);     
210                 if ((error = copyin(pdata,&la,rqsize)) != 0) break;
211                 error = ncp_conn_lock(conn, p, cred, NCPM_EXECUTE | NCPM_WRITE);
212                 if (error) return error;
213                 error = ncp_login(conn, la.username, la.objtype, la.password, p, p->p_ucred);
214                 ncp_conn_unlock(conn, p);
215                 p->p_retval[0] = error;
216                 break;
217             }
218             case NCP_CONN_GETINFO: {
219                 struct ncp_conn_stat ncs;
220                 int len = sizeof(ncs);
221
222                 error = ncp_conn_lock(conn, p, p->p_ucred, NCPM_READ);
223                 if (error) return error;
224                 ncp_conn_getinfo(conn, &ncs);
225                 copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
226                 error = copyout(&ncs, &uap->ncpbuf->packet, len);
227                 ncp_conn_unlock(conn, p);
228                 break;
229             }
230             case NCP_CONN_GETUSER: {
231                 int len;
232
233                 error = ncp_conn_lock(conn, p, p->p_ucred, NCPM_READ);
234                 if (error) return error;
235                 len = (conn->li.user) ? strlen(conn->li.user) + 1 : 0;
236                 copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
237                 if (len) {
238                         error = copyout(conn->li.user, &uap->ncpbuf->packet, len);
239                 }
240                 ncp_conn_unlock(conn, p);
241                 break;
242             }
243             case NCP_CONN_CONN2REF: {
244                 int len = sizeof(int);
245
246                 error = ncp_conn_lock(conn, p, p->p_ucred, NCPM_READ);
247                 if (error) return error;
248                 copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
249                 if (len) {
250                         error = copyout(&conn->nc_id, &uap->ncpbuf->packet, len);
251                 }
252                 ncp_conn_unlock(conn, p);
253                 break;
254             }
255             case NCP_CONN_FRAG: {
256                 struct ncp_conn_frag nf;
257
258                 if (rqsize != sizeof(nf)) return (EBADRPC);     
259                 if ((error = copyin(pdata, &nf, rqsize)) != 0) break;
260                 error = ncp_conn_lock(conn, p, cred, NCPM_EXECUTE);
261                 if (error) return error;
262                 error = ncp_conn_frag_rq(conn, p, &nf);
263                 ncp_conn_unlock(conn, p);
264                 copyout(&nf, &pdata, sizeof(nf));
265                 p->p_retval[0] = error;
266                 break;
267             }
268             case NCP_CONN_DUP: {
269                 struct ncp_handle *newhp;
270                 int len = sizeof(NWCONN_HANDLE);
271
272                 error = ncp_conn_lock(conn, p, cred, NCPM_READ);
273                 if (error) break;
274                 copyout(&len, &uap->ncpbuf->rpsize, len);
275                 error = ncp_conn_gethandle(conn, p, &newhp);
276                 if (!error)
277                         error = copyout(&newhp->nh_id, uap->ncpbuf->packet, len);
278                 ncp_conn_unlock(conn,p);
279                 break;
280             }
281             case NCP_CONN_CONNCLOSE: {
282                 error = ncp_conn_lock(conn, p, cred, NCPM_EXECUTE);
283                 if (error) break;
284                 ncp_conn_puthandle(hp, p, 0);
285                 error = ncp_disconnect(conn);
286                 if (error)
287                         ncp_conn_unlock(conn, p);
288                 break;
289             }
290             default:
291                     error = EOPNOTSUPP;
292         }
293         return error;
294 }
295
296 struct sncp_conn_scan_args {
297         struct ncp_conn_args *li;
298         int *connHandle;
299 };
300
301 static int 
302 __P(sncp_conn_scan(struct proc *p, struct sncp_conn_scan_args *uap)){
303         int connHandle = 0, error;
304         struct ncp_conn_args li, *lip;
305         struct ncp_conn *conn;
306         struct ncp_handle *hp;
307         char *user = NULL, *password = NULL;
308
309         if (uap->li) {
310                 if (copyin(uap->li,&li,sizeof(li))) return EFAULT;
311                 lip = &li;
312         } else {
313                 lip = NULL;
314         }
315
316         if (lip != NULL) {
317                 lip->server[sizeof(lip->server)-1]=0; /* just to make sure */
318                 ncp_str_upper(lip->server);
319                 if (lip->user) {
320                         user = ncp_str_dup(lip->user);
321                         if (user == NULL) return EINVAL;
322                         ncp_str_upper(user);
323                 }
324                 if (lip->password) {
325                         password = ncp_str_dup(lip->password);
326                         if (password == NULL) {
327                                 if (user)
328                                         free(user, M_NCPDATA);
329                                 return EINVAL;
330                         }
331                         ncp_str_upper(password);
332                 }
333                 lip->user = user;
334                 lip->password = password;
335         }
336         error = ncp_conn_getbyli(lip,p,p->p_ucred,NCPM_EXECUTE,&conn);
337         if (!error) {           /* already have this login */
338                 ncp_conn_gethandle(conn, p, &hp);
339                 connHandle = hp->nh_id;
340                 ncp_conn_unlock(conn,p);
341                 copyout(&connHandle,uap->connHandle,sizeof(connHandle));
342         }
343         if (user) free(user, M_NCPDATA);
344         if (password) free(password, M_NCPDATA);
345         p->p_retval[0] = error;
346         return error;
347
348 }
349
350 int
351 ncp_conn_frag_rq(struct ncp_conn *conn, struct proc *p, struct ncp_conn_frag *nfp){
352         int error = 0, i, rpsize;
353         u_int32_t fsize;
354         NW_FRAGMENT *fp;
355         DECLARE_RQ;
356
357         ncp_rq_head(rqp,NCP_REQUEST,nfp->fn,p,p->p_ucred);
358         if (nfp->rqfcnt) {
359                 for(fp = nfp->rqf, i = 0; i < nfp->rqfcnt; i++, fp++) {
360                         checkbad(ncp_rq_usermem(rqp,(caddr_t)fp->fragAddress, fp->fragSize));
361                 }
362         }
363         checkbad(ncp_request(conn, rqp));
364         rpsize = rqp->rpsize;
365         if (rpsize && nfp->rpfcnt) {
366                 for(fp = nfp->rpf, i = 0; i < nfp->rpfcnt; i++, fp++) {
367                         checkbad(copyin(&fp->fragSize, &fsize, sizeof (fsize)));
368                         fsize = min(fsize, rpsize);
369                         checkbad(ncp_rp_usermem(rqp,(caddr_t)fp->fragAddress, fsize));
370                         rpsize -= fsize;
371                         checkbad(copyout(&fsize, &fp->fragSize, sizeof (fsize)));
372                 }
373         }
374         nfp->cs = rqp->cs;
375         nfp->cc = rqp->cc;
376         NCP_RQ_EXIT;
377         return error;
378 }
379
380 /*
381  * Internal functions, here should be all calls that do not require connection.
382  * To simplify possible future movement to cdev, we use IOCTL macros.
383  * Pretty much of this stolen from ioctl() function.
384  */
385 struct sncp_intfn_args {
386         u_long  com;
387         caddr_t data;
388 };
389
390 static int
391 sncp_intfn(struct proc *p, struct sncp_intfn_args *uap)
392 {
393         return ENOSYS;
394 }
395 /*
396  * define our new system calls
397  */
398 static struct sysent newent[] = {
399         {2,     (sy_call_t*)sncp_conn_scan},
400         {2,     (sy_call_t*)sncp_connect},
401         {2,     (sy_call_t*)sncp_intfn},
402         {3,     (sy_call_t*)sncp_request}
403 };
404
405 #define SC_SIZE sizeof(newent)/sizeof(struct sysent)
406 /*
407  * Miscellaneous modules must have their own save areas...
408  */
409 static struct sysent    oldent[SC_SIZE];        /* save are for old callslot entry*/
410
411 /*
412  * Number of syscall entries for a.out executables
413  */
414 /*#define nsysent SYS_MAXSYSCALL*/
415 #define nsysent (aout_sysvec.sv_size)
416
417
418 static int
419 ncp_load(void) {
420         int i, ff, scnt, err=0;
421
422         while(1) {
423                 /* Search the table looking for an enough number of slots... */
424                 for (scnt=0, ff = -1, i = 0; i < nsysent; i++) {
425                         if (sysent[i].sy_call == (sy_call_t *)lkmnosys) {
426                                 if (ff == -1) {
427                                     ff = i;
428                                     scnt = 1;
429                                 } else {
430                                     scnt++;
431                                     if (scnt == SC_SIZE) break;
432                                 }
433                         } else {
434                                 ff = -1;
435                         }
436                 }
437                 /* out of allocable slots?*/
438                 if(i == nsysent || ff == -1) {
439                         err = ENFILE;
440                         break;
441                 }
442                 err = ncp_init();
443                 if (err) break;
444                 bcopy(&sysent[ff], &oldent, sizeof(struct sysent)*SC_SIZE);
445                 bcopy(&newent, &sysent[ff], sizeof(struct sysent)*SC_SIZE);
446                 ncp_sysent = ff;        /* slot in sysent[]*/
447                 printf("ncp_load: [%d-%d]\n",ff,i);
448                 break;
449         }
450
451         return( err);
452 }
453
454 static int
455 ncp_unload(void) {
456         ncp_done();
457         bcopy(&oldent, &sysent[ncp_sysent], sizeof(struct sysent) * SC_SIZE);
458         printf( "ncp_unload: unloaded\n");
459         return 0;
460 }
461
462 static int
463 ncp_mod_handler(module_t mod, int type, void *data)
464 {
465         int error;
466
467         switch (type) {
468             case MOD_LOAD:
469                 error = ncp_load();
470                 break;
471             case MOD_UNLOAD:
472                 error = ncp_unload();
473                 break;
474             default:
475                 error = EINVAL;
476         }
477         return error;
478 }
479                                                                \
480 static moduledata_t ncp_mod = {
481         "ncp",
482         ncp_mod_handler,
483         NULL
484 };
485 DECLARE_MODULE(ncp, ncp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);