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