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 *
stoa(str,addr)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
dostring(s,buf,quote)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
dobase(s,buf,type)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 *
atos(str,addr,type)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
x_atos(s,a,l)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
o_atos(s,a,l)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
memcp(d,s,n)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 *
xfer(dest,src,len,max)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 *
prescan(s)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
scan(s)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 *
xcmd(s,ec,ps,len)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