xref: /titanic_44/usr/src/cmd/ssh/libssh/common/misc.c (revision 55f5292c612446ce6f93ddd248c0019b5974618b)
1 /*
2  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 /*
25  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 #include "includes.h"
30 RCSID("$OpenBSD: misc.c,v 1.19 2002/03/04 17:27:39 stevesk Exp $");
31 
32 #include "misc.h"
33 #include "log.h"
34 #include "xmalloc.h"
35 
36 /* remove newline at end of string */
37 char *
38 chop(char *s)
39 {
40 	char *t = s;
41 	while (*t) {
42 		if (*t == '\n' || *t == '\r') {
43 			*t = '\0';
44 			return s;
45 		}
46 		t++;
47 	}
48 	return s;
49 
50 }
51 
52 /* set/unset filedescriptor to non-blocking */
53 void
54 set_nonblock(int fd)
55 {
56 	int val;
57 
58 	val = fcntl(fd, F_GETFL, 0);
59 	if (val < 0) {
60 		error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
61 		return;
62 	}
63 	if (val & O_NONBLOCK) {
64 		debug2("fd %d is O_NONBLOCK", fd);
65 		return;
66 	}
67 	debug("fd %d setting O_NONBLOCK", fd);
68 	val |= O_NONBLOCK;
69 	if (fcntl(fd, F_SETFL, val) == -1)
70 		debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
71 		    fd, strerror(errno));
72 }
73 
74 void
75 unset_nonblock(int fd)
76 {
77 	int val;
78 
79 	val = fcntl(fd, F_GETFL, 0);
80 	if (val < 0) {
81 		error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
82 		return;
83 	}
84 	if (!(val & O_NONBLOCK)) {
85 		debug2("fd %d is not O_NONBLOCK", fd);
86 		return;
87 	}
88 	debug("fd %d clearing O_NONBLOCK", fd);
89 	val &= ~O_NONBLOCK;
90 	if (fcntl(fd, F_SETFL, val) == -1)
91 		debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
92 		    fd, strerror(errno));
93 }
94 
95 /* disable nagle on socket */
96 void
97 set_nodelay(int fd)
98 {
99 	int opt;
100 	socklen_t optlen;
101 
102 	optlen = sizeof opt;
103 	if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
104 		error("getsockopt TCP_NODELAY: %.100s", strerror(errno));
105 		return;
106 	}
107 	if (opt == 1) {
108 		debug2("fd %d is TCP_NODELAY", fd);
109 		return;
110 	}
111 	opt = 1;
112 	debug("fd %d setting TCP_NODELAY", fd);
113 	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
114 		error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
115 }
116 
117 /* Characters considered whitespace in strsep calls. */
118 #define WHITESPACE " \t\r\n"
119 
120 /*
121  * Function returns a pointer to the 1st token on the line. Such a token can
122  * be an empty string in the case of '*s' equal to " value". It changes the
123  * first whitespace token or '=' character after the 1st token to '\0'. Upon
124  * return it changes '*s' to point to the first character of the next token.
125  * That token may be an empty string if the 1st token was followed only by
126  * whitespace or it could be a NULL pointer if the line contained one token
127  * only.
128  */
129 char *
130 strdelim(char **s)
131 {
132 	char *old;
133 	int wspace = 0;
134 
135 	if (*s == NULL)
136 		return NULL;
137 
138 	old = *s;
139 
140 	*s = strpbrk(*s, WHITESPACE "=");
141 	if (*s == NULL)
142 		return (old);
143 
144 	/* Allow only one '=' to be skipped */
145 	if (*s[0] == '=')
146 		wspace = 1;
147 	*s[0] = '\0';
148 
149 	*s += strspn(*s + 1, WHITESPACE) + 1;
150 	if (*s[0] == '=' && !wspace)
151 		*s += strspn(*s + 1, WHITESPACE) + 1;
152 
153 	return (old);
154 }
155 
156 struct passwd *
157 pwcopy(struct passwd *pw)
158 {
159 	struct passwd *copy = xmalloc(sizeof(*copy));
160 
161 	memset(copy, 0, sizeof(*copy));
162 	copy->pw_name = xstrdup(pw->pw_name);
163 	copy->pw_passwd = xstrdup(pw->pw_passwd);
164 	copy->pw_gecos = xstrdup(pw->pw_gecos);
165 	copy->pw_uid = pw->pw_uid;
166 	copy->pw_gid = pw->pw_gid;
167 #ifdef HAVE_PW_EXPIRE_IN_PASSWD
168 	copy->pw_expire = pw->pw_expire;
169 #endif
170 #ifdef HAVE_PW_CHANGE_IN_PASSWD
171 	copy->pw_change = pw->pw_change;
172 #endif
173 #ifdef HAVE_PW_CLASS_IN_PASSWD
174 	copy->pw_class = xstrdup(pw->pw_class);
175 #endif
176 	copy->pw_dir = xstrdup(pw->pw_dir);
177 	copy->pw_shell = xstrdup(pw->pw_shell);
178 	return copy;
179 }
180 
181 void
182 pwfree(struct passwd **pw)
183 {
184 	struct passwd *p;
185 
186 	if (pw == NULL || *pw == NULL)
187 		return;
188 
189 	p = *pw;
190 	*pw = NULL;
191 
192 	xfree(p->pw_name);
193 	xfree(p->pw_passwd);
194 	xfree(p->pw_gecos);
195 #ifdef HAVE_PW_CLASS_IN_PASSWD
196 	xfree(p->pw_class);
197 #endif
198 	xfree(p->pw_dir);
199 	xfree(p->pw_shell);
200 	xfree(p);
201 }
202 
203 /*
204  * Convert ASCII string to TCP/IP port number.
205  * Port must be >0 and <=65535.
206  * Return 0 if invalid.
207  */
208 int
209 a2port(const char *s)
210 {
211 	long port;
212 	char *endp;
213 
214 	errno = 0;
215 	port = strtol(s, &endp, 0);
216 	if (s == endp || *endp != '\0' ||
217 	    (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
218 	    port <= 0 || port > 65535)
219 		return 0;
220 
221 	return port;
222 }
223 
224 #define SECONDS		1
225 #define MINUTES		(SECONDS * 60)
226 #define HOURS		(MINUTES * 60)
227 #define DAYS		(HOURS * 24)
228 #define WEEKS		(DAYS * 7)
229 
230 /*
231  * Convert a time string into seconds; format is
232  * a sequence of:
233  *      time[qualifier]
234  *
235  * Valid time qualifiers are:
236  *      <none>  seconds
237  *      s|S     seconds
238  *      m|M     minutes
239  *      h|H     hours
240  *      d|D     days
241  *      w|W     weeks
242  *
243  * Examples:
244  *      90m     90 minutes
245  *      1h30m   90 minutes
246  *      2d      2 days
247  *      1w      1 week
248  *
249  * Return -1 if time string is invalid.
250  */
251 long
252 convtime(const char *s)
253 {
254 	long total, secs;
255 	const char *p;
256 	char *endp;
257 
258 	errno = 0;
259 	total = 0;
260 	p = s;
261 
262 	if (p == NULL || *p == '\0')
263 		return -1;
264 
265 	while (*p) {
266 		secs = strtol(p, &endp, 10);
267 		if (p == endp ||
268 		    (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
269 		    secs < 0)
270 			return -1;
271 
272 		switch (*endp++) {
273 		case '\0':
274 			endp--;
275 			break;
276 		case 's':
277 		case 'S':
278 			break;
279 		case 'm':
280 		case 'M':
281 			secs *= MINUTES;
282 			break;
283 		case 'h':
284 		case 'H':
285 			secs *= HOURS;
286 			break;
287 		case 'd':
288 		case 'D':
289 			secs *= DAYS;
290 			break;
291 		case 'w':
292 		case 'W':
293 			secs *= WEEKS;
294 			break;
295 		default:
296 			return -1;
297 		}
298 		total += secs;
299 		if (total < 0)
300 			return -1;
301 		p = endp;
302 	}
303 
304 	return total;
305 }
306 
307 /*
308  * Search for next delimiter between hostnames/addresses and ports.
309  * Argument may be modified (for termination).
310  * Returns *cp if parsing succeeds.
311  * *cp is set to the start of the next delimiter, if one was found.
312  * If this is the last field, *cp is set to NULL.
313  */
314 char *
315 hpdelim(char **cp)
316 {
317 	char *s, *old;
318 
319 	if (cp == NULL || *cp == NULL)
320 		return NULL;
321 
322 	old = s = *cp;
323 	if (*s == '[') {
324 		if ((s = strchr(s, ']')) == NULL)
325 			return NULL;
326 		else
327 			s++;
328 	} else if ((s = strpbrk(s, ":/")) == NULL)
329 		s = *cp + strlen(*cp); /* skip to end (see first case below) */
330 
331 	switch (*s) {
332 	case '\0':
333 		*cp = NULL;	/* no more fields*/
334 		break;
335 
336 	case ':':
337 	case '/':
338 		*s = '\0';	/* terminate */
339 		*cp = s + 1;
340 		break;
341 
342 	default:
343 		return NULL;
344 	}
345 
346 	return old;
347 }
348 
349 char *
350 cleanhostname(char *host)
351 {
352 	if (*host == '[' && host[strlen(host) - 1] == ']') {
353 		host[strlen(host) - 1] = '\0';
354 		return (host + 1);
355 	} else
356 		return host;
357 }
358 
359 char *
360 colon(char *cp)
361 {
362 	int flag = 0;
363 
364 	if (*cp == ':')		/* Leading colon is part of file name. */
365 		return (0);
366 	if (*cp == '[')
367 		flag = 1;
368 
369 	for (; *cp; ++cp) {
370 		if (*cp == '@' && *(cp+1) == '[')
371 			flag = 1;
372 		if (*cp == ']' && *(cp+1) == ':' && flag)
373 			return (cp+1);
374 		if (*cp == ':' && !flag)
375 			return (cp);
376 		if (*cp == '/')
377 			return (0);
378 	}
379 	return (0);
380 }
381 
382 /* function to assist building execv() arguments */
383 /* PRINTFLIKE2 */
384 void
385 addargs(arglist *args, char *fmt, ...)
386 {
387 	va_list ap;
388 	char buf[1024];
389 
390 	va_start(ap, fmt);
391 	vsnprintf(buf, sizeof(buf), fmt, ap);
392 	va_end(ap);
393 
394 	if (args->list == NULL) {
395 		args->nalloc = 32;
396 		args->num = 0;
397 	} else if (args->num+2 >= args->nalloc)
398 		args->nalloc *= 2;
399 
400 	args->list = xrealloc(args->list, args->nalloc * sizeof(char *));
401 	args->list[args->num++] = xstrdup(buf);
402 	args->list[args->num] = NULL;
403 }
404 
405 void
406 replacearg(arglist *args, u_int which, char *fmt, ...)
407 {
408 	va_list ap;
409 	char *cp;
410 	int r;
411 
412 	va_start(ap, fmt);
413 	r = vasprintf(&cp, fmt, ap);
414 	va_end(ap);
415 	if (r == -1)
416 		fatal("replacearg: argument too long");
417 
418 	if (which >= args->num)
419 		fatal("replacearg: tried to replace invalid arg %d >= %d",
420 		    which, args->num);
421 	xfree(args->list[which]);
422 	args->list[which] = cp;
423 }
424 
425 void
426 freeargs(arglist *args)
427 {
428 	u_int i;
429 
430 	if (args->list != NULL) {
431 		for (i = 0; i < args->num; i++)
432 			xfree(args->list[i]);
433 		xfree(args->list);
434 		args->nalloc = args->num = 0;
435 		args->list = NULL;
436 	}
437 }
438 
439 /*
440  * Expand a string with a set of %[char] escapes. A number of escapes may be
441  * specified as (char *escape_chars, char *replacement) pairs. The list must
442  * be terminated by a NULL escape_char. Returns replaced string in memory
443  * allocated by xmalloc.
444  */
445 char *
446 percent_expand(const char *string, ...)
447 {
448 #define EXPAND_MAX_KEYS	16
449 	struct {
450 		const char *key;
451 		const char *repl;
452 	} keys[EXPAND_MAX_KEYS];
453 	u_int num_keys, i, j;
454 	char buf[4096];
455 	va_list ap;
456 
457 	/* Gather keys */
458 	va_start(ap, string);
459 	for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
460 		keys[num_keys].key = va_arg(ap, char *);
461 		if (keys[num_keys].key == NULL)
462 			break;
463 		keys[num_keys].repl = va_arg(ap, char *);
464 		if (keys[num_keys].repl == NULL)
465 			fatal("percent_expand: NULL replacement");
466 	}
467 	va_end(ap);
468 
469 	if (num_keys >= EXPAND_MAX_KEYS)
470 		fatal("percent_expand: too many keys");
471 
472 	/* Expand string */
473 	*buf = '\0';
474 	for (i = 0; *string != '\0'; string++) {
475 		if (*string != '%') {
476  append:
477 			buf[i++] = *string;
478 			if (i >= sizeof(buf))
479 				fatal("percent_expand: string too long");
480 			buf[i] = '\0';
481 			continue;
482 		}
483 		string++;
484 		if (*string == '%')
485 			goto append;
486 		for (j = 0; j < num_keys; j++) {
487 			if (strchr(keys[j].key, *string) != NULL) {
488 				i = strlcat(buf, keys[j].repl, sizeof(buf));
489 				if (i >= sizeof(buf))
490 					fatal("percent_expand: string too long");
491 				break;
492 			}
493 		}
494 		if (j >= num_keys)
495 			fatal("percent_expand: unknown key %%%c", *string);
496 	}
497 	return (xstrdup(buf));
498 #undef EXPAND_MAX_KEYS
499 }
500 
501 /*
502  * Ensure that file descriptors 0, 1 and 2 are open or directed to /dev/null,
503  * do not touch those that are already open.
504  */
505 void
506 sanitise_stdfd(void)
507 {
508 	int nullfd, dupfd;
509 
510 	if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
511 		fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno));
512 		exit(1);
513 	}
514 	while (++dupfd <= 2) {
515 		/* Only clobber closed fds */
516 		if (fcntl(dupfd, F_GETFL, 0) >= 0)
517 			continue;
518 		if (dup2(nullfd, dupfd) == -1) {
519 			fprintf(stderr, "dup2: %s", strerror(errno));
520 			exit(1);
521 		}
522 	}
523 	if (nullfd > 2)
524 		close(nullfd);
525 }
526 
527 char *
528 tohex(const void *vp, size_t l)
529 {
530 	const u_char *p = (const u_char *)vp;
531 	char b[3], *r;
532 	size_t i, hl;
533 
534 	if (l > 65536)
535 		return xstrdup("tohex: length > 65536");
536 
537 	hl = l * 2 + 1;
538 	r = xcalloc(1, hl);
539 	for (i = 0; i < l; i++) {
540 		snprintf(b, sizeof(b), "%02x", p[i]);
541 		strlcat(r, b, hl);
542 	}
543 	return (r);
544 }
545 
546 u_int64_t
547 get_u64(const void *vp)
548 {
549 	const u_char *p = (const u_char *)vp;
550 	u_int64_t v;
551 
552 	v  = (u_int64_t)p[0] << 56;
553 	v |= (u_int64_t)p[1] << 48;
554 	v |= (u_int64_t)p[2] << 40;
555 	v |= (u_int64_t)p[3] << 32;
556 	v |= (u_int64_t)p[4] << 24;
557 	v |= (u_int64_t)p[5] << 16;
558 	v |= (u_int64_t)p[6] << 8;
559 	v |= (u_int64_t)p[7];
560 
561 	return (v);
562 }
563 
564 u_int32_t
565 get_u32(const void *vp)
566 {
567 	const u_char *p = (const u_char *)vp;
568 	u_int32_t v;
569 
570 	v  = (u_int32_t)p[0] << 24;
571 	v |= (u_int32_t)p[1] << 16;
572 	v |= (u_int32_t)p[2] << 8;
573 	v |= (u_int32_t)p[3];
574 
575 	return (v);
576 }
577 
578 u_int16_t
579 get_u16(const void *vp)
580 {
581 	const u_char *p = (const u_char *)vp;
582 	u_int16_t v;
583 
584 	v  = (u_int16_t)p[0] << 8;
585 	v |= (u_int16_t)p[1];
586 
587 	return (v);
588 }
589 
590 void
591 put_u64(void *vp, u_int64_t v)
592 {
593 	u_char *p = (u_char *)vp;
594 
595 	p[0] = (u_char)(v >> 56) & 0xff;
596 	p[1] = (u_char)(v >> 48) & 0xff;
597 	p[2] = (u_char)(v >> 40) & 0xff;
598 	p[3] = (u_char)(v >> 32) & 0xff;
599 	p[4] = (u_char)(v >> 24) & 0xff;
600 	p[5] = (u_char)(v >> 16) & 0xff;
601 	p[6] = (u_char)(v >> 8) & 0xff;
602 	p[7] = (u_char)v & 0xff;
603 }
604 
605 void
606 put_u32(void *vp, u_int32_t v)
607 {
608 	u_char *p = (u_char *)vp;
609 
610 	p[0] = (u_char)(v >> 24) & 0xff;
611 	p[1] = (u_char)(v >> 16) & 0xff;
612 	p[2] = (u_char)(v >> 8) & 0xff;
613 	p[3] = (u_char)v & 0xff;
614 }
615 
616 
617 void
618 put_u16(void *vp, u_int16_t v)
619 {
620 	u_char *p = (u_char *)vp;
621 
622 	p[0] = (u_char)(v >> 8) & 0xff;
623 	p[1] = (u_char)v & 0xff;
624 }
625 
626 mysig_t
627 mysignal(int sig, mysig_t act)
628 {
629 #ifdef HAVE_SIGACTION
630 	struct sigaction sa, osa;
631 
632 	if (sigaction(sig, NULL, &osa) == -1)
633 		return (mysig_t) -1;
634 	if (osa.sa_handler != act) {
635 		memset(&sa, 0, sizeof(sa));
636 		sigemptyset(&sa.sa_mask);
637 		sa.sa_flags = 0;
638 #if defined(SA_INTERRUPT)
639 		if (sig == SIGALRM)
640 			sa.sa_flags |= SA_INTERRUPT;
641 #endif
642 		sa.sa_handler = act;
643 		if (sigaction(sig, &sa, NULL) == -1)
644 			return (mysig_t) -1;
645 	}
646 	return (osa.sa_handler);
647 #else
648 	return (signal(sig, act));
649 #endif
650 }
651 
652 /*
653  * Return true if argument is one of "yes", "true", "no" or "false". If
654  * 'active' is 0 than we are in a non-matching Host section of the
655  * configuration file so we check the syntax but will not set the value of
656  * '*option'. Otherwise we set its value if not already set.
657  */
658 int
659 get_yes_no_flag(int *option, const char *arg, const char *filename, int linenum,
660     int active)
661 {
662 	int value = -1;
663 
664 	if (arg == NULL || *arg == '\0')
665 		fatal("%.200s line %d: Missing argument.", filename, linenum);
666 	if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
667 		value = 1;
668 	else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
669 		value = 0;
670 
671 	if (active && *option == -1 && value != -1)
672 		*option = value;
673 
674 	return (value != -1);
675 }
676 
677 /*
678  * Convert a string to lowercase. The string returned is an internally allocated
679  * one so the consumer of this function is not expected to change it or free it.
680  */
681 char *
682 tolowercase(const char *s)
683 {
684 	int i, len;
685 	static int lenret = 0;
686 	static char *ret = NULL;
687 
688 	/* allocate a new string if the old one it not long enough to store s */
689 	len = strlen(s) + 1;
690 	if (len > lenret) {
691 		if (ret != NULL)
692 			xfree(ret);
693 		ret = xmalloc(len);
694 		lenret = len;
695 	}
696 
697 	/* process the string including the ending '\0' */
698 	for (i = 0; i < len; ++i)
699 		ret[i] = tolower(s[i]);
700 
701 	return (ret);
702 }
703