xref: /illumos-gate/usr/src/cmd/listen/nstoa.c (revision 113f4232)
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