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