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