]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netncp/ncp_mod.c
This commit was generated by cvs2svn to compensate for changes in r157191,
[FreeBSD/FreeBSD.git] / sys / netncp / ncp_mod.c
1 /*-
2  * Copyright (c) 2003 Tim J. Robbins.
3  * Copyright (c) 1999, 2000, 2001 Boris Popov
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *    This product includes software developed by Boris Popov.
17  * 4. Neither the name of the author nor the names of any co-contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/conf.h>
40 #include <sys/proc.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/sysctl.h>
44 #include <sys/malloc.h>
45 #include <sys/uio.h>
46 #include <sys/ioccom.h>
47
48 #include <netncp/ncp.h>
49 #include <netncp/ncp_conn.h>
50 #include <netncp/ncp_subr.h>
51 #include <netncp/ncp_ncp.h>
52 #include <netncp/ncp_user.h>
53 #include <netncp/ncp_rq.h>
54 #include <netncp/ncp_nls.h>
55 #include <netncp/ncpio.h>
56
57 int ncp_version = NCP_VERSION;
58
59 SYSCTL_NODE(_net, OID_AUTO, ncp, CTLFLAG_RW, NULL, "NetWare requester");
60 SYSCTL_INT(_net_ncp, OID_AUTO, version, CTLFLAG_RD, &ncp_version, 0, "");
61
62 MODULE_VERSION(ncp, 1);
63 MODULE_DEPEND(ncp, libmchain, 1, 1, 1);
64
65 static struct cdev *ncp_dev;
66
67 static d_ioctl_t        ncp_ioctl;
68
69 static struct cdevsw ncp_cdevsw = {
70         .d_version =    D_VERSION,
71         .d_flags =      D_NEEDGIANT,
72         .d_ioctl =      ncp_ioctl,
73         .d_name =       "ncp",
74 };
75
76 static int ncp_conn_frag_rq(struct ncp_conn *, struct thread *,
77     struct ncp_conn_frag *);
78 static int ncp_conn_handler(struct thread *, struct ncpioc_request *,
79     struct ncp_conn *, struct ncp_handle *);
80 static int sncp_conn_scan(struct thread *, struct ncpioc_connscan *);
81 static int sncp_connect(struct thread *, struct ncpioc_connect *);
82 static int sncp_request(struct thread *, struct ncpioc_request *);
83
84 static int
85 ncp_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
86 {
87
88         switch (cmd) {
89         case NCPIOC_CONNECT:
90                 return (sncp_connect(td, (struct ncpioc_connect *)data));
91         case NCPIOC_CONNSCAN:
92                 return (sncp_conn_scan(td, (struct ncpioc_connscan *)data));
93         case NCPIOC_REQUEST:
94                 return (sncp_request(td, (struct ncpioc_request *)data));
95         }
96         return (EINVAL);
97 }
98
99 /*
100  * Attach to NCP server
101  */
102
103 static int
104 sncp_connect(struct thread *td, struct ncpioc_connect *args)
105 {
106         int connHandle = 0, error;
107         struct ncp_conn *conn;
108         struct ncp_handle *handle;
109         struct ncp_conn_args li;
110
111         checkbad(copyin(args->ioc_li,&li,sizeof(li)));
112         /* XXX Should be useracc() */
113         checkbad(copyout(&connHandle,args->ioc_connhandle,
114             sizeof(connHandle)));
115         li.password = li.user = NULL;
116         error = ncp_conn_getattached(&li, td, td->td_ucred, NCPM_WRITE | NCPM_EXECUTE, &conn);
117         if (error) {
118                 error = ncp_conn_alloc(&li, td, td->td_ucred, &conn);
119                 if (error)
120                         goto bad;
121                 error = ncp_conn_reconnect(conn);
122                 if (error)
123                         ncp_conn_free(conn);
124         }
125         if (!error) {
126                 error = ncp_conn_gethandle(conn, td, &handle);
127                 copyout(&handle->nh_id, args->ioc_connhandle,
128                     sizeof(args->ioc_connhandle));
129                 ncp_conn_unlock(conn,td);
130         }
131 bad:
132         return error;
133 }
134
135 static int
136 sncp_request(struct thread *td, struct ncpioc_request *args)
137 {
138         struct ncp_rq *rqp;
139         struct ncp_conn *conn;
140         struct ncp_handle *handle;
141         int error = 0, rqsize;
142
143         error = ncp_conn_findhandle(args->ioc_connhandle, td, &handle);
144         if (error)
145                 return error;
146         conn = handle->nh_conn;
147         if (args->ioc_fn == NCP_CONN)
148                 return ncp_conn_handler(td, args, conn, handle);
149         error = copyin(&args->ioc_ncpbuf->rqsize, &rqsize, sizeof(int));
150         if (error)
151                 return(error);
152         error = ncp_rq_alloc(args->ioc_fn, conn, td, td->td_ucred, &rqp);
153         if (error)
154                 return error;
155         if (rqsize) {
156                 error = mb_put_mem(&rqp->rq, (caddr_t)args->ioc_ncpbuf->packet,
157                     rqsize, MB_MUSER);
158                 if (error)
159                         goto bad;
160         }
161         rqp->nr_flags |= NCPR_DONTFREEONERR;
162         error = ncp_request(rqp);
163         if (error == 0 && rqp->nr_rpsize)
164                 error = md_get_mem(&rqp->rp, (caddr_t)args->ioc_ncpbuf->packet, 
165                                 rqp->nr_rpsize, MB_MUSER);
166         copyout(&rqp->nr_cs, &args->ioc_ncpbuf->cs, sizeof(rqp->nr_cs));
167         copyout(&rqp->nr_cc, &args->ioc_ncpbuf->cc, sizeof(rqp->nr_cc));
168         copyout(&rqp->nr_rpsize, &args->ioc_ncpbuf->rpsize, sizeof(rqp->nr_rpsize));
169 bad:
170         ncp_rq_done(rqp);
171         return error;
172 }
173
174 static int
175 ncp_mod_login(struct ncp_conn *conn, char *user, int objtype, char *password,
176         struct thread *td, struct ucred *cred)
177 {
178         int error;
179
180         if (ncp_suser(cred) != 0 && cred->cr_uid != conn->nc_owner->cr_uid)
181                 return EACCES;
182         conn->li.user = ncp_str_dup(user);
183         if (conn->li.user == NULL)
184                 return ENOMEM;
185         conn->li.password = ncp_str_dup(password);
186         if (conn->li.password == NULL) {
187                 error = ENOMEM;
188                 goto bad;
189         }
190         ncp_str_upper(conn->li.user);
191         if ((conn->li.opt & NCP_OPT_NOUPCASEPASS) == 0)
192                 ncp_str_upper(conn->li.password);
193         conn->li.objtype = objtype;
194         error = ncp_conn_login(conn, td, cred);
195         return error;
196 bad:
197         if (conn->li.user) {
198                 free(conn->li.user, M_NCPDATA);
199                 conn->li.user = NULL;
200         }
201         if (conn->li.password) {
202                 free(conn->li.password, M_NCPDATA);
203                 conn->li.password = NULL;
204         }
205         return error;
206 }
207
208 static int
209 ncp_conn_handler(struct thread *td, struct ncpioc_request *args,
210         struct ncp_conn *conn, struct ncp_handle *hp)
211 {
212         int error = 0, rqsize, subfn;
213         struct ucred *cred;
214
215         char *pdata;
216
217         cred = td->td_ucred;
218         error = copyin(&args->ioc_ncpbuf->rqsize, &rqsize, sizeof(int));
219         if (error)
220                 return(error);
221         error = 0;
222         pdata = args->ioc_ncpbuf->packet;
223         subfn = *(pdata++) & 0xff;
224         rqsize--;
225         switch (subfn) {
226             case NCP_CONN_READ: case NCP_CONN_WRITE: {
227                 struct ncp_rw rwrq;
228                 struct uio auio;
229                 struct iovec iov;
230
231                 if (rqsize != sizeof(rwrq))
232                         return (EBADRPC);
233                 error = copyin(pdata,&rwrq,rqsize);
234                 if (error)
235                         return (error);
236                 iov.iov_base = rwrq.nrw_base;
237                 iov.iov_len = rwrq.nrw_cnt;
238                 auio.uio_iov = &iov;
239                 auio.uio_iovcnt = 1;
240                 auio.uio_offset = rwrq.nrw_offset;
241                 auio.uio_resid = rwrq.nrw_cnt;
242                 auio.uio_segflg = UIO_USERSPACE;
243                 auio.uio_rw = (subfn == NCP_CONN_READ) ? UIO_READ : UIO_WRITE;
244                 auio.uio_td = td;
245                 if (subfn == NCP_CONN_READ)
246                         error = ncp_read(conn, &rwrq.nrw_fh, &auio, cred);
247                 else
248                         error = ncp_write(conn, &rwrq.nrw_fh, &auio, cred);
249                 rwrq.nrw_cnt -= auio.uio_resid;
250                 /*td->td_retval[0] = rwrq.nrw_cnt;*/
251                 break;
252             } /* case int_read/write */
253             case NCP_CONN_SETFLAGS: {
254                 u_int16_t mask, flags;
255
256                 error = copyin(pdata,&mask, sizeof(mask));
257                 if (error)
258                         return error;
259                 pdata += sizeof(mask);
260                 error = copyin(pdata,&flags,sizeof(flags));
261                 if (error)
262                         return error;
263                 error = ncp_conn_lock(conn, td, cred, NCPM_WRITE);
264                 if (error)
265                         return error;
266                 if (mask & NCPFL_PERMANENT) {
267                         conn->flags &= ~NCPFL_PERMANENT;
268                         conn->flags |= (flags & NCPFL_PERMANENT);
269                 }
270                 if (mask & NCPFL_PRIMARY) {
271                         error = ncp_conn_setprimary(conn, flags & NCPFL_PRIMARY);
272                         if (error) {
273                                 ncp_conn_unlock(conn, td);
274                                 break;
275                         }
276                 }
277                 ncp_conn_unlock(conn, td);
278                 break;
279             }
280             case NCP_CONN_LOGIN: {
281                 struct ncp_conn_login la;
282
283                 if (rqsize != sizeof(la))
284                         return EBADRPC;
285                 if (conn->flags & NCPFL_LOGGED)
286                         return EALREADY;
287                 if ((error = copyin(pdata,&la,rqsize)) != 0)
288                         break;
289                 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE | NCPM_WRITE);
290                 if (error)
291                         return error;
292                 error = ncp_mod_login(conn, la.username, la.objtype,
293                     la.password, td, td->td_ucred);
294                 ncp_conn_unlock(conn, td);
295                 break;
296             }
297             case NCP_CONN_GETINFO: {
298                 struct ncp_conn_stat ncs;
299                 int len = sizeof(ncs);
300
301                 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ);
302                 if (error)
303                         return error;
304                 ncp_conn_getinfo(conn, &ncs);
305                 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int));
306                 error = copyout(&ncs, &args->ioc_ncpbuf->packet, len);
307                 ncp_conn_unlock(conn, td);
308                 break;
309             }
310             case NCP_CONN_GETUSER: {
311                 int len;
312
313                 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ);
314                 if (error)
315                         return error;
316                 len = (conn->li.user) ? strlen(conn->li.user) + 1 : 0;
317                 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int));
318                 if (len) {
319                         error = copyout(conn->li.user,
320                             &args->ioc_ncpbuf->packet, len);
321                 }
322                 ncp_conn_unlock(conn, td);
323                 break;
324             }
325             case NCP_CONN_CONN2REF: {
326                 int len = sizeof(int);
327
328                 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ);
329                 if (error)
330                         return error;
331                 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int));
332                 if (len) {
333                         error = copyout(&conn->nc_id,
334                             &args->ioc_ncpbuf->packet, len);
335                 }
336                 ncp_conn_unlock(conn, td);
337                 break;
338             }
339             case NCP_CONN_FRAG: {
340                 struct ncp_conn_frag nf;
341
342                 if (rqsize != sizeof(nf))
343                         return (EBADRPC);
344                 if ((error = copyin(pdata, &nf, rqsize)) != 0) break;
345                 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE);
346                 if (error)
347                         return error;
348                 error = ncp_conn_frag_rq(conn, td, &nf);
349                 ncp_conn_unlock(conn, td);
350                 copyout(&nf, &pdata, sizeof(nf));
351                 td->td_retval[0] = error;
352                 break;
353             }
354             case NCP_CONN_DUP: {
355                 struct ncp_handle *newhp;
356                 int len = sizeof(NWCONN_HANDLE);
357
358                 error = ncp_conn_lock(conn, td, cred, NCPM_READ);
359                 if (error) break;
360                 copyout(&len, &args->ioc_ncpbuf->rpsize, len);
361                 error = ncp_conn_gethandle(conn, td, &newhp);
362                 if (!error)
363                         error = copyout(&newhp->nh_id,
364                             args->ioc_ncpbuf->packet, len);
365                 ncp_conn_unlock(conn, td);
366                 break;
367             }
368             case NCP_CONN_CONNCLOSE: {
369                 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE);
370                 if (error) break;
371                 ncp_conn_puthandle(hp, td, 0);
372                 error = ncp_conn_free(conn);
373                 if (error)
374                         ncp_conn_unlock(conn, td);
375                 break;
376             }
377             default:
378                     error = EOPNOTSUPP;
379         }
380         return error;
381 }
382
383 static int
384 sncp_conn_scan(struct thread *td, struct ncpioc_connscan *args)
385 {
386         int connHandle = 0, error;
387         struct ncp_conn_args li, *lip;
388         struct ncp_conn *conn;
389         struct ncp_handle *hp;
390         char *user = NULL, *password = NULL;
391
392         if (args->ioc_li) {
393                 if (copyin(args->ioc_li, &li, sizeof(li)))
394                         return EFAULT;
395                 lip = &li;
396         } else {
397                 lip = NULL;
398         }
399
400         if (lip != NULL) {
401                 lip->server[sizeof(lip->server)-1]=0; /* just to make sure */
402                 ncp_str_upper(lip->server);
403                 if (lip->user) {
404                         user = ncp_str_dup(lip->user);
405                         if (user == NULL)
406                                 return EINVAL;
407                         ncp_str_upper(user);
408                 }
409                 if (lip->password) {
410                         password = ncp_str_dup(lip->password);
411                         if (password == NULL) {
412                                 if (user)
413                                         free(user, M_NCPDATA);
414                                 return EINVAL;
415                         }
416                         ncp_str_upper(password);
417                 }
418                 lip->user = user;
419                 lip->password = password;
420         }
421         error = ncp_conn_getbyli(lip, td, td->td_ucred, NCPM_EXECUTE, &conn);
422         if (!error) {           /* already have this login */
423                 ncp_conn_gethandle(conn, td, &hp);
424                 connHandle = hp->nh_id;
425                 ncp_conn_unlock(conn, td);
426                 copyout(&connHandle, args->ioc_connhandle, sizeof(connHandle));
427         }
428         if (user)
429                 free(user, M_NCPDATA);
430         if (password)
431                 free(password, M_NCPDATA);
432         return error;
433
434 }
435
436 int
437 ncp_conn_frag_rq(struct ncp_conn *conn, struct thread *td,
438                  struct ncp_conn_frag *nfp)
439 {
440         NW_FRAGMENT *fp;
441         struct ncp_rq *rqp;
442         u_int32_t fsize;
443         int error, i, rpsize;
444
445         error = ncp_rq_alloc(nfp->fn, conn, td, td->td_ucred, &rqp);
446         if (error)
447                 return error;
448         for(fp = nfp->rqf, i = 0; i < nfp->rqfcnt; i++, fp++) {
449                 error = mb_put_mem(&rqp->rq, (caddr_t)fp->fragAddress, fp->fragSize, MB_MUSER);
450                 if (error)
451                         goto bad;
452         }
453         rqp->nr_flags |= NCPR_DONTFREEONERR;
454         error = ncp_request(rqp);
455         if (error)
456                 goto bad;
457         rpsize = rqp->nr_rpsize;
458         if (rpsize && nfp->rpfcnt) {
459                 for(fp = nfp->rpf, i = 0; i < nfp->rpfcnt; i++, fp++) {
460                         error = copyin(&fp->fragSize, &fsize, sizeof (fsize));
461                         if (error)
462                                 break;
463                         fsize = min(fsize, rpsize);
464                         error = md_get_mem(&rqp->rp, (caddr_t)fp->fragAddress, fsize, MB_MUSER);
465                         if (error)
466                                 break;
467                         rpsize -= fsize;
468                         error = copyout(&fsize, &fp->fragSize, sizeof (fsize));
469                         if (error)
470                                 break;
471                 }
472         }
473         nfp->cs = rqp->nr_cs;
474         nfp->cc = rqp->nr_cc;
475 bad:
476         ncp_rq_done(rqp);
477         return error;
478 }
479
480 static int
481 ncp_load(void)
482 {
483         int error;
484
485         if ((error = ncp_init()) != 0)
486                 return (error);
487         ncp_dev = make_dev(&ncp_cdevsw, 0, 0, 0, 0666, "ncp");
488         printf("ncp_load: loaded\n");
489         return (0);
490 }
491
492 static int
493 ncp_unload(void)
494 {
495         int error;
496
497         error = ncp_done();
498         if (error)
499                 return (error);
500         destroy_dev(ncp_dev);
501         printf("ncp_unload: unloaded\n");
502         return (0);
503 }
504
505 static int
506 ncp_mod_handler(module_t mod, int type, void *data)
507 {
508         int error;
509
510         switch (type) {
511         case MOD_LOAD:
512                 error = ncp_load();
513                 break;
514         case MOD_UNLOAD:
515                 error = ncp_unload();
516                 break;
517         default:
518                 error = EINVAL;
519         }
520         return error;
521 }
522
523 static moduledata_t ncp_mod = {
524         "ncp",
525         ncp_mod_handler,
526         NULL
527 };
528 DECLARE_MODULE(ncp, ncp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);