1 /*
2  * Copyright (c) 1999, Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD: stable/9/lib/libncp/ncpl_subr.c 165920 2007-01-09 23:27:39Z imp $");
32 
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/errno.h>
36 #include <sys/sysctl.h>
37 #include <sys/ioctl.h>
38 #include <unistd.h>
39 #include <ctype.h>
40 #include <fcntl.h>
41 #include <paths.h>
42 #include <string.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 
47 #include <netncp/ncp_lib.h>
48 #include <netncp/ncp_rcfile.h>
49 #include <netncp/ncp_nls.h>
50 /*#include <netncp/ncp_cfg.h>*/
51 #include <netncp/ncpio.h>
52 
53 #define	_PATH_NCP	_PATH_DEV NCP_NAME
54 
55 void
ncp_add_word_lh(struct ncp_buf * conn,u_int16_t x)56 ncp_add_word_lh(struct ncp_buf *conn, u_int16_t x) {
57 	setwle(conn->packet, conn->rqsize, x);
58 	conn->rqsize += 2;
59 	return;
60 }
61 
62 void
ncp_add_dword_lh(struct ncp_buf * conn,u_int32_t x)63 ncp_add_dword_lh(struct ncp_buf *conn, u_int32_t x) {
64 	setdle(conn->packet, conn->rqsize, x);
65 	conn->rqsize += 4;
66 	return;
67 }
68 
69 void
ncp_add_word_hl(struct ncp_buf * conn,u_int16_t x)70 ncp_add_word_hl(struct ncp_buf *conn, u_int16_t x){
71 	setwbe(conn->packet, conn->rqsize, x);
72 	conn->rqsize += 2;
73 	return;
74 }
75 
76 void
ncp_add_dword_hl(struct ncp_buf * conn,u_int32_t x)77 ncp_add_dword_hl(struct ncp_buf *conn, u_int32_t x) {
78 	setdbe(conn->packet, conn->rqsize, x);
79 	conn->rqsize += 4;
80 	return;
81 }
82 
83 void
ncp_add_mem(struct ncp_buf * conn,const void * source,int size)84 ncp_add_mem(struct ncp_buf *conn, const void *source, int size) {
85 	memcpy(conn->packet+conn->rqsize, source, size);
86 	conn->rqsize += size;
87 	return;
88 }
89 
90 void
ncp_add_mem_nls(struct ncp_buf * conn,const void * source,int size)91 ncp_add_mem_nls(struct ncp_buf *conn, const void *source, int size) {
92 	ncp_nls_mem_u2n(conn->packet+conn->rqsize, source, size);
93 	conn->rqsize += size;
94 	return;
95 }
96 
97 void
ncp_add_pstring(struct ncp_buf * conn,const char * s)98 ncp_add_pstring(struct ncp_buf *conn, const char *s) {
99 	int len = strlen(s);
100 	if (len > 255) {
101 		ncp_printf("ncp_add_pstring: string too long: %s\n", s);
102 		len = 255;
103 	}
104 	ncp_add_byte(conn, len);
105 	ncp_add_mem(conn, s, len);
106 	return;
107 }
108 
109 void
ncp_add_handle_path(struct ncp_buf * conn,nuint32 volNumber,nuint32 dirNumber,int handleFlag,const char * path)110 ncp_add_handle_path(struct ncp_buf *conn, nuint32 volNumber, nuint32 dirNumber,
111 	int handleFlag, const char *path)
112 {
113 	ncp_add_byte(conn, volNumber);
114 	ncp_add_dword_lh(conn, dirNumber);
115 	ncp_add_byte(conn, handleFlag);
116 	if (path) {
117 		ncp_add_byte(conn, 1);		/* 1 component */
118 		ncp_add_pstring(conn, path);
119 	} else {
120 		ncp_add_byte(conn, 0);
121 	}
122 }
123 
124 void
ncp_init_request(struct ncp_buf * conn)125 ncp_init_request(struct ncp_buf *conn) {
126 	conn->rqsize = 0;
127 	conn->rpsize = 0;
128 }
129 
130 void
ncp_init_request_s(struct ncp_buf * conn,int subfn)131 ncp_init_request_s(struct ncp_buf *conn, int subfn) {
132 	ncp_init_request(conn);
133 	ncp_add_word_lh(conn, 0);
134 	ncp_add_byte(conn, subfn);
135 }
136 
137 u_int16_t
ncp_reply_word_hl(struct ncp_buf * conn,int offset)138 ncp_reply_word_hl(struct ncp_buf *conn, int offset) {
139 	return getwbe(ncp_reply_data(conn, offset), 0);
140 }
141 
142 u_int16_t
ncp_reply_word_lh(struct ncp_buf * conn,int offset)143 ncp_reply_word_lh(struct ncp_buf *conn, int offset) {
144 	return getwle(ncp_reply_data(conn, offset), 0);
145 }
146 
147 u_int32_t
ncp_reply_dword_hl(struct ncp_buf * conn,int offset)148 ncp_reply_dword_hl(struct ncp_buf *conn, int offset) {
149 	return getdbe(ncp_reply_data(conn, offset), 0);
150 }
151 
152 u_int32_t
ncp_reply_dword_lh(struct ncp_buf * conn,int offset)153 ncp_reply_dword_lh(struct ncp_buf *conn, int offset) {
154 	return getdle(ncp_reply_data(conn, offset), 0);
155 }
156 
157 
158 int
ncp_connect(struct ncp_conn_args * li,int * connHandle)159 ncp_connect(struct ncp_conn_args *li, int *connHandle) {
160 	struct ncpioc_connect args;
161 	int fd, r;
162 	if ((fd = open(_PATH_NCP, O_RDWR)) < 0)
163 		return (errno);
164 	args.ioc_li = li;
165 	args.ioc_connhandle = connHandle;
166 	errno = 0;
167 	(void)ioctl(fd, NCPIOC_CONNECT, &args);
168 	r = errno;
169 	close(fd);
170 	return (r);
171 }
172 
173 int
ncp_disconnect(int cH)174 ncp_disconnect(int cH) {
175 	DECLARE_RQ;
176 
177 	ncp_init_request(conn);
178 	ncp_add_byte(conn, NCP_CONN_CONNCLOSE);
179 	return ncp_conn_request(cH, conn);
180 }
181 
182 int
ncp_request(int connHandle,int function,struct ncp_buf * ncpbuf)183 ncp_request(int connHandle,int function, struct ncp_buf *ncpbuf){
184 	struct ncpioc_request args;
185 	int fd, r;
186 	if ((fd = open(_PATH_NCP, O_RDWR)) < 0)
187 		return (errno);
188 	args.ioc_connhandle = connHandle;
189 	args.ioc_fn = function;
190 	args.ioc_ncpbuf = ncpbuf;
191 	errno = 0;
192 	(void)ioctl(fd, NCPIOC_REQUEST, &args);
193 	r = errno;
194 	close(fd);
195 	return (r);
196 }
197 
198 int
ncp_conn_request(int connHandle,struct ncp_buf * ncpbuf)199 ncp_conn_request(int connHandle, struct ncp_buf *ncpbuf){
200 	return (ncp_request(connHandle, NCP_CONN, ncpbuf));
201 }
202 
203 int
ncp_conn_scan(struct ncp_conn_loginfo * li,int * connid)204 ncp_conn_scan(struct ncp_conn_loginfo *li, int *connid) {
205 	struct ncpioc_connscan args;
206 	int fd, r;
207 	if ((fd = open(_PATH_NCP, O_RDWR)) < 0)
208 		return (errno);
209 	args.ioc_li = li;
210 	args.ioc_connhandle = connid;
211 	errno = 0;
212 	(void)ioctl(fd, NCPIOC_CONNSCAN, &args);
213 	r = errno;
214 	close(fd);
215 	return (r);
216 }
217 
218 NWCCODE
NWRequest(NWCONN_HANDLE cH,nuint16 fn,nuint16 nrq,NW_FRAGMENT * rq,nuint16 nrp,NW_FRAGMENT * rp)219 NWRequest(NWCONN_HANDLE cH, nuint16 fn,
220 	nuint16 nrq, NW_FRAGMENT* rq,
221 	nuint16 nrp, NW_FRAGMENT* rp)
222 {
223 	int error;
224 	struct ncp_conn_frag nf;
225 	DECLARE_RQ;
226 
227 	ncp_init_request(conn);
228 	ncp_add_byte(conn, NCP_CONN_FRAG);
229 	nf.fn = fn;
230 	nf.rqfcnt = nrq;
231 	nf.rqf = rq;
232 	nf.rpf = rp;
233 	nf.rpfcnt = nrp;
234 	ncp_add_mem(conn, &nf, sizeof(nf));
235 	error = ncp_conn_request(cH, conn);
236 	return error;
237 }
238 
239 
240 int
ncp_initlib(void)241 ncp_initlib(void){
242 	int error;
243 	int kv;
244 	size_t kvlen = sizeof(kv);
245 	static int ncp_initialized;
246 
247 	if (ncp_initialized)
248 		return 0;
249 	error = sysctlbyname("net.ncp.version", &kv, &kvlen, NULL, 0);
250 	if (error) {
251 		if (errno == ENOENT)
252 			fprintf(stderr, "Kernel module ncp is not loaded.\n");
253 		else
254 			fprintf(stderr, "%s: kernel module is old, please recompile it.\n", __func__);
255 		return error;
256 	}
257 	if (NCP_VERSION != kv) {
258 		fprintf(stderr, "%s: kernel module version(%d) don't match library(%d).\n", __func__, kv, NCP_VERSION);
259 		return EINVAL;
260 	}
261 	if ((error = ncp_nls_setrecode(0)) != 0) {
262 		fprintf(stderr, "%s: can't initialise recode\n", __func__);
263 		return error;
264 	}
265 	if ((error = ncp_nls_setlocale("")) != 0) {
266 		fprintf(stderr, "%s: can't initialise locale\n", __func__);
267 		return error;
268 	}
269 	ncp_initialized++;
270 	return 0;
271 }
272 
273 
274 /*
275  */
276 int	ncp_opterr = 1,		/* if error message should be printed */
277 	ncp_optind = 1,		/* index into parent argv vector */
278 	ncp_optopt,			/* character checked for validity */
279 	ncp_optreset;		/* reset getopt */
280 char	*ncp_optarg;		/* argument associated with option */
281 
282 #define	BADCH	(int)'?'
283 #define	BADARG	(int)':'
284 #define	EMSG	""
285 
286 int
ncp_getopt(nargc,nargv,ostr)287 ncp_getopt(nargc, nargv, ostr)
288 	int nargc;
289 	char * const *nargv;
290 	const char *ostr;
291 {
292 	static char *place = EMSG;		/* option letter processing */
293 	char *oli;				/* option letter list index */
294 	int tmpind;
295 
296 	if (ncp_optreset || !*place) {		/* update scanning pointer */
297 		ncp_optreset = 0;
298 		tmpind = ncp_optind;
299 		while (1) {
300 			if (tmpind >= nargc) {
301 				place = EMSG;
302 				return (-1);
303 			}
304 			if (*(place = nargv[tmpind]) != '-') {
305 				tmpind++;
306 				continue;	/* lookup next option */
307 			}
308 			if (place[1] && *++place == '-') {	/* found "--" */
309 				ncp_optind = ++tmpind;
310 				place = EMSG;
311 				return (-1);
312 			}
313 			ncp_optind = tmpind;
314 			break;
315 		}
316 	}					/* option letter okay? */
317 	if ((ncp_optopt = (int)*place++) == (int)':' ||
318 	    !(oli = strchr(ostr, ncp_optopt))) {
319 		/*
320 		 * if the user didn't specify '-' as an option,
321 		 * assume it means -1.
322 		 */
323 		if (ncp_optopt == (int)'-')
324 			return (-1);
325 		if (!*place)
326 			++ncp_optind;
327 		if (ncp_opterr && *ostr != ':')
328 			(void)fprintf(stderr,
329 			    "%s: illegal option -- %c\n", _getprogname(), ncp_optopt);
330 		return (BADCH);
331 	}
332 	if (*++oli != ':') {			/* don't need argument */
333 		ncp_optarg = NULL;
334 		if (!*place)
335 			++ncp_optind;
336 	}
337 	else {					/* need an argument */
338 		if (*place)			/* no white space */
339 			ncp_optarg = place;
340 		else if (nargc <= ++ncp_optind) {	/* no arg */
341 			place = EMSG;
342 			if (*ostr == ':')
343 				return (BADARG);
344 			if (ncp_opterr)
345 				(void)fprintf(stderr,
346 				    "%s: option requires an argument -- %c\n",
347 				    _getprogname(), ncp_optopt);
348 			return (BADCH);
349 		}
350 	 	else				/* white space */
351 			ncp_optarg = nargv[ncp_optind];
352 		place = EMSG;
353 		++ncp_optind;
354 	}
355 	return (ncp_optopt);			/* dump back option letter */
356 }
357 /*
358  * misc options parsing routines
359  */
360 int
ncp_args_parserc(struct ncp_args * na,char * sect,ncp_setopt_t * set_callback)361 ncp_args_parserc(struct ncp_args *na, char *sect, ncp_setopt_t *set_callback) {
362 	int len, error;
363 
364 	for (; na->opt; na++) {
365 		switch (na->at) {
366 		    case NCA_STR:
367 			if (rc_getstringptr(ncp_rc,sect,na->name,&na->str) == 0) {
368 				len = strlen(na->str);
369 				if (len > na->ival) {
370 					fprintf(stderr,"rc: Argument for option '%c' (%s) too long\n",na->opt,na->name);
371 					return EINVAL;
372 				}
373 				set_callback(na);
374 			}
375 			break;
376 		    case NCA_BOOL:
377 			error = rc_getbool(ncp_rc,sect,na->name,&na->ival);
378 			if (error == ENOENT) break;
379 			if (error) return EINVAL;
380 			set_callback(na);
381 			break;
382 		    case NCA_INT:
383 			if (rc_getint(ncp_rc,sect,na->name,&na->ival) == 0) {
384 				if (((na->flag & NAFL_HAVEMIN) &&
385 				     (na->ival < na->min)) ||
386 				    ((na->flag & NAFL_HAVEMAX) &&
387 				     (na->ival > na->max))) {
388 					fprintf(stderr,"rc: Argument for option '%c' (%s) should be in [%d-%d] range\n",na->opt,na->name,na->min,na->max);
389 					return EINVAL;
390 				}
391 				set_callback(na);
392 			};
393 			break;
394 		    default:
395 			break;
396 		}
397 	}
398 	return 0;
399 }
400 
401 int
ncp_args_parseopt(struct ncp_args * na,int opt,char * optarg,ncp_setopt_t * set_callback)402 ncp_args_parseopt(struct ncp_args *na, int opt, char *optarg, ncp_setopt_t *set_callback) {
403 	int len;
404 
405 	for (; na->opt; na++) {
406 		if (na->opt != opt) continue;
407 		switch (na->at) {
408 		    case NCA_STR:
409 			na->str = optarg;
410 			if (optarg) {
411 				len = strlen(na->str);
412 				if (len > na->ival) {
413 					fprintf(stderr,"opt: Argument for option '%c' (%s) too long\n",na->opt,na->name);
414 					return EINVAL;
415 				}
416 				set_callback(na);
417 			}
418 			break;
419 		    case NCA_BOOL:
420 			na->ival = 0;
421 			set_callback(na);
422 			break;
423 		    case NCA_INT:
424 			errno = 0;
425 			na->ival = strtol(optarg, NULL, 0);
426 			if (errno) {
427 				fprintf(stderr,"opt: Invalid integer value for option '%c' (%s).\n",na->opt,na->name);
428 				return EINVAL;
429 			}
430 			if (((na->flag & NAFL_HAVEMIN) &&
431 			     (na->ival < na->min)) ||
432 			    ((na->flag & NAFL_HAVEMAX) &&
433 			     (na->ival > na->max))) {
434 				fprintf(stderr,"opt: Argument for option '%c' (%s) should be in [%d-%d] range\n",na->opt,na->name,na->min,na->max);
435 				return EINVAL;
436 			}
437 			set_callback(na);
438 			break;
439 		    default:
440 			break;
441 		}
442 		break;
443 	}
444 	return 0;
445 }
446 
447 /*
448  * Print a (descriptive) error message
449  * error values:
450  *  	   0 - no specific error code available;
451  *  -999..-1 - NDS error
452  *  1..32767 - system error
453  *  the rest - requester error;
454  */
455 void
ncp_error(const char * fmt,int error,...)456 ncp_error(const char *fmt, int error, ...) {
457 	va_list ap;
458 
459 	fprintf(stderr, "%s: ", _getprogname());
460 	va_start(ap, error);
461 	vfprintf(stderr, fmt, ap);
462 	va_end(ap);
463 	if (error == -1)
464 		error = errno;
465 	if (error > -1000 && error < 0) {
466 		fprintf(stderr, ": dserr = %d\n", error);
467 	} else if (error & 0x8000) {
468 		fprintf(stderr, ": nwerr = %04x\n", error);
469 	} else if (error) {
470 		fprintf(stderr, ": syserr = %s\n", strerror(error));
471 	} else
472 		fprintf(stderr, "\n");
473 }
474 
475 char *
ncp_printb(char * dest,int flags,const struct ncp_bitname * bnp)476 ncp_printb(char *dest, int flags, const struct ncp_bitname *bnp) {
477 	int first = 1;
478 
479 	strcpy(dest, "<");
480 	for(; bnp->bn_bit; bnp++) {
481 		if (flags & bnp->bn_bit) {
482 			strcat(dest, bnp->bn_name);
483 			first = 0;
484 		}
485 		if (!first && (flags & bnp[1].bn_bit))
486 			strcat(dest, "|");
487 	}
488 	strcat(dest, ">");
489 	return dest;
490 }
491