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$");
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);
Cache object: 74b72f74dd41e8cac339eb78cfb00c7b
|