proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[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  * $DragonFly: src/sys/netproto/ncp/ncp_mod.c,v 1.3 2003/06/25 03:56:05 dillon Exp $
34  */
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/sysproto.h>
38 #include <sys/sysent.h>
39 #include <sys/proc.h>
40 #include <sys/kernel.h>
41 #include <sys/sysctl.h>
42 #include <sys/malloc.h>
43 #include <sys/uio.h>
44
45 #include <netncp/ncp.h>
46 #include <netncp/ncp_conn.h>
47 #include <netncp/ncp_subr.h>
48 #include <netncp/ncp_ncp.h>
49 #include <netncp/ncp_user.h>
50 #include <netncp/ncp_rq.h>
51 #include <netncp/ncp_nls.h>
52
53 int ncp_version = NCP_VERSION;
54
55 static int ncp_sysent;
56
57 SYSCTL_NODE(_net, OID_AUTO, ncp, CTLFLAG_RW, NULL, "NetWare requester");
58 SYSCTL_INT(_net_ncp, OID_AUTO, sysent, CTLFLAG_RD, &ncp_sysent, 0, "");
59 SYSCTL_INT(_net_ncp, OID_AUTO, version, CTLFLAG_RD, &ncp_version, 0, "");
60
61 static int
62 ncp_conn_frag_rq(struct ncp_conn *conn, struct thread *td, struct ncp_conn_frag *nfp);
63
64 /*
65  * Attach to NCP server
66  */
67 struct sncp_connect_args {
68         struct ncp_conn_args *li;
69         int *connHandle;
70 };
71
72 static int 
73 sncp_connect(struct thread *td, struct sncp_connect_args *uap)
74 {
75         int connHandle = 0, error;
76         struct ncp_conn *conn;
77         struct ncp_handle *handle;
78         struct ncp_conn_args li;
79         struct ucred *cred;
80
81         KKASSERT(td->td_proc);
82         cred = td->td_proc->p_ucred;
83
84         checkbad(copyin(uap->li,&li,sizeof(li)));
85         checkbad(copyout(&connHandle,uap->connHandle,sizeof(connHandle))); /* check before */
86         li.password = li.user = NULL;
87         error = ncp_conn_getattached(&li, td, cred, NCPM_WRITE | NCPM_EXECUTE, &conn);
88         if (error) {
89                 error = ncp_connect(&li, td, cred, &conn);
90         }
91         if (!error) {
92                 error = ncp_conn_gethandle(conn, td, &handle);
93                 copyout(&handle->nh_id, uap->connHandle, sizeof(uap->connHandle));
94                 ncp_conn_unlock(conn,td);
95         }
96 bad:
97         td->td_proc->p_retval[0]=error;
98         return error;
99 }
100
101 struct sncp_request_args {
102         int connHandle;
103         int fn;
104         struct ncp_buf *ncpbuf;
105 };
106
107 static int ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
108         struct ncp_conn *conn, struct ncp_handle *handle);
109
110 static int
111 sncp_request(struct thread *td, struct sncp_request_args *uap)
112 {
113         int error = 0, rqsize;
114         struct ncp_conn *conn;
115         struct ncp_handle *handle;
116         struct ucred *cred;
117
118         DECLARE_RQ;
119
120         KKASSERT(td->td_proc);
121         cred = td->td_proc->p_ucred;
122
123         error = ncp_conn_findhandle(uap->connHandle,td,&handle);
124         if (error) return error;
125         conn = handle->nh_conn;
126         if (uap->fn == NCP_CONN)
127                 return ncp_conn_handler(td, uap, conn, handle);
128         error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
129         if (error) return(error);
130         error = ncp_conn_lock(conn,td,cred,NCPM_EXECUTE);
131         if (error) return(error);
132         ncp_rq_head(rqp,NCP_REQUEST,uap->fn,td,cred);
133         if (rqsize)
134                 error = ncp_rq_usermem(rqp,(caddr_t)uap->ncpbuf->packet, rqsize);
135         if (!error) {
136                 error = ncp_request(conn, rqp);
137                 if (error == 0 && rqp->rpsize)
138                         ncp_rp_usermem(rqp, (caddr_t)uap->ncpbuf->packet, 
139                                 rqp->rpsize);
140                 copyout(&rqp->cs, &uap->ncpbuf->cs, sizeof(rqp->cs));
141                 copyout(&rqp->cc, &uap->ncpbuf->cc, sizeof(rqp->cc));
142                 copyout(&rqp->rpsize, &uap->ncpbuf->rpsize, sizeof(rqp->rpsize));
143         }
144         ncp_rq_done(rqp);
145         ncp_conn_unlock(conn,td);
146         return error;
147 }
148
149 static int
150 ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
151         struct ncp_conn *conn, struct ncp_handle *hp)
152 {
153         int error=0, rqsize, subfn;
154         struct ucred *cred;
155         
156         char *pdata;
157
158         KKASSERT(td->td_proc);
159         cred = td->td_proc->p_ucred;
160
161         error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
162         if (error) return(error);
163         error = 0;
164         pdata = uap->ncpbuf->packet;
165         subfn = *(pdata++) & 0xff;
166         rqsize--;
167         switch (subfn) {
168             case NCP_CONN_READ: case NCP_CONN_WRITE: {
169                 struct ncp_rw rwrq;
170                 struct uio auio;
171                 struct iovec iov;
172         
173                 if (rqsize != sizeof(rwrq)) return (EBADRPC);   
174                 error = copyin(pdata,&rwrq,rqsize);
175                 if (error) return (error);
176                 iov.iov_base = rwrq.nrw_base;
177                 iov.iov_len = rwrq.nrw_cnt;
178                 auio.uio_iov = &iov;
179                 auio.uio_iovcnt = 1;
180                 auio.uio_offset = rwrq.nrw_offset;
181                 auio.uio_resid = rwrq.nrw_cnt;
182                 auio.uio_segflg = UIO_USERSPACE;
183                 auio.uio_rw = (subfn == NCP_CONN_READ) ? UIO_READ : UIO_WRITE;
184                 auio.uio_td = td;
185                 error = ncp_conn_lock(conn,td,cred,NCPM_EXECUTE);
186                 if (error) return(error);
187                 if (subfn == NCP_CONN_READ)
188                         error = ncp_read(conn, &rwrq.nrw_fh, &auio, cred);
189                 else
190                         error = ncp_write(conn, &rwrq.nrw_fh, &auio, cred);
191                 rwrq.nrw_cnt -= auio.uio_resid;
192                 ncp_conn_unlock(conn,td);
193                 td->td_proc->p_retval[0] = rwrq.nrw_cnt;
194                 break;
195             } /* case int_read/write */
196             case NCP_CONN_SETFLAGS: {
197                 u_int16_t mask, flags;
198
199                 error = copyin(pdata,&mask, sizeof(mask));
200                 if (error) return error;
201                 pdata += sizeof(mask);
202                 error = copyin(pdata,&flags,sizeof(flags));
203                 if (error) return error;
204                 error = ncp_conn_lock(conn,td,cred,NCPM_WRITE);
205                 if (error) return error;
206                 if (mask & NCPFL_PERMANENT) {
207                         conn->flags &= ~NCPFL_PERMANENT;
208                         conn->flags |= (flags & NCPFL_PERMANENT);
209                 }
210                 if (mask & NCPFL_PRIMARY) {
211                         error = ncp_conn_setprimary(conn, flags & NCPFL_PRIMARY);
212                         if (error) {
213                                 ncp_conn_unlock(conn,td);
214                                 break;
215                         }
216                 }
217                 ncp_conn_unlock(conn,td);
218                 break;
219             }
220             case NCP_CONN_LOGIN: {
221                 struct ncp_conn_login la;
222
223                 if (rqsize != sizeof(la)) return (EBADRPC);     
224                 if ((error = copyin(pdata,&la,rqsize)) != 0) break;
225                 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE | NCPM_WRITE);
226                 if (error) return error;
227                 error = ncp_login(conn, la.username, la.objtype, la.password, td, cred);
228                 ncp_conn_unlock(conn, td);
229                 td->td_proc->p_retval[0] = error;
230                 break;
231             }
232             case NCP_CONN_GETINFO: {
233                 struct ncp_conn_stat ncs;
234                 int len = sizeof(ncs);
235
236                 error = ncp_conn_lock(conn, td, cred, NCPM_READ);
237                 if (error) return error;
238                 ncp_conn_getinfo(conn, &ncs);
239                 copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
240                 error = copyout(&ncs, &uap->ncpbuf->packet, len);
241                 ncp_conn_unlock(conn, td);
242                 break;
243             }
244             case NCP_CONN_GETUSER: {
245                 int len;
246
247                 error = ncp_conn_lock(conn, td, cred, NCPM_READ);
248                 if (error) return error;
249                 len = (conn->li.user) ? strlen(conn->li.user) + 1 : 0;
250                 copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
251                 if (len) {
252                         error = copyout(conn->li.user, &uap->ncpbuf->packet, len);
253                 }
254                 ncp_conn_unlock(conn, td);
255                 break;
256             }
257             case NCP_CONN_CONN2REF: {
258                 int len = sizeof(int);
259
260                 error = ncp_conn_lock(conn, td, cred, NCPM_READ);
261                 if (error) return error;
262                 copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
263                 if (len) {
264                         error = copyout(&conn->nc_id, &uap->ncpbuf->packet, len);
265                 }
266                 ncp_conn_unlock(conn, td);
267                 break;
268             }
269             case NCP_CONN_FRAG: {
270                 struct ncp_conn_frag nf;
271
272                 if (rqsize != sizeof(nf)) return (EBADRPC);     
273                 if ((error = copyin(pdata, &nf, rqsize)) != 0) break;
274                 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE);
275                 if (error) return error;
276                 error = ncp_conn_frag_rq(conn, td, &nf);
277                 ncp_conn_unlock(conn, td);
278                 copyout(&nf, &pdata, sizeof(nf));
279                 td->td_proc->p_retval[0] = error;
280                 break;
281             }
282             case NCP_CONN_DUP: {
283                 struct ncp_handle *newhp;
284                 int len = sizeof(NWCONN_HANDLE);
285
286                 error = ncp_conn_lock(conn, td, cred, NCPM_READ);
287                 if (error) break;
288                 copyout(&len, &uap->ncpbuf->rpsize, len);
289                 error = ncp_conn_gethandle(conn, td, &newhp);
290                 if (!error)
291                         error = copyout(&newhp->nh_id, uap->ncpbuf->packet, len);
292                 ncp_conn_unlock(conn,td);
293                 break;
294             }
295             case NCP_CONN_CONNCLOSE: {
296                 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE);
297                 if (error) break;
298                 ncp_conn_puthandle(hp, td, 0);
299                 error = ncp_disconnect(conn);
300                 if (error)
301                         ncp_conn_unlock(conn, td);
302                 break;
303             }
304             default:
305                     error = EOPNOTSUPP;
306         }
307         return error;
308 }
309
310 struct sncp_conn_scan_args {
311         struct ncp_conn_args *li;
312         int *connHandle;
313 };
314
315 static int 
316 sncp_conn_scan(struct thread *td, struct sncp_conn_scan_args *uap)
317 {
318         int connHandle = 0, error;
319         struct ncp_conn_args li, *lip;
320         struct ncp_conn *conn;
321         struct ncp_handle *hp;
322         char *user = NULL, *password = NULL;
323         struct ucred *cred;
324
325         KKASSERT(td->td_proc);
326         cred = td->td_proc->p_ucred;
327
328         if (uap->li) {
329                 if (copyin(uap->li,&li,sizeof(li))) return EFAULT;
330                 lip = &li;
331         } else {
332                 lip = NULL;
333         }
334
335         if (lip != NULL) {
336                 lip->server[sizeof(lip->server)-1]=0; /* just to make sure */
337                 ncp_str_upper(lip->server);
338                 if (lip->user) {
339                         user = ncp_str_dup(lip->user);
340                         if (user == NULL) return EINVAL;
341                         ncp_str_upper(user);
342                 }
343                 if (lip->password) {
344                         password = ncp_str_dup(lip->password);
345                         if (password == NULL) {
346                                 if (user)
347                                         free(user, M_NCPDATA);
348                                 return EINVAL;
349                         }
350                         ncp_str_upper(password);
351                 }
352                 lip->user = user;
353                 lip->password = password;
354         }
355         error = ncp_conn_getbyli(lip,td,cred,NCPM_EXECUTE,&conn);
356         if (!error) {           /* already have this login */
357                 ncp_conn_gethandle(conn, td, &hp);
358                 connHandle = hp->nh_id;
359                 ncp_conn_unlock(conn,td);
360                 copyout(&connHandle,uap->connHandle,sizeof(connHandle));
361         }
362         if (user) free(user, M_NCPDATA);
363         if (password) free(password, M_NCPDATA);
364         td->td_proc->p_retval[0] = error;
365         return error;
366
367 }
368
369 int
370 ncp_conn_frag_rq(struct ncp_conn *conn, struct thread *td, struct ncp_conn_frag *nfp){
371         int error = 0, i, rpsize;
372         u_int32_t fsize;
373         NW_FRAGMENT *fp;
374         struct ucred *cred;
375         DECLARE_RQ;
376
377         KKASSERT(td->td_proc);
378         cred = td->td_proc->p_ucred;
379
380         ncp_rq_head(rqp,NCP_REQUEST,nfp->fn,td,cred);
381         if (nfp->rqfcnt) {
382                 for(fp = nfp->rqf, i = 0; i < nfp->rqfcnt; i++, fp++) {
383                         checkbad(ncp_rq_usermem(rqp,(caddr_t)fp->fragAddress, fp->fragSize));
384                 }
385         }
386         checkbad(ncp_request(conn, rqp));
387         rpsize = rqp->rpsize;
388         if (rpsize && nfp->rpfcnt) {
389                 for(fp = nfp->rpf, i = 0; i < nfp->rpfcnt; i++, fp++) {
390                         checkbad(copyin(&fp->fragSize, &fsize, sizeof (fsize)));
391                         fsize = min(fsize, rpsize);
392                         checkbad(ncp_rp_usermem(rqp,(caddr_t)fp->fragAddress, fsize));
393                         rpsize -= fsize;
394                         checkbad(copyout(&fsize, &fp->fragSize, sizeof (fsize)));
395                 }
396         }
397         nfp->cs = rqp->cs;
398         nfp->cc = rqp->cc;
399         NCP_RQ_EXIT;
400         return error;
401 }
402
403 /*
404  * Internal functions, here should be all calls that do not require connection.
405  * To simplify possible future movement to cdev, we use IOCTL macros.
406  * Pretty much of this stolen from ioctl() function.
407  */
408 struct sncp_intfn_args {
409         u_long  com;
410         caddr_t data;
411 };
412
413 static int
414 sncp_intfn(struct thread *td, struct sncp_intfn_args *uap)
415 {
416         return ENOSYS;
417 }
418 /*
419  * define our new system calls
420  */
421 static struct sysent newent[] = {
422         {2,     (sy_call_t*)sncp_conn_scan},
423         {2,     (sy_call_t*)sncp_connect},
424         {2,     (sy_call_t*)sncp_intfn},
425         {3,     (sy_call_t*)sncp_request}
426 };
427
428 #define SC_SIZE sizeof(newent)/sizeof(struct sysent)
429 /*
430  * Miscellaneous modules must have their own save areas...
431  */
432 static struct sysent    oldent[SC_SIZE];        /* save are for old callslot entry*/
433
434 /*
435  * Number of syscall entries for a.out executables
436  */
437 /*#define nsysent SYS_MAXSYSCALL*/
438 #define nsysent (aout_sysvec.sv_size)
439
440
441 static int
442 ncp_load(void) {
443         int i, ff, scnt, err=0;
444
445         while(1) {
446                 /* Search the table looking for an enough number of slots... */
447                 for (scnt=0, ff = -1, i = 0; i < nsysent; i++) {
448                         if (sysent[i].sy_call == (sy_call_t *)lkmnosys) {
449                                 if (ff == -1) {
450                                     ff = i;
451                                     scnt = 1;
452                                 } else {
453                                     scnt++;
454                                     if (scnt == SC_SIZE) break;
455                                 }
456                         } else {
457                                 ff = -1;
458                         }
459                 }
460                 /* out of allocable slots?*/
461                 if(i == nsysent || ff == -1) {
462                         err = ENFILE;
463                         break;
464                 }
465                 err = ncp_init();
466                 if (err) break;
467                 bcopy(&sysent[ff], &oldent, sizeof(struct sysent)*SC_SIZE);
468                 bcopy(&newent, &sysent[ff], sizeof(struct sysent)*SC_SIZE);
469                 ncp_sysent = ff;        /* slot in sysent[]*/
470                 printf("ncp_load: [%d-%d]\n",ff,i);
471                 break;
472         }
473
474         return( err);
475 }
476
477 static int
478 ncp_unload(void) {
479         ncp_done();
480         bcopy(&oldent, &sysent[ncp_sysent], sizeof(struct sysent) * SC_SIZE);
481         printf( "ncp_unload: unloaded\n");
482         return 0;
483 }
484
485 static int
486 ncp_mod_handler(module_t mod, int type, void *data)
487 {
488         int error;
489
490         switch (type) {
491             case MOD_LOAD:
492                 error = ncp_load();
493                 break;
494             case MOD_UNLOAD:
495                 error = ncp_unload();
496                 break;
497             default:
498                 error = EINVAL;
499         }
500         return error;
501 }
502                                                                \
503 static moduledata_t ncp_mod = {
504         "ncp",
505         ncp_mod_handler,
506         NULL
507 };
508 DECLARE_MODULE(ncp, ncp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);