1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 /* 35 stoa - convert string to address 36 37 If a string begins in \o or \O, the following address is octal 38 " " " " " \x or \X, the following address is hex 39 Otherwise, a string is considered text. Text may be quoted 40 with double quotes and the C-like escapes \n, \b, \t, \v, \r, and \nnn 41 (nnn = octal char) are recognized. 42 A \ followed by a newline causes the newline 43 to vanish. A \ followed by any other char causes any "magic" of 44 any other char to disappear. 45 46 Other escape sequences recognized are: 47 \!cmd args [ \! || EOL ] 48 which is replaced by the raw output of the execution of cmd. 49 This may only be used in a string. 50 51 \$cmd args [ \$ || EOL ] 52 which is replaced by the output of the execution of cmd and 53 is then reprocessed. 54 55 A NULL is returned on any error(s). 56 */ 57 58 #include <stdio.h> 59 #include <memory.h> 60 #include <ctype.h> 61 #include "nsaddr.h" 62 63 64 #define toupper(c) (islower(c) ? _toupper(c) : (c)) 65 #define todigit(c) ((int)((c) - '0')) /* char to digit */ 66 #define toxdigit(c) ((isdigit(c))?todigit(c):(toupper(c)-(int)'A'+10)) 67 #define isodigit(c) (isdigit(c) && ((c) != '9') && ((c) != '8')) 68 #define itoac(i) (((i) > 9) ? ((char)((i)-10) + 'A'):((char)(i) + '0')) 69 #define MASK(n) ((1 << (n)) - 1) 70 71 #define MAXRLEVEL 10 /* maximum recursion level */ 72 73 #define TRUE 1; 74 #define FALSE 0; 75 76 char scanbuf[SBUFSIZE]; 77 int sbp = 0; 78 int rec = 0; /* Recursion level */ 79 80 char sbuf[SBUFSIZE]; 81 82 extern void free(); 83 84 struct netbuf * 85 stoa(str, addr) /* Return 0 for success, -1 for error */ 86 char *str; 87 struct netbuf *addr; 88 { 89 char *xfer(), *prescan(); 90 91 int myadr; /* was netbuf struct allocated here ? */ 92 int quote; /* quoted string ? */ 93 94 myadr = FALSE; 95 96 if (!str) 97 return NULL; 98 while (*str && isspace(*str)) /* leading whites are OK */ 99 ++str; 100 101 str = prescan(str); /* Do all \$ ... \$ */ 102 103 if (!str || !*str) return NULL; /* Nothing to convert */ 104 105 if (!addr) { 106 if ((addr = (struct netbuf *)malloc(sizeof(struct netbuf))) == NULL) 107 return NULL; 108 myadr = TRUE; 109 addr->buf = NULL; 110 addr->maxlen = 0; 111 addr->len = 0; 112 } 113 114 /* Now process the address */ 115 quote = 0; 116 117 if (*str == '\\') { 118 ++str; 119 switch (*str) { 120 121 case 'X': /* hex */ 122 case 'x': 123 addr->len = dobase(++str, sbuf, HEX); 124 break; 125 126 case 'o': /* octal */ 127 case 'O': 128 addr->len = dobase(++str, sbuf, OCT); 129 break; 130 131 case '\0': /* No address given!, length is 0 */ 132 addr->len = dostring(str, sbuf, 0); 133 break; 134 135 default: /* \ is handled by dostring */ 136 addr->len = dostring(--str, sbuf, quote); 137 break; 138 } 139 } 140 else { 141 if (*str == '"') { /* quoted string */ 142 quote = 1; 143 ++str; 144 } 145 addr->len = dostring(str, sbuf, quote); 146 } 147 148 if (addr->len == 0) { /* Error in conversion */ 149 if (myadr) 150 free(addr); 151 return NULL; 152 } 153 if ((addr->buf = xfer(addr->buf, sbuf, addr->len, addr->maxlen)) == NULL) 154 return NULL; 155 else 156 return addr; 157 } 158 159 160 /* 161 dostring: Copy string at s to buf translating 162 escaped characters and shell escapes. 163 return length of string. 164 */ 165 166 int 167 dostring(s, buf, quote) /* read in a raw address */ 168 char *s, *buf; 169 int quote; 170 { 171 char *xcmd(); 172 173 int oc, ch, len = 0; 174 int l = 0; 175 char *rout; 176 177 while (*s) { 178 if (len >= SBUFSIZE) { 179 fprintf(stderr, "dostring: string too long\n"); 180 break; 181 } 182 else if (*s == '\\') 183 switch(*++s) { 184 185 case '!': /* raw shell escape */ 186 if (rout = xcmd(s+1, '!', &s, &l)) { 187 if (len + l < SBUFSIZE) 188 memcpy(buf+len, rout, l); 189 len += l; 190 free(rout); 191 } 192 break; 193 194 case '\n': /* ignore newline */ 195 ++s; 196 break; 197 198 case 'b': /* backspace */ 199 buf[len++] = '\b'; s++; 200 break; 201 202 case 'n': /* newline */ 203 buf[len++] = '\n'; s++; 204 break; 205 206 case 'r': /* return */ 207 buf[len++] = '\r'; s++; 208 break; 209 210 case 't': /* horiz. tab */ 211 buf[len++] = '\t'; s++; 212 break; 213 214 case 'v': /* vert. tab */ 215 buf[len++] = '\v'; s++; 216 217 case '0': 218 case '1': 219 case '2': 220 case '3': 221 for(oc=ch=0; (*s >= '0' && *s <= '7') && oc++ < 3; ++s) 222 ch = (ch << 3) | (*s - '0'); 223 buf[len++] = ch; 224 break; 225 226 case 0: /* end of string -- terminate */ 227 break; 228 229 default: /* take the character blindly */ 230 buf[len++] = *s++; 231 break; 232 } 233 else if ((quote && (*s == '"')) || (!quote && isspace(*s))) 234 break; 235 236 else 237 buf[len++] = *s++; 238 } 239 return (len >= SBUFSIZE) ? 0 : len; 240 } 241 242 243 /* 244 dobase : converts a hex or octal ASCII string 245 to a binary address. Only HEX or OCT may be used 246 for type. 247 return length of binary string (in bytes), 0 if error. 248 The binary result is placed at buf. 249 */ 250 251 int 252 dobase(s, buf, type) /* read in an address */ 253 char *s, *buf; /* source ASCII, result binary string */ 254 int type; 255 { 256 void memcp(); 257 int bp = SBUFSIZE - 1; 258 int shift = 0; 259 char *end; 260 261 for (end = s; *end && ((type == OCT) ? isodigit(*end) : 262 isxdigit(*end)); ++end) ; 263 264 /* any non-white, non-digits cause address to be rejected, 265 other fields are ignored */ 266 267 if ((*s == 0) || (end == s) || (!isspace(*end) && *end)) { 268 fprintf(stderr, "dobase: Illegal trailer on address string\n"); 269 buf[0] = '\0'; 270 return 0; 271 } 272 --end; 273 274 buf[bp] = '\0'; 275 276 while (bp > 0 && end >= s) { 277 buf[bp] |= toxdigit(*end) << shift; 278 if (type == OCT) { 279 if (shift > 5) { 280 buf[--bp] = (todigit(*end) >> (8 - shift)) 281 & MASK(shift-5); 282 } 283 if ((shift = (shift + 3) % 8) == 0) 284 buf[--bp] = 0; 285 } 286 else /* hex */ 287 if ((shift = (shift) ? 0 : 4) == 0) 288 buf[--bp] = 0;; 289 --end; 290 } 291 if (bp == 0) { 292 fprintf(stderr, "stoa: dobase: number to long\n"); 293 return 0; 294 } 295 296 /* need to catch end case to avoid extra 0's in front */ 297 if (!shift) 298 bp++; 299 memcp(buf, &buf[bp], (SBUFSIZE - bp)); 300 return (SBUFSIZE - bp); 301 } 302 303 #ifdef NOTUSED 304 305 306 /* 307 308 atos(str, addr, type) 309 310 convert address to ASCII form with address in hex, octal, 311 or character form. 312 return pointer to buffer (NULL on failure). 313 */ 314 315 316 char * 317 atos(str, addr, type) 318 char *str; 319 struct netbuf *addr; 320 int type; 321 { 322 char *xfer(); 323 int mystr = 0; /* was str allocated here ? */ 324 unsigned x_atos(), o_atos(); 325 void memcp(); 326 327 char *base; 328 329 if (addr == NULL) 330 return NULL; 331 332 if (str == NULL) 333 if ((str = malloc(SBUFSIZE)) == NULL) 334 return NULL; 335 else 336 mystr = 1; 337 338 switch (type) { 339 340 case OCT: 341 /* first add \o */ 342 sbuf[0] = '\\'; 343 sbuf[1] = 'o'; 344 345 return xfer(str, sbuf, o_atos(sbuf+2, addr->buf, addr->len) + 2, 346 mystr ? SBUFSIZE : 0); 347 348 case HEX: 349 /* first add \x */ 350 sbuf[0] = '\\'; 351 sbuf[1] = 'x'; 352 353 return xfer(str, sbuf, x_atos(sbuf+2, addr->buf, addr->len) + 2, 354 mystr ? SBUFSIZE : 0); 355 356 case RAW: 357 base = xfer(str, addr->buf, 358 addr->len + 1, mystr ? SBUFSIZE : 0); 359 if (base) 360 base[addr->len] = '\0'; /* terminate*/ 361 return base; 362 363 default: 364 return NULL; 365 } 366 } 367 368 369 /* 370 x_atos, o_atos 371 return the number of bytes occupied by string + NULL*/ 372 373 /* 374 x_atos : convert an address string a, length s 375 to hex ASCII in s */ 376 377 378 unsigned 379 x_atos(s, a, l) 380 char *s, *a; 381 unsigned l; 382 { 383 char *b; 384 385 b = s; 386 while (l--) { 387 *s++ = itoac(((*a >> 4) & MASK (4))); 388 *s++ = itoac((*a & MASK(4))); 389 ++a; 390 } 391 *s = '\0'; 392 return (s - b + 1); 393 } 394 395 396 /* 397 o_atos : convert an address a, length l 398 to octal ASCII in s */ 399 400 401 unsigned 402 o_atos(s, a, l) 403 char *s, *a; 404 unsigned l; 405 { 406 int i, shift; 407 char *b; 408 409 b = s; 410 if (l == 0) { 411 *s = '\0'; 412 return 0; 413 } 414 415 /* take care of partial bits and set shift factor for next 3 */ 416 417 i = l % 3; 418 *s++ = itoac((*a>>(i+5)) & MASK(3-i)); 419 shift = 2 + i; 420 421 while (l) 422 if (shift <= 5) { 423 *s++ = itoac((*a >> shift) & MASK(3)); 424 if (shift == 0) { 425 ++a; 426 --l; 427 } 428 shift += (shift < 3) ? 5 : -3; 429 } 430 else { 431 i = (*a & MASK(shift-5)) << (8-shift); 432 i |= (*++a >> shift) & MASK(8-shift); 433 *s++ = itoac(i); 434 shift -= 3; 435 --l; 436 } 437 *s++ = '\0'; 438 return (s - b + 1); 439 } 440 441 #endif /* NOTUSED */ 442 443 void 444 memcp(d, s, n) /* safe memcpy for overlapping regions */ 445 char *d, *s; 446 int n; 447 { 448 while (n--) 449 *d++ = *s++; 450 } 451 452 453 /* transfer block to a given destination or allocate one of the 454 right size 455 if max = 0 : ignore max 456 */ 457 458 char * 459 xfer(dest, src, len, max) 460 char *dest, *src; 461 unsigned len, max; 462 { 463 if (max && dest && max < len) { /* No room */ 464 fprintf(stderr, "xfer: destination not long enough\n"); 465 return NULL; 466 } 467 if (!dest) 468 if ((dest = (char *)malloc(len)) == NULL) { 469 fprintf(stderr, "xfer: malloc failed\n"); 470 return NULL; 471 } 472 473 memcpy(dest, src, (int)len); 474 return dest; 475 } 476 477 /* 478 prescan: scan through string s, expanding all \$...\$ 479 as shell escapes. 480 Return pointer to string of expanded text. 481 */ 482 483 char * 484 prescan(s) 485 char *s; 486 { 487 int scan(); 488 489 rec = sbp = 0; 490 if (!s || !*s || !scan(s)) 491 return NULL; 492 scanbuf[sbp] = '\0'; 493 return scanbuf; 494 } 495 496 497 /* 498 scan: scan through string s, expanding all \$...\$. 499 (Part II of prescan) 500 Return 0 if anything failed, else 1. 501 */ 502 503 int 504 scan(s) 505 char *s; 506 { 507 char *xcmd(); 508 char *cmd; 509 int len; 510 int esc = 0; /* Keep lookout for \\$ */ 511 512 while (*s) { 513 if (!esc && (*s == '\\' && *(s+1) == '$')) { 514 if (rec++ == MAXRLEVEL) { 515 fprintf(stderr, "scan: Recursion \ 516 level past %d on shell escape\n", rec); 517 return 0; 518 } 519 if ((cmd = xcmd(s+2, '$', &s, &len)) != NULL) { 520 cmd[len] = '\0'; 521 if (*cmd != '\0') 522 scan(cmd); 523 free(cmd); 524 } 525 else 526 return 0; 527 } 528 529 else if (sbp == SBUFSIZE) { 530 fprintf(stderr, "Overflow on shell esc expansion\n"); 531 return 0; 532 } 533 else if (sbp < SBUFSIZE) 534 esc = ((scanbuf[sbp++] = *s++) == '\\'); 535 } 536 return 1; 537 } 538 539 540 /* 541 xcmd : extract command line for shell escape and execute it 542 return pointer to output of command 543 */ 544 545 char * 546 xcmd(s, ec, ps, len) 547 char *s; /* input string */ 548 char ec; /* escape char ( $ or ! ) */ 549 char **ps; /* address of input string pointer */ 550 int *len; /* Number of bytes of output from command */ 551 { 552 FILE *popen(); 553 int pclose(); 554 555 FILE *pfp; /* pipe for process */ 556 char *cmd; /* command buffer */ 557 char *cmdp; /* pointer along cmd */ 558 char *ocmd; /* output of command buffer */ 559 int esc = 0; /* escaped escape shell */ 560 561 *len = 0; 562 563 if ((cmd = cmdp = (char *)malloc(SBUFSIZE)) == NULL) { 564 fprintf(stderr, "xcmd: malloc failed\n"); 565 return NULL; 566 } 567 568 if ((ocmd = (char *)malloc(SBUFSIZE)) == NULL) { 569 fprintf(stderr, "xcmd: malloc failed\n"); 570 free(cmd); 571 return NULL; 572 } 573 while (*s) { 574 if (!esc && *s == '\\' && *(s+1) == ec) { 575 s += 2; 576 break; 577 } 578 else 579 esc = (*cmdp++ = *s++) == '\\'; 580 } 581 *cmdp = '\0'; 582 *ps = s; 583 584 if ((pfp = popen(cmd, "r")) == NULL) 585 fprintf(stderr, "xcmd: popen failed\n"); 586 while (fread(&ocmd[*len], 1, 1, pfp)) 587 if ((*len += 1) >= SBUFSIZE) { 588 fprintf(stderr, "xcmd: command output too long\n"); 589 break; 590 } 591 pclose(pfp); 592 free(cmd); 593 594 return ocmd; 595 } 596