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