]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libncp/ncpl_subr.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / libncp / ncpl_subr.c
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$");
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
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
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
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
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
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
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
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
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
125 ncp_init_request(struct ncp_buf *conn) {
126         conn->rqsize = 0;
127         conn->rpsize = 0;
128 }
129
130 void
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
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
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
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
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
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
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
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
199 ncp_conn_request(int connHandle, struct ncp_buf *ncpbuf){
200         return (ncp_request(connHandle, NCP_CONN, ncpbuf));
201 }
202
203 int
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
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
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
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
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
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
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 *
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 }