ncpl_subr.c revision 93399
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 93399 2002-03-29 22:43:43Z markm $");
35
36#include <sys/param.h>
37#include <sys/types.h>
38#include <sys/errno.h>
39#include <sys/sysctl.h>
40#include <sys/syscall.h>
41#include <unistd.h>
42#include <ctype.h>
43#include <string.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <stdarg.h>
47
48#include <netncp/ncp_lib.h>
49#include <netncp/ncp_rcfile.h>
50#include <netncp/ncp_nls.h>
51/*#include <netncp/ncp_cfg.h>*/
52#include "ncp_mod.h"
53
54int sysentoffset;
55
56void
57ncp_add_word_lh(struct ncp_buf *conn, u_int16_t x) {
58	setwle(conn->packet, conn->rqsize, x);
59	conn->rqsize += 2;
60	return;
61}
62
63void
64ncp_add_dword_lh(struct ncp_buf *conn, u_int32_t x) {
65	setdle(conn->packet, conn->rqsize, x);
66	conn->rqsize += 4;
67	return;
68}
69
70void
71ncp_add_word_hl(struct ncp_buf *conn, u_int16_t x){
72	setwbe(conn->packet, conn->rqsize, x);
73	conn->rqsize += 2;
74	return;
75}
76
77void
78ncp_add_dword_hl(struct ncp_buf *conn, u_int32_t x) {
79	setdbe(conn->packet, conn->rqsize, x);
80	conn->rqsize += 4;
81	return;
82}
83
84void
85ncp_add_mem(struct ncp_buf *conn, const void *source, int size) {
86	memcpy(conn->packet+conn->rqsize, source, size);
87	conn->rqsize += size;
88	return;
89}
90
91void
92ncp_add_mem_nls(struct ncp_buf *conn, const void *source, int size) {
93	ncp_nls_mem_u2n(conn->packet+conn->rqsize, source, size);
94	conn->rqsize += size;
95	return;
96}
97
98void
99ncp_add_pstring(struct ncp_buf *conn, const char *s) {
100	int len = strlen(s);
101	if (len > 255) {
102		ncp_printf("ncp_add_pstring: string too long: %s\n", s);
103		len = 255;
104	}
105	ncp_add_byte(conn, len);
106	ncp_add_mem(conn, s, len);
107	return;
108}
109
110void
111ncp_add_handle_path(struct ncp_buf *conn, nuint32 volNumber, nuint32 dirNumber,
112	int handleFlag, const char *path)
113{
114	ncp_add_byte(conn, volNumber);
115	ncp_add_dword_lh(conn, dirNumber);
116	ncp_add_byte(conn, handleFlag);
117	if (path) {
118		ncp_add_byte(conn, 1);		/* 1 component */
119		ncp_add_pstring(conn, path);
120	} else {
121		ncp_add_byte(conn, 0);
122	}
123}
124
125void
126ncp_init_request(struct ncp_buf *conn) {
127	conn->rqsize = 0;
128	conn->rpsize = 0;
129}
130
131void
132ncp_init_request_s(struct ncp_buf *conn, int subfn) {
133	ncp_init_request(conn);
134	ncp_add_word_lh(conn, 0);
135	ncp_add_byte(conn, subfn);
136}
137
138u_int16_t
139ncp_reply_word_hl(struct ncp_buf *conn, int offset) {
140	return getwbe(ncp_reply_data(conn, offset), 0);
141}
142
143u_int16_t
144ncp_reply_word_lh(struct ncp_buf *conn, int offset) {
145	return getwle(ncp_reply_data(conn, offset), 0);
146}
147
148u_int32_t
149ncp_reply_dword_hl(struct ncp_buf *conn, int offset) {
150	return getdbe(ncp_reply_data(conn, offset), 0);
151}
152
153u_int32_t
154ncp_reply_dword_lh(struct ncp_buf *conn, int offset) {
155	return getdle(ncp_reply_data(conn, offset), 0);
156}
157
158
159int
160ncp_connect(struct ncp_conn_args *li, int *connHandle) {
161	return syscall(NCP_CONNECT,li,connHandle);
162}
163
164int
165ncp_disconnect(int cH) {
166	DECLARE_RQ;
167
168	ncp_init_request(conn);
169	ncp_add_byte(conn, NCP_CONN_CONNCLOSE);
170	return ncp_conn_request(cH, conn);
171}
172
173int
174ncp_request(int connHandle,int function, struct ncp_buf *ncpbuf){
175	int err = syscall(SNCP_REQUEST,connHandle,function,ncpbuf);
176	return (err<0) ? errno : 0;
177}
178
179int
180ncp_conn_request(int connHandle, struct ncp_buf *ncpbuf){
181	return syscall(SNCP_REQUEST, connHandle, NCP_CONN, ncpbuf);
182}
183
184int
185ncp_conn_scan(struct ncp_conn_loginfo *li, int *connid) {
186	return syscall(NCP_CONNSCAN,li, connid);
187}
188
189NWCCODE
190NWRequest(NWCONN_HANDLE cH, nuint16 fn,
191	nuint16 nrq, NW_FRAGMENT* rq,
192	nuint16 nrp, NW_FRAGMENT* rp)
193{
194	int error;
195	struct ncp_conn_frag nf;
196	DECLARE_RQ;
197
198	ncp_init_request(conn);
199	ncp_add_byte(conn, NCP_CONN_FRAG);
200	nf.fn = fn;
201	nf.rqfcnt = nrq;
202	nf.rqf = rq;
203	nf.rpf = rp;
204	nf.rpfcnt = nrp;
205	ncp_add_mem(conn, &nf, sizeof(nf));
206	error = ncp_conn_request(cH, conn);
207	return error;
208}
209
210
211int
212ncp_initlib(void){
213	int error;
214	int len = sizeof(sysentoffset);
215	int kv, kvlen = sizeof(kv);
216	static int ncp_initialized;
217
218	if (ncp_initialized)
219		return 0;
220#if __FreeBSD_version < 400001
221	error = sysctlbyname("net.ipx.ncp.sysent", &sysentoffset, &len, NULL, 0);
222#else
223	error = sysctlbyname("net.ncp.sysent", &sysentoffset, &len, NULL, 0);
224#endif
225	if (error) {
226		fprintf(stderr, "%s: can't find kernel module\n", __FUNCTION__);
227		return error;
228	}
229#if __FreeBSD_version < 400001
230	error = sysctlbyname("net.ipx.ncp.version", &kv, &kvlen, NULL, 0);
231#else
232	error = sysctlbyname("net.ncp.version", &kv, &kvlen, NULL, 0);
233#endif
234	if (error) {
235		fprintf(stderr, "%s: kernel module is old, please recompile it.\n", __FUNCTION__);
236		return error;
237	}
238	if (NCP_VERSION != kv) {
239		fprintf(stderr, "%s: kernel module version(%d) don't match library(%d).\n", __FUNCTION__, kv, NCP_VERSION);
240		return EINVAL;
241	}
242	if ((error = ncp_nls_setrecode(0)) != 0) {
243		fprintf(stderr, "%s: can't initialise recode\n", __FUNCTION__);
244		return error;
245	}
246	if ((error = ncp_nls_setlocale("")) != 0) {
247		fprintf(stderr, "%s: can't initialise locale\n", __FUNCTION__);
248		return error;
249	}
250	ncp_initialized++;
251	return 0;
252}
253
254
255/*
256 */
257int	ncp_opterr = 1,		/* if error message should be printed */
258	ncp_optind = 1,		/* index into parent argv vector */
259	ncp_optopt,			/* character checked for validity */
260	ncp_optreset;		/* reset getopt */
261char	*ncp_optarg;		/* argument associated with option */
262
263#define	BADCH	(int)'?'
264#define	BADARG	(int)':'
265#define	EMSG	""
266
267int
268ncp_getopt(nargc, nargv, ostr)
269	int nargc;
270	char * const *nargv;
271	const char *ostr;
272{
273	static char *place = EMSG;		/* option letter processing */
274	char *oli;				/* option letter list index */
275	int tmpind;
276
277	if (ncp_optreset || !*place) {		/* update scanning pointer */
278		ncp_optreset = 0;
279		tmpind = ncp_optind;
280		while (1) {
281			if (tmpind >= nargc) {
282				place = EMSG;
283				return (-1);
284			}
285			if (*(place = nargv[tmpind]) != '-') {
286				tmpind++;
287				continue;	/* lookup next option */
288			}
289			if (place[1] && *++place == '-') {	/* found "--" */
290				ncp_optind = ++tmpind;
291				place = EMSG;
292				return (-1);
293			}
294			ncp_optind = tmpind;
295			break;
296		}
297	}					/* option letter okay? */
298	if ((ncp_optopt = (int)*place++) == (int)':' ||
299	    !(oli = strchr(ostr, ncp_optopt))) {
300		/*
301		 * if the user didn't specify '-' as an option,
302		 * assume it means -1.
303		 */
304		if (ncp_optopt == (int)'-')
305			return (-1);
306		if (!*place)
307			++ncp_optind;
308		if (ncp_opterr && *ostr != ':')
309			(void)fprintf(stderr,
310			    "%s: illegal option -- %c\n", _getprogname(), ncp_optopt);
311		return (BADCH);
312	}
313	if (*++oli != ':') {			/* don't need argument */
314		ncp_optarg = NULL;
315		if (!*place)
316			++ncp_optind;
317	}
318	else {					/* need an argument */
319		if (*place)			/* no white space */
320			ncp_optarg = place;
321		else if (nargc <= ++ncp_optind) {	/* no arg */
322			place = EMSG;
323			if (*ostr == ':')
324				return (BADARG);
325			if (ncp_opterr)
326				(void)fprintf(stderr,
327				    "%s: option requires an argument -- %c\n",
328				    _getprogname(), ncp_optopt);
329			return (BADCH);
330		}
331	 	else				/* white space */
332			ncp_optarg = nargv[ncp_optind];
333		place = EMSG;
334		++ncp_optind;
335	}
336	return (ncp_optopt);			/* dump back option letter */
337}
338/*
339 * misc options parsing routines
340 */
341int
342ncp_args_parserc(struct ncp_args *na, char *sect, ncp_setopt_t *set_callback) {
343	int len, error;
344
345	for (; na->opt; na++) {
346		switch (na->at) {
347		    case NCA_STR:
348			if (rc_getstringptr(ncp_rc,sect,na->name,&na->str) == 0) {
349				len = strlen(na->str);
350				if (len > na->ival) {
351					fprintf(stderr,"rc: Argument for option '%c' (%s) too long\n",na->opt,na->name);
352					return EINVAL;
353				}
354				set_callback(na);
355			}
356			break;
357		    case NCA_BOOL:
358			error = rc_getbool(ncp_rc,sect,na->name,&na->ival);
359			if (error == ENOENT) break;
360			if (error) return EINVAL;
361			set_callback(na);
362			break;
363		    case NCA_INT:
364			if (rc_getint(ncp_rc,sect,na->name,&na->ival) == 0) {
365				if (((na->flag & NAFL_HAVEMIN) &&
366				     (na->ival < na->min)) ||
367				    ((na->flag & NAFL_HAVEMAX) &&
368				     (na->ival > na->max))) {
369					fprintf(stderr,"rc: Argument for option '%c' (%s) should be in [%d-%d] range\n",na->opt,na->name,na->min,na->max);
370					return EINVAL;
371				}
372				set_callback(na);
373			};
374			break;
375		    default:
376			break;
377		}
378	}
379	return 0;
380}
381
382int
383ncp_args_parseopt(struct ncp_args *na, int opt, char *optarg, ncp_setopt_t *set_callback) {
384	int len;
385
386	for (; na->opt; na++) {
387		if (na->opt != opt) continue;
388		switch (na->at) {
389		    case NCA_STR:
390			na->str = optarg;
391			if (optarg) {
392				len = strlen(na->str);
393				if (len > na->ival) {
394					fprintf(stderr,"opt: Argument for option '%c' (%s) too long\n",na->opt,na->name);
395					return EINVAL;
396				}
397				set_callback(na);
398			}
399			break;
400		    case NCA_BOOL:
401			na->ival = 0;
402			set_callback(na);
403			break;
404		    case NCA_INT:
405			errno = 0;
406			na->ival = strtol(optarg, NULL, 0);
407			if (errno) {
408				fprintf(stderr,"opt: Invalid integer value for option '%c' (%s).\n",na->opt,na->name);
409				return EINVAL;
410			}
411			if (((na->flag & NAFL_HAVEMIN) &&
412			     (na->ival < na->min)) ||
413			    ((na->flag & NAFL_HAVEMAX) &&
414			     (na->ival > na->max))) {
415				fprintf(stderr,"opt: Argument for option '%c' (%s) should be in [%d-%d] range\n",na->opt,na->name,na->min,na->max);
416				return EINVAL;
417			}
418			set_callback(na);
419			break;
420		    default:
421			break;
422		}
423		break;
424	}
425	return 0;
426}
427
428/*
429 * Print a (descriptive) error message
430 * error values:
431 *  	   0 - no specific error code available;
432 *  -999..-1 - NDS error
433 *  1..32767 - system error
434 *  the rest - requester error;
435 */
436void
437ncp_error(const char *fmt, int error, ...) {
438	va_list ap;
439
440	fprintf(stderr, "%s: ", _getprogname());
441	va_start(ap, error);
442	vfprintf(stderr, fmt, ap);
443	va_end(ap);
444	if (error == -1)
445		error = errno;
446	if (error > -1000 && error < 0) {
447		fprintf(stderr, ": dserr = %d\n", error);
448	} else if (error & 0x8000) {
449		fprintf(stderr, ": nwerr = %04x\n", error);
450	} else if (error) {
451		fprintf(stderr, ": syserr = %s\n", strerror(error));
452	} else
453		fprintf(stderr, "\n");
454}
455
456char *
457ncp_printb(char *dest, int flags, const struct ncp_bitname *bnp) {
458	int first = 1;
459
460	strcpy(dest, "<");
461	for(; bnp->bn_bit; bnp++) {
462		if (flags & bnp->bn_bit) {
463			strcat(dest, bnp->bn_name);
464			first = 0;
465		}
466		if (!first && (flags & bnp[1].bn_bit))
467			strcat(dest, "|");
468	}
469	strcat(dest, ">");
470	return dest;
471}
472