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