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