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