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