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