]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/netncp/ncp_mod.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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/priv.h>
41 #include <sys/proc.h>
42 #include <sys/kernel.h>
43 #include <sys/module.h>
44 #include <sys/sysctl.h>
45 #include <sys/malloc.h>
46 #include <sys/uio.h>
47 #include <sys/ioccom.h>
48
49 #include <netncp/ncp.h>
50 #include <netncp/ncp_conn.h>
51 #include <netncp/ncp_subr.h>
52 #include <netncp/ncp_ncp.h>
53 #include <netncp/ncp_user.h>
54 #include <netncp/ncp_rq.h>
55 #include <netncp/ncp_nls.h>
56 #include <netncp/ncpio.h>
57
58 int ncp_version = NCP_VERSION;
59
60 SYSCTL_NODE(_net, OID_AUTO, ncp, CTLFLAG_RW, NULL, "NetWare requester");
61 SYSCTL_INT(_net_ncp, OID_AUTO, version, CTLFLAG_RD, &ncp_version, 0, "");
62
63 MODULE_VERSION(ncp, 1);
64 MODULE_DEPEND(ncp, libmchain, 1, 1, 1);
65
66 static struct cdev *ncp_dev;
67
68 static d_ioctl_t        ncp_ioctl;
69
70 static struct cdevsw ncp_cdevsw = {
71         .d_version =    D_VERSION,
72         .d_flags =      D_NEEDGIANT,
73         .d_ioctl =      ncp_ioctl,
74         .d_name =       "ncp",
75 };
76
77 static int ncp_conn_frag_rq(struct ncp_conn *, struct thread *,
78     struct ncp_conn_frag *);
79 static int ncp_conn_handler(struct thread *, struct ncpioc_request *,
80     struct ncp_conn *, struct ncp_handle *);
81 static int sncp_conn_scan(struct thread *, struct ncpioc_connscan *);
82 static int sncp_connect(struct thread *, struct ncpioc_connect *);
83 static int sncp_request(struct thread *, struct ncpioc_request *);
84
85 static int
86 ncp_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
87 {
88
89         switch (cmd) {
90         case NCPIOC_CONNECT:
91                 return (sncp_connect(td, (struct ncpioc_connect *)data));
92         case NCPIOC_CONNSCAN:
93                 return (sncp_conn_scan(td, (struct ncpioc_connscan *)data));
94         case NCPIOC_REQUEST:
95                 return (sncp_request(td, (struct ncpioc_request *)data));
96         }
97         return (EINVAL);
98 }
99
100 /*
101  * Attach to NCP server
102  */
103
104 static int
105 sncp_connect(struct thread *td, struct ncpioc_connect *args)
106 {
107         int connHandle = 0, error;
108         struct ncp_conn *conn;
109         struct ncp_handle *handle;
110         struct ncp_conn_args li;
111
112         checkbad(copyin(args->ioc_li,&li,sizeof(li)));
113         /* XXX Should be useracc() */
114         checkbad(copyout(&connHandle,args->ioc_connhandle,
115             sizeof(connHandle)));
116         li.password = li.user = NULL;
117         error = ncp_conn_getattached(&li, td, td->td_ucred, NCPM_WRITE | NCPM_EXECUTE, &conn);
118         if (error) {
119                 error = ncp_conn_alloc(&li, td, td->td_ucred, &conn);
120                 if (error)
121                         goto bad;
122                 error = ncp_conn_reconnect(conn);
123                 if (error)
124                         ncp_conn_free(conn);
125         }
126         if (!error) {
127                 error = ncp_conn_gethandle(conn, td, &handle);
128                 copyout(&handle->nh_id, args->ioc_connhandle,
129                     sizeof(args->ioc_connhandle));
130                 ncp_conn_unlock(conn,td);
131         }
132 bad:
133         return error;
134 }
135
136 static int
137 sncp_request(struct thread *td, struct ncpioc_request *args)
138 {
139         struct ncp_rq *rqp;
140         struct ncp_conn *conn;
141         struct ncp_handle *handle;
142         int error = 0, rqsize;
143
144         error = ncp_conn_findhandle(args->ioc_connhandle, td, &handle);
145         if (error)
146                 return error;
147         conn = handle->nh_conn;
148         if (args->ioc_fn == NCP_CONN)
149                 return ncp_conn_handler(td, args, conn, handle);
150         error = copyin(&args->ioc_ncpbuf->rqsize, &rqsize, sizeof(int));
151         if (error)
152                 return(error);
153         error = ncp_rq_alloc(args->ioc_fn, conn, td, td->td_ucred, &rqp);
154         if (error)
155                 return error;
156         if (rqsize) {
157                 error = mb_put_mem(&rqp->rq, (caddr_t)args->ioc_ncpbuf->packet,
158                     rqsize, MB_MUSER);
159                 if (error)
160                         goto bad;
161         }
162         rqp->nr_flags |= NCPR_DONTFREEONERR;
163         error = ncp_request(rqp);
164         if (error == 0 && rqp->nr_rpsize)
165                 error = md_get_mem(&rqp->rp, (caddr_t)args->ioc_ncpbuf->packet, 
166                                 rqp->nr_rpsize, MB_MUSER);
167         copyout(&rqp->nr_cs, &args->ioc_ncpbuf->cs, sizeof(rqp->nr_cs));
168         copyout(&rqp->nr_cc, &args->ioc_ncpbuf->cc, sizeof(rqp->nr_cc));
169         copyout(&rqp->nr_rpsize, &args->ioc_ncpbuf->rpsize, sizeof(rqp->nr_rpsize));
170 bad:
171         ncp_rq_done(rqp);
172         return error;
173 }
174
175 static int
176 ncp_mod_login(struct ncp_conn *conn, char *user, int objtype, char *password,
177         struct thread *td, struct ucred *cred)
178 {
179         int error;
180
181         if (ncp_suser(cred) != 0 && cred->cr_uid != conn->nc_owner->cr_uid)
182                 return EACCES;
183         conn->li.user = ncp_str_dup(user);
184         if (conn->li.user == NULL)
185                 return ENOMEM;
186         conn->li.password = ncp_str_dup(password);
187         if (conn->li.password == NULL) {
188                 error = ENOMEM;
189                 goto bad;
190         }
191         ncp_str_upper(conn->li.user);
192         if ((conn->li.opt & NCP_OPT_NOUPCASEPASS) == 0)
193                 ncp_str_upper(conn->li.password);
194         conn->li.objtype = objtype;
195         error = ncp_conn_login(conn, td, cred);
196         return error;
197 bad:
198         if (conn->li.user) {
199                 free(conn->li.user, M_NCPDATA);
200                 conn->li.user = NULL;
201         }
202         if (conn->li.password) {
203                 free(conn->li.password, M_NCPDATA);
204                 conn->li.password = NULL;
205         }
206         return error;
207 }
208
209 static int
210 ncp_conn_handler(struct thread *td, struct ncpioc_request *args,
211         struct ncp_conn *conn, struct ncp_handle *hp)
212 {
213         int error = 0, rqsize, subfn;
214         struct ucred *cred;
215
216         char *pdata;
217
218         cred = td->td_ucred;
219         error = copyin(&args->ioc_ncpbuf->rqsize, &rqsize, sizeof(int));
220         if (error)
221                 return(error);
222         error = 0;
223         pdata = args->ioc_ncpbuf->packet;
224         subfn = *(pdata++) & 0xff;
225         rqsize--;
226         switch (subfn) {
227             case NCP_CONN_READ: case NCP_CONN_WRITE: {
228                 struct ncp_rw rwrq;
229                 struct uio auio;
230                 struct iovec iov;
231
232                 if (rqsize != sizeof(rwrq))
233                         return (EBADRPC);
234                 error = copyin(pdata,&rwrq,rqsize);
235                 if (error)
236                         return (error);
237                 iov.iov_base = rwrq.nrw_base;
238                 iov.iov_len = rwrq.nrw_cnt;
239                 auio.uio_iov = &iov;
240                 auio.uio_iovcnt = 1;
241                 auio.uio_offset = rwrq.nrw_offset;
242                 auio.uio_resid = rwrq.nrw_cnt;
243                 auio.uio_segflg = UIO_USERSPACE;
244                 auio.uio_rw = (subfn == NCP_CONN_READ) ? UIO_READ : UIO_WRITE;
245                 auio.uio_td = td;
246                 if (subfn == NCP_CONN_READ)
247                         error = ncp_read(conn, &rwrq.nrw_fh, &auio, cred);
248                 else
249                         error = ncp_write(conn, &rwrq.nrw_fh, &auio, cred);
250                 rwrq.nrw_cnt -= auio.uio_resid;
251                 /*td->td_retval[0] = rwrq.nrw_cnt;*/
252                 break;
253             } /* case int_read/write */
254             case NCP_CONN_SETFLAGS: {
255                 u_int16_t mask, flags;
256
257                 error = copyin(pdata,&mask, sizeof(mask));
258                 if (error)
259                         return error;
260                 pdata += sizeof(mask);
261                 error = copyin(pdata,&flags,sizeof(flags));
262                 if (error)
263                         return error;
264                 error = ncp_conn_lock(conn, td, cred, NCPM_WRITE);
265                 if (error)
266                         return error;
267                 if (mask & NCPFL_PERMANENT) {
268                         conn->flags &= ~NCPFL_PERMANENT;
269                         conn->flags |= (flags & NCPFL_PERMANENT);
270                 }
271                 if (mask & NCPFL_PRIMARY) {
272                         error = ncp_conn_setprimary(conn, flags & NCPFL_PRIMARY);
273                         if (error) {
274                                 ncp_conn_unlock(conn, td);
275                                 break;
276                         }
277                 }
278                 ncp_conn_unlock(conn, td);
279                 break;
280             }
281             case NCP_CONN_LOGIN: {
282                 struct ncp_conn_login la;
283
284                 if (rqsize != sizeof(la))
285                         return EBADRPC;
286                 if (conn->flags & NCPFL_LOGGED)
287                         return EALREADY;
288                 if ((error = copyin(pdata,&la,rqsize)) != 0)
289                         break;
290                 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE | NCPM_WRITE);
291                 if (error)
292                         return error;
293                 error = ncp_mod_login(conn, la.username, la.objtype,
294                     la.password, td, td->td_ucred);
295                 ncp_conn_unlock(conn, td);
296                 break;
297             }
298             case NCP_CONN_GETINFO: {
299                 struct ncp_conn_stat ncs;
300                 int len = sizeof(ncs);
301
302                 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ);
303                 if (error)
304                         return error;
305                 ncp_conn_getinfo(conn, &ncs);
306                 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int));
307                 error = copyout(&ncs, &args->ioc_ncpbuf->packet, len);
308                 ncp_conn_unlock(conn, td);
309                 break;
310             }
311             case NCP_CONN_GETUSER: {
312                 int len;
313
314                 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ);
315                 if (error)
316                         return error;
317                 len = (conn->li.user) ? strlen(conn->li.user) + 1 : 0;
318                 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int));
319                 if (len) {
320                         error = copyout(conn->li.user,
321                             &args->ioc_ncpbuf->packet, len);
322                 }
323                 ncp_conn_unlock(conn, td);
324                 break;
325             }
326             case NCP_CONN_CONN2REF: {
327                 int len = sizeof(int);
328
329                 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ);
330                 if (error)
331                         return error;
332                 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int));
333                 if (len) {
334                         error = copyout(&conn->nc_id,
335                             &args->ioc_ncpbuf->packet, len);
336                 }
337                 ncp_conn_unlock(conn, td);
338                 break;
339             }
340             case NCP_CONN_FRAG: {
341                 struct ncp_conn_frag nf;
342
343                 if (rqsize != sizeof(nf))
344                         return (EBADRPC);
345                 if ((error = copyin(pdata, &nf, rqsize)) != 0) break;
346                 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE);
347                 if (error)
348                         return error;
349                 error = ncp_conn_frag_rq(conn, td, &nf);
350                 ncp_conn_unlock(conn, td);
351                 copyout(&nf, &pdata, sizeof(nf));
352                 td->td_retval[0] = error;
353                 break;
354             }
355             case NCP_CONN_DUP: {
356                 struct ncp_handle *newhp;
357                 int len = sizeof(NWCONN_HANDLE);
358
359                 error = ncp_conn_lock(conn, td, cred, NCPM_READ);
360                 if (error) break;
361                 copyout(&len, &args->ioc_ncpbuf->rpsize, len);
362                 error = ncp_conn_gethandle(conn, td, &newhp);
363                 if (!error)
364                         error = copyout(&newhp->nh_id,
365                             args->ioc_ncpbuf->packet, len);
366                 ncp_conn_unlock(conn, td);
367                 break;
368             }
369             case NCP_CONN_CONNCLOSE: {
370                 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE);
371                 if (error) break;
372                 ncp_conn_puthandle(hp, td, 0);
373                 error = ncp_conn_free(conn);
374                 if (error)
375                         ncp_conn_unlock(conn, td);
376                 break;
377             }
378             default:
379                     error = EOPNOTSUPP;
380         }
381         return error;
382 }
383
384 static int
385 sncp_conn_scan(struct thread *td, struct ncpioc_connscan *args)
386 {
387         int connHandle = 0, error;
388         struct ncp_conn_args li, *lip;
389         struct ncp_conn *conn;
390         struct ncp_handle *hp;
391         char *user = NULL, *password = NULL;
392
393         if (args->ioc_li) {
394                 if (copyin(args->ioc_li, &li, sizeof(li)))
395                         return EFAULT;
396                 lip = &li;
397         } else {
398                 lip = NULL;
399         }
400
401         if (lip != NULL) {
402                 lip->server[sizeof(lip->server)-1]=0; /* just to make sure */
403                 ncp_str_upper(lip->server);
404                 if (lip->user) {
405                         user = ncp_str_dup(lip->user);
406                         if (user == NULL)
407                                 return EINVAL;
408                         ncp_str_upper(user);
409                 }
410                 if (lip->password) {
411                         password = ncp_str_dup(lip->password);
412                         if (password == NULL) {
413                                 if (user)
414                                         free(user, M_NCPDATA);
415                                 return EINVAL;
416                         }
417                         ncp_str_upper(password);
418                 }
419                 lip->user = user;
420                 lip->password = password;
421         }
422         error = ncp_conn_getbyli(lip, td, td->td_ucred, NCPM_EXECUTE, &conn);
423         if (!error) {           /* already have this login */
424                 ncp_conn_gethandle(conn, td, &hp);
425                 connHandle = hp->nh_id;
426                 ncp_conn_unlock(conn, td);
427                 copyout(&connHandle, args->ioc_connhandle, sizeof(connHandle));
428         }
429         if (user)
430                 free(user, M_NCPDATA);
431         if (password)
432                 free(password, M_NCPDATA);
433         return error;
434
435 }
436
437 int
438 ncp_conn_frag_rq(struct ncp_conn *conn, struct thread *td,
439                  struct ncp_conn_frag *nfp)
440 {
441         NW_FRAGMENT *fp;
442         struct ncp_rq *rqp;
443         u_int32_t fsize;
444         int error, i, rpsize;
445
446         error = ncp_rq_alloc(nfp->fn, conn, td, td->td_ucred, &rqp);
447         if (error)
448                 return error;
449         for(fp = nfp->rqf, i = 0; i < nfp->rqfcnt; i++, fp++) {
450                 error = mb_put_mem(&rqp->rq, (caddr_t)fp->fragAddress, fp->fragSize, MB_MUSER);
451                 if (error)
452                         goto bad;
453         }
454         rqp->nr_flags |= NCPR_DONTFREEONERR;
455         error = ncp_request(rqp);
456         if (error)
457                 goto bad;
458         rpsize = rqp->nr_rpsize;
459         if (rpsize && nfp->rpfcnt) {
460                 for(fp = nfp->rpf, i = 0; i < nfp->rpfcnt; i++, fp++) {
461                         error = copyin(&fp->fragSize, &fsize, sizeof (fsize));
462                         if (error)
463                                 break;
464                         fsize = min(fsize, rpsize);
465                         error = md_get_mem(&rqp->rp, (caddr_t)fp->fragAddress, fsize, MB_MUSER);
466                         if (error)
467                                 break;
468                         rpsize -= fsize;
469                         error = copyout(&fsize, &fp->fragSize, sizeof (fsize));
470                         if (error)
471                                 break;
472                 }
473         }
474         nfp->cs = rqp->nr_cs;
475         nfp->cc = rqp->nr_cc;
476 bad:
477         ncp_rq_done(rqp);
478         return error;
479 }
480
481 static int
482 ncp_load(void)
483 {
484         int error;
485
486         if ((error = ncp_init()) != 0)
487                 return (error);
488         ncp_dev = make_dev(&ncp_cdevsw, 0, 0, 0, 0666, "ncp");
489         printf("ncp_load: loaded\n");
490         return (0);
491 }
492
493 static int
494 ncp_unload(void)
495 {
496         int error;
497
498         error = ncp_done();
499         if (error)
500                 return (error);
501         destroy_dev(ncp_dev);
502         printf("ncp_unload: unloaded\n");
503         return (0);
504 }
505
506 static int
507 ncp_mod_handler(module_t mod, int type, void *data)
508 {
509         int error;
510
511         switch (type) {
512         case MOD_LOAD:
513                 error = ncp_load();
514                 break;
515         case MOD_UNLOAD:
516                 error = ncp_unload();
517                 break;
518         default:
519                 error = EINVAL;
520         }
521         return error;
522 }
523
524 static moduledata_t ncp_mod = {
525         "ncp",
526         ncp_mod_handler,
527         NULL
528 };
529 DECLARE_MODULE(ncp, ncp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);