ncpl_subr.c revision 165920
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: head/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
55void
56ncp_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
62void
63ncp_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
69void
70ncp_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
76void
77ncp_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
83void
84ncp_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
90void
91ncp_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
97void
98ncp_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
109void
110ncp_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
124void
125ncp_init_request(struct ncp_buf *conn) {
126	conn->rqsize = 0;
127	conn->rpsize = 0;
128}
129
130void
131ncp_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
137u_int16_t
138ncp_reply_word_hl(struct ncp_buf *conn, int offset) {
139	return getwbe(ncp_reply_data(conn, offset), 0);
140}
141
142u_int16_t
143ncp_reply_word_lh(struct ncp_buf *conn, int offset) {
144	return getwle(ncp_reply_data(conn, offset), 0);
145}
146
147u_int32_t
148ncp_reply_dword_hl(struct ncp_buf *conn, int offset) {
149	return getdbe(ncp_reply_data(conn, offset), 0);
150}
151
152u_int32_t
153ncp_reply_dword_lh(struct ncp_buf *conn, int offset) {
154	return getdle(ncp_reply_data(conn, offset), 0);
155}
156
157
158int
159ncp_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
173int
174ncp_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
182int
183ncp_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
198int
199ncp_conn_request(int connHandle, struct ncp_buf *ncpbuf){
200	return (ncp_request(connHandle, NCP_CONN, ncpbuf));
201}
202
203int
204ncp_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
218NWCCODE
219NWRequest(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
240int
241ncp_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 */
276int	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 */
280char	*ncp_optarg;		/* argument associated with option */
281
282#define	BADCH	(int)'?'
283#define	BADARG	(int)':'
284#define	EMSG	""
285
286int
287ncp_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 */
360int
361ncp_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
401int
402ncp_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 */
455void
456ncp_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
475char *
476ncp_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