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