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