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: stable/9/sys/netncp/ncp_mod.c 164033 2006-11-06 13:42:10Z rwatson $");
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
ncp_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)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
sncp_connect(struct thread * td,struct ncpioc_connect * args)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
sncp_request(struct thread * td,struct ncpioc_request * args)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
ncp_mod_login(struct ncp_conn * conn,char * user,int objtype,char * password,struct thread * td,struct ucred * cred)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
ncp_conn_handler(struct thread * td,struct ncpioc_request * args,struct ncp_conn * conn,struct ncp_handle * hp)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
sncp_conn_scan(struct thread * td,struct ncpioc_connscan * args)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
ncp_conn_frag_rq(struct ncp_conn * conn,struct thread * td,struct ncp_conn_frag * nfp)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
ncp_load(void)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
ncp_unload(void)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
ncp_mod_handler(module_t mod,int type,void * data)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);
530