FreeBSD/Linux Kernel Cross Reference
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: releng/6.4/sys/netncp/ncp_mod.c 139823 2005-01-07 01:45:51Z imp $");
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);
Cache object: 5923dee6643d1fa03894be13e2d4fd1f
|