Annotation of src/crypto/external/bsd/openssh/dist/misc.c, Revision 1.16.2.2
1.16.2.2! pgoyette 1: /* $NetBSD: misc.c,v 1.18 2018/08/26 07:46:36 christos Exp $ */
! 2: /* $OpenBSD: misc.c,v 1.131 2018/07/27 05:13:02 dtucker Exp $ */
! 3:
1.1 christos 4: /*
5: * Copyright (c) 2000 Markus Friedl. All rights reserved.
6: * Copyright (c) 2005,2006 Damien Miller. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27: */
28:
1.2 christos 29: #include "includes.h"
1.16.2.2! pgoyette 30: __RCSID("$NetBSD: misc.c,v 1.18 2018/08/26 07:46:36 christos Exp $");
1.1 christos 31: #include <sys/types.h>
32: #include <sys/ioctl.h>
33: #include <sys/socket.h>
1.16 christos 34: #include <sys/stat.h>
1.12 christos 35: #include <sys/time.h>
1.16 christos 36: #include <sys/wait.h>
1.9 christos 37: #include <sys/un.h>
1.1 christos 38:
39: #include <net/if.h>
1.2 christos 40: #include <net/if_tun.h>
1.1 christos 41: #include <netinet/in.h>
1.5 christos 42: #include <netinet/ip.h>
1.1 christos 43: #include <netinet/tcp.h>
44:
1.9 christos 45: #include <ctype.h>
1.1 christos 46: #include <errno.h>
47: #include <fcntl.h>
48: #include <netdb.h>
49: #include <paths.h>
50: #include <pwd.h>
1.16 christos 51: #include <libgen.h>
1.10 christos 52: #include <limits.h>
1.16 christos 53: #include <signal.h>
1.1 christos 54: #include <stdarg.h>
55: #include <stdio.h>
56: #include <stdlib.h>
57: #include <string.h>
58: #include <unistd.h>
59:
60: #include "xmalloc.h"
61: #include "misc.h"
62: #include "log.h"
63: #include "ssh.h"
1.16 christos 64: #include "sshbuf.h"
65: #include "ssherr.h"
1.1 christos 66:
67: /* remove newline at end of string */
68: char *
69: chop(char *s)
70: {
71: char *t = s;
72: while (*t) {
73: if (*t == '\n' || *t == '\r') {
74: *t = '\0';
75: return s;
76: }
77: t++;
78: }
79: return s;
80:
81: }
82:
83: /* set/unset filedescriptor to non-blocking */
84: int
85: set_nonblock(int fd)
86: {
87: int val;
88:
1.13 christos 89: val = fcntl(fd, F_GETFL);
1.1 christos 90: if (val < 0) {
1.13 christos 91: error("fcntl(%d, F_GETFL): %s", fd, strerror(errno));
1.1 christos 92: return (-1);
93: }
94: if (val & O_NONBLOCK) {
95: debug3("fd %d is O_NONBLOCK", fd);
96: return (0);
97: }
98: debug2("fd %d setting O_NONBLOCK", fd);
99: val |= O_NONBLOCK;
100: if (fcntl(fd, F_SETFL, val) == -1) {
101: debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
102: strerror(errno));
103: return (-1);
104: }
105: return (0);
106: }
107:
108: int
109: unset_nonblock(int fd)
110: {
111: int val;
112:
1.13 christos 113: val = fcntl(fd, F_GETFL);
1.1 christos 114: if (val < 0) {
1.13 christos 115: error("fcntl(%d, F_GETFL): %s", fd, strerror(errno));
1.1 christos 116: return (-1);
117: }
118: if (!(val & O_NONBLOCK)) {
119: debug3("fd %d is not O_NONBLOCK", fd);
120: return (0);
121: }
122: debug("fd %d clearing O_NONBLOCK", fd);
123: val &= ~O_NONBLOCK;
124: if (fcntl(fd, F_SETFL, val) == -1) {
125: debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
126: fd, strerror(errno));
127: return (-1);
128: }
129: return (0);
130: }
131:
132: const char *
133: ssh_gai_strerror(int gaierr)
134: {
1.8 christos 135: if (gaierr == EAI_SYSTEM && errno != 0)
1.1 christos 136: return strerror(errno);
137: return gai_strerror(gaierr);
138: }
139:
140: /* disable nagle on socket */
141: void
142: set_nodelay(int fd)
143: {
144: int opt;
145: socklen_t optlen;
146:
147: optlen = sizeof opt;
148: if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
149: debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
150: return;
151: }
152: if (opt == 1) {
153: debug2("fd %d is TCP_NODELAY", fd);
154: return;
155: }
156: opt = 1;
157: debug2("fd %d setting TCP_NODELAY", fd);
158: if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
159: error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
160: }
161:
1.16.2.1 pgoyette 162: /* Allow local port reuse in TIME_WAIT */
163: int
164: set_reuseaddr(int fd)
165: {
166: int on = 1;
167:
168: if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
169: error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
170: return -1;
171: }
172: return 0;
173: }
174:
175: /* Get/set routing domain */
176: char *
177: get_rdomain(int fd)
178: {
179: #ifdef SO_RTABLE
180: int rtable;
181: char *ret;
182: socklen_t len = sizeof(rtable);
183:
184: if (getsockopt(fd, SOL_SOCKET, SO_RTABLE, &rtable, &len) == -1) {
185: error("Failed to get routing domain for fd %d: %s",
186: fd, strerror(errno));
187: return NULL;
188: }
189: xasprintf(&ret, "%d", rtable);
190: return ret;
191: #else
192: return NULL;
193: #endif
194: }
195:
196: int
197: set_rdomain(int fd, const char *name)
198: {
199: #ifdef SO_RTABLE
200: int rtable;
201: const char *errstr;
202:
203: if (name == NULL)
204: return 0; /* default table */
205:
206: rtable = (int)strtonum(name, 0, 255, &errstr);
207: if (errstr != NULL) {
208: /* Shouldn't happen */
209: error("Invalid routing domain \"%s\": %s", name, errstr);
210: return -1;
211: }
212: if (setsockopt(fd, SOL_SOCKET, SO_RTABLE,
213: &rtable, sizeof(rtable)) == -1) {
214: error("Failed to set routing domain %d on fd %d: %s",
215: rtable, fd, strerror(errno));
216: return -1;
217: }
218: return 0;
219: #else
220: return -1;
221: #endif
222: }
223:
1.1 christos 224: /* Characters considered whitespace in strsep calls. */
225: #define WHITESPACE " \t\r\n"
226: #define QUOTE "\""
227:
228: /* return next token in configuration line */
1.16.2.2! pgoyette 229: static char *
! 230: strdelim_internal(char **s, int split_equals)
1.1 christos 231: {
232: char *old;
233: int wspace = 0;
234:
235: if (*s == NULL)
236: return NULL;
237:
238: old = *s;
239:
1.16.2.2! pgoyette 240: *s = strpbrk(*s,
! 241: split_equals ? WHITESPACE QUOTE "=" : WHITESPACE QUOTE);
1.1 christos 242: if (*s == NULL)
243: return (old);
244:
245: if (*s[0] == '\"') {
246: memmove(*s, *s + 1, strlen(*s)); /* move nul too */
247: /* Find matching quote */
248: if ((*s = strpbrk(*s, QUOTE)) == NULL) {
249: return (NULL); /* no matching quote */
250: } else {
251: *s[0] = '\0';
1.4 adam 252: *s += strspn(*s + 1, WHITESPACE) + 1;
1.1 christos 253: return (old);
254: }
255: }
256:
257: /* Allow only one '=' to be skipped */
1.16.2.2! pgoyette 258: if (split_equals && *s[0] == '=')
1.1 christos 259: wspace = 1;
260: *s[0] = '\0';
261:
262: /* Skip any extra whitespace after first token */
263: *s += strspn(*s + 1, WHITESPACE) + 1;
1.16.2.2! pgoyette 264: if (split_equals && *s[0] == '=' && !wspace)
1.1 christos 265: *s += strspn(*s + 1, WHITESPACE) + 1;
266:
267: return (old);
268: }
269:
1.16.2.2! pgoyette 270: /*
! 271: * Return next token in configuration line; splts on whitespace or a
! 272: * single '=' character.
! 273: */
! 274: char *
! 275: strdelim(char **s)
! 276: {
! 277: return strdelim_internal(s, 1);
! 278: }
! 279:
! 280: /*
! 281: * Return next token in configuration line; splts on whitespace only.
! 282: */
! 283: char *
! 284: strdelimw(char **s)
! 285: {
! 286: return strdelim_internal(s, 0);
! 287: }
! 288:
1.1 christos 289: struct passwd *
290: pwcopy(struct passwd *pw)
291: {
292: struct passwd *copy = xcalloc(1, sizeof(*copy));
293:
294: copy->pw_name = xstrdup(pw->pw_name);
295: copy->pw_passwd = xstrdup(pw->pw_passwd);
296: copy->pw_gecos = xstrdup(pw->pw_gecos);
297: copy->pw_uid = pw->pw_uid;
298: copy->pw_gid = pw->pw_gid;
299: copy->pw_expire = pw->pw_expire;
300: copy->pw_change = pw->pw_change;
301: copy->pw_class = xstrdup(pw->pw_class);
302: copy->pw_dir = xstrdup(pw->pw_dir);
303: copy->pw_shell = xstrdup(pw->pw_shell);
304: return copy;
305: }
306:
307: /*
308: * Convert ASCII string to TCP/IP port number.
309: * Port must be >=0 and <=65535.
310: * Return -1 if invalid.
311: */
312: int
313: a2port(const char *s)
314: {
315: long long port;
316: const char *errstr;
317:
318: port = strtonum(s, 0, 65535, &errstr);
319: if (errstr != NULL)
320: return -1;
321: return (int)port;
322: }
323:
324: int
325: a2tun(const char *s, int *remote)
326: {
327: const char *errstr = NULL;
328: char *sp, *ep;
329: int tun;
330:
331: if (remote != NULL) {
332: *remote = SSH_TUNID_ANY;
333: sp = xstrdup(s);
334: if ((ep = strchr(sp, ':')) == NULL) {
1.8 christos 335: free(sp);
1.1 christos 336: return (a2tun(s, NULL));
337: }
338: ep[0] = '\0'; ep++;
339: *remote = a2tun(ep, NULL);
340: tun = a2tun(sp, NULL);
1.8 christos 341: free(sp);
1.1 christos 342: return (*remote == SSH_TUNID_ERR ? *remote : tun);
343: }
344:
345: if (strcasecmp(s, "any") == 0)
346: return (SSH_TUNID_ANY);
347:
348: tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
349: if (errstr != NULL)
350: return (SSH_TUNID_ERR);
351:
352: return (tun);
353: }
354:
355: #define SECONDS 1
356: #define MINUTES (SECONDS * 60)
357: #define HOURS (MINUTES * 60)
358: #define DAYS (HOURS * 24)
359: #define WEEKS (DAYS * 7)
360:
361: /*
362: * Convert a time string into seconds; format is
363: * a sequence of:
364: * time[qualifier]
365: *
366: * Valid time qualifiers are:
367: * <none> seconds
368: * s|S seconds
369: * m|M minutes
370: * h|H hours
371: * d|D days
372: * w|W weeks
373: *
374: * Examples:
375: * 90m 90 minutes
376: * 1h30m 90 minutes
377: * 2d 2 days
378: * 1w 1 week
379: *
380: * Return -1 if time string is invalid.
381: */
382: long
383: convtime(const char *s)
384: {
1.15 christos 385: long total, secs, multiplier = 1;
1.1 christos 386: const char *p;
387: char *endp;
388:
389: errno = 0;
390: total = 0;
391: p = s;
392:
393: if (p == NULL || *p == '\0')
394: return -1;
395:
396: while (*p) {
397: secs = strtol(p, &endp, 10);
398: if (p == endp ||
399: (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
400: secs < 0)
401: return -1;
402:
403: switch (*endp++) {
404: case '\0':
405: endp--;
406: break;
407: case 's':
408: case 'S':
409: break;
410: case 'm':
411: case 'M':
1.15 christos 412: multiplier = MINUTES;
1.1 christos 413: break;
414: case 'h':
415: case 'H':
1.15 christos 416: multiplier = HOURS;
1.1 christos 417: break;
418: case 'd':
419: case 'D':
1.15 christos 420: multiplier = DAYS;
1.1 christos 421: break;
422: case 'w':
423: case 'W':
1.15 christos 424: multiplier = WEEKS;
1.1 christos 425: break;
426: default:
427: return -1;
428: }
1.15 christos 429: if (secs >= LONG_MAX / multiplier)
430: return -1;
431: secs *= multiplier;
432: if (total >= LONG_MAX - secs)
433: return -1;
1.1 christos 434: total += secs;
435: if (total < 0)
436: return -1;
437: p = endp;
438: }
439:
440: return total;
441: }
442:
443: /*
444: * Returns a standardized host+port identifier string.
445: * Caller must free returned string.
446: */
447: char *
448: put_host_port(const char *host, u_short port)
449: {
450: char *hoststr;
451:
452: if (port == 0 || port == SSH_DEFAULT_PORT)
453: return(xstrdup(host));
454: if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
455: fatal("put_host_port: asprintf: %s", strerror(errno));
456: debug3("put_host_port: %s", hoststr);
457: return hoststr;
458: }
459:
460: /*
461: * Search for next delimiter between hostnames/addresses and ports.
462: * Argument may be modified (for termination).
463: * Returns *cp if parsing succeeds.
1.16.2.1 pgoyette 464: * *cp is set to the start of the next field, if one was found.
465: * The delimiter char, if present, is stored in delim.
1.1 christos 466: * If this is the last field, *cp is set to NULL.
467: */
1.16.2.1 pgoyette 468: static char *
469: hpdelim2(char **cp, char *delim)
1.1 christos 470: {
471: char *s, *old;
472:
473: if (cp == NULL || *cp == NULL)
474: return NULL;
475:
476: old = s = *cp;
477: if (*s == '[') {
478: if ((s = strchr(s, ']')) == NULL)
479: return NULL;
480: else
481: s++;
482: } else if ((s = strpbrk(s, ":/")) == NULL)
483: s = *cp + strlen(*cp); /* skip to end (see first case below) */
484:
485: switch (*s) {
486: case '\0':
487: *cp = NULL; /* no more fields*/
488: break;
489:
490: case ':':
491: case '/':
1.16.2.1 pgoyette 492: if (delim != NULL)
493: *delim = *s;
1.1 christos 494: *s = '\0'; /* terminate */
495: *cp = s + 1;
496: break;
497:
498: default:
499: return NULL;
500: }
501:
502: return old;
503: }
504:
505: char *
1.16.2.1 pgoyette 506: hpdelim(char **cp)
507: {
508: return hpdelim2(cp, NULL);
509: }
510:
511: char *
1.1 christos 512: cleanhostname(char *host)
513: {
514: if (*host == '[' && host[strlen(host) - 1] == ']') {
515: host[strlen(host) - 1] = '\0';
516: return (host + 1);
517: } else
518: return host;
519: }
520:
521: char *
522: colon(char *cp)
523: {
524: int flag = 0;
525:
526: if (*cp == ':') /* Leading colon is part of file name. */
1.4 adam 527: return NULL;
1.1 christos 528: if (*cp == '[')
529: flag = 1;
530:
531: for (; *cp; ++cp) {
532: if (*cp == '@' && *(cp+1) == '[')
533: flag = 1;
534: if (*cp == ']' && *(cp+1) == ':' && flag)
535: return (cp+1);
536: if (*cp == ':' && !flag)
537: return (cp);
538: if (*cp == '/')
1.4 adam 539: return NULL;
1.1 christos 540: }
1.4 adam 541: return NULL;
1.1 christos 542: }
543:
1.13 christos 544: /*
1.16.2.1 pgoyette 545: * Parse a [user@]host:[path] string.
546: * Caller must free returned user, host and path.
547: * Any of the pointer return arguments may be NULL (useful for syntax checking).
548: * If user was not specified then *userp will be set to NULL.
549: * If host was not specified then *hostp will be set to NULL.
550: * If path was not specified then *pathp will be set to ".".
551: * Returns 0 on success, -1 on failure.
552: */
553: int
554: parse_user_host_path(const char *s, char **userp, char **hostp,
555: const char **pathp)
556: {
557: char *user = NULL, *host = NULL, *path = NULL;
558: char *tmp, *sdup;
559: int ret = -1;
560:
561: if (userp != NULL)
562: *userp = NULL;
563: if (hostp != NULL)
564: *hostp = NULL;
565: if (pathp != NULL)
566: *pathp = NULL;
567:
568: sdup = xstrdup(s);
569:
570: /* Check for remote syntax: [user@]host:[path] */
571: if ((tmp = colon(sdup)) == NULL)
572: goto out;
573:
574: /* Extract optional path */
575: *tmp++ = '\0';
576: if (*tmp == '\0')
577: tmp = __UNCONST(".");
578: path = xstrdup(tmp);
579:
580: /* Extract optional user and mandatory host */
581: tmp = strrchr(sdup, '@');
582: if (tmp != NULL) {
583: *tmp++ = '\0';
584: host = xstrdup(cleanhostname(tmp));
585: if (*sdup != '\0')
586: user = xstrdup(sdup);
587: } else {
588: host = xstrdup(cleanhostname(sdup));
589: user = NULL;
590: }
591:
592: /* Success */
593: if (userp != NULL) {
594: *userp = user;
595: user = NULL;
596: }
597: if (hostp != NULL) {
598: *hostp = host;
599: host = NULL;
600: }
601: if (pathp != NULL) {
602: *pathp = path;
603: path = NULL;
604: }
605: ret = 0;
606: out:
607: free(sdup);
608: free(user);
609: free(host);
610: free(path);
611: return ret;
612: }
613:
614: /*
1.13 christos 615: * Parse a [user@]host[:port] string.
616: * Caller must free returned user and host.
617: * Any of the pointer return arguments may be NULL (useful for syntax checking).
618: * If user was not specified then *userp will be set to NULL.
619: * If port was not specified then *portp will be -1.
620: * Returns 0 on success, -1 on failure.
621: */
622: int
623: parse_user_host_port(const char *s, char **userp, char **hostp, int *portp)
624: {
625: char *sdup, *cp, *tmp;
626: char *user = NULL, *host = NULL;
627: int port = -1, ret = -1;
628:
629: if (userp != NULL)
630: *userp = NULL;
631: if (hostp != NULL)
632: *hostp = NULL;
633: if (portp != NULL)
634: *portp = -1;
635:
636: if ((sdup = tmp = strdup(s)) == NULL)
637: return -1;
638: /* Extract optional username */
1.16.2.1 pgoyette 639: if ((cp = strrchr(tmp, '@')) != NULL) {
1.13 christos 640: *cp = '\0';
641: if (*tmp == '\0')
642: goto out;
643: if ((user = strdup(tmp)) == NULL)
644: goto out;
645: tmp = cp + 1;
646: }
647: /* Extract mandatory hostname */
648: if ((cp = hpdelim(&tmp)) == NULL || *cp == '\0')
649: goto out;
650: host = xstrdup(cleanhostname(cp));
651: /* Convert and verify optional port */
652: if (tmp != NULL && *tmp != '\0') {
653: if ((port = a2port(tmp)) <= 0)
654: goto out;
655: }
656: /* Success */
657: if (userp != NULL) {
658: *userp = user;
659: user = NULL;
660: }
661: if (hostp != NULL) {
662: *hostp = host;
663: host = NULL;
664: }
665: if (portp != NULL)
666: *portp = port;
667: ret = 0;
668: out:
669: free(sdup);
670: free(user);
671: free(host);
672: return ret;
673: }
674:
1.16.2.1 pgoyette 675: /*
676: * Converts a two-byte hex string to decimal.
677: * Returns the decimal value or -1 for invalid input.
678: */
679: static int
680: hexchar(const char *s)
681: {
682: unsigned char result[2];
683: int i;
684:
685: for (i = 0; i < 2; i++) {
686: if (s[i] >= '0' && s[i] <= '9')
687: result[i] = (unsigned char)(s[i] - '0');
688: else if (s[i] >= 'a' && s[i] <= 'f')
689: result[i] = (unsigned char)(s[i] - 'a') + 10;
690: else if (s[i] >= 'A' && s[i] <= 'F')
691: result[i] = (unsigned char)(s[i] - 'A') + 10;
692: else
693: return -1;
694: }
695: return (result[0] << 4) | result[1];
696: }
697:
698: /*
699: * Decode an url-encoded string.
700: * Returns a newly allocated string on success or NULL on failure.
701: */
702: static char *
703: urldecode(const char *src)
704: {
705: char *ret, *dst;
706: int ch;
707:
708: ret = xmalloc(strlen(src) + 1);
709: for (dst = ret; *src != '\0'; src++) {
710: switch (*src) {
711: case '+':
712: *dst++ = ' ';
713: break;
714: case '%':
715: if (!isxdigit((unsigned char)src[1]) ||
716: !isxdigit((unsigned char)src[2]) ||
717: (ch = hexchar(src + 1)) == -1) {
718: free(ret);
719: return NULL;
720: }
721: *dst++ = ch;
722: src += 2;
723: break;
724: default:
725: *dst++ = *src;
726: break;
727: }
728: }
729: *dst = '\0';
730:
731: return ret;
732: }
733:
734: /*
735: * Parse an (scp|ssh|sftp)://[user@]host[:port][/path] URI.
736: * See https://tools.ietf.org/html/draft-ietf-secsh-scp-sftp-ssh-uri-04
737: * Either user or path may be url-encoded (but not host or port).
738: * Caller must free returned user, host and path.
739: * Any of the pointer return arguments may be NULL (useful for syntax checking)
740: * but the scheme must always be specified.
741: * If user was not specified then *userp will be set to NULL.
742: * If port was not specified then *portp will be -1.
743: * If path was not specified then *pathp will be set to NULL.
744: * Returns 0 on success, 1 if non-uri/wrong scheme, -1 on error/invalid uri.
745: */
746: int
747: parse_uri(const char *scheme, const char *uri, char **userp, char **hostp,
748: int *portp, const char **pathp)
749: {
750: char *uridup, *cp, *tmp, ch;
751: char *user = NULL, *host = NULL, *path = NULL;
752: int port = -1, ret = -1;
753: size_t len;
754:
755: len = strlen(scheme);
756: if (strncmp(uri, scheme, len) != 0 || strncmp(uri + len, "://", 3) != 0)
757: return 1;
758: uri += len + 3;
759:
760: if (userp != NULL)
761: *userp = NULL;
762: if (hostp != NULL)
763: *hostp = NULL;
764: if (portp != NULL)
765: *portp = -1;
766: if (pathp != NULL)
767: *pathp = NULL;
768:
769: uridup = tmp = xstrdup(uri);
770:
771: /* Extract optional ssh-info (username + connection params) */
772: if ((cp = strchr(tmp, '@')) != NULL) {
773: char *delim;
774:
775: *cp = '\0';
776: /* Extract username and connection params */
777: if ((delim = strchr(tmp, ';')) != NULL) {
778: /* Just ignore connection params for now */
779: *delim = '\0';
780: }
781: if (*tmp == '\0') {
782: /* Empty username */
783: goto out;
784: }
785: if ((user = urldecode(tmp)) == NULL)
786: goto out;
787: tmp = cp + 1;
788: }
789:
790: /* Extract mandatory hostname */
791: if ((cp = hpdelim2(&tmp, &ch)) == NULL || *cp == '\0')
792: goto out;
793: host = xstrdup(cleanhostname(cp));
794: if (!valid_domain(host, 0, NULL))
795: goto out;
796:
797: if (tmp != NULL && *tmp != '\0') {
798: if (ch == ':') {
799: /* Convert and verify port. */
800: if ((cp = strchr(tmp, '/')) != NULL)
801: *cp = '\0';
802: if ((port = a2port(tmp)) <= 0)
803: goto out;
804: tmp = cp ? cp + 1 : NULL;
805: }
806: if (tmp != NULL && *tmp != '\0') {
807: /* Extract optional path */
808: if ((path = urldecode(tmp)) == NULL)
809: goto out;
810: }
811: }
812:
813: /* Success */
814: if (userp != NULL) {
815: *userp = user;
816: user = NULL;
817: }
818: if (hostp != NULL) {
819: *hostp = host;
820: host = NULL;
821: }
822: if (portp != NULL)
823: *portp = port;
824: if (pathp != NULL) {
825: *pathp = path;
826: path = NULL;
827: }
828: ret = 0;
829: out:
830: free(uridup);
831: free(user);
832: free(host);
833: free(path);
834: return ret;
835: }
836:
1.1 christos 837: /* function to assist building execv() arguments */
838: void
1.5 christos 839: addargs(arglist *args, const char *fmt, ...)
1.1 christos 840: {
841: va_list ap;
842: char *cp;
843: u_int nalloc;
844: int r;
845:
846: va_start(ap, fmt);
847: r = vasprintf(&cp, fmt, ap);
848: va_end(ap);
849: if (r == -1)
850: fatal("addargs: argument too long");
851:
852: nalloc = args->nalloc;
853: if (args->list == NULL) {
854: nalloc = 32;
855: args->num = 0;
856: } else if (args->num+2 >= nalloc)
857: nalloc *= 2;
858:
1.16 christos 859: args->list = xrecallocarray(args->list, args->nalloc, nalloc, sizeof(char *));
1.1 christos 860: args->nalloc = nalloc;
861: args->list[args->num++] = cp;
862: args->list[args->num] = NULL;
863: }
864:
865: void
1.5 christos 866: replacearg(arglist *args, u_int which, const char *fmt, ...)
1.1 christos 867: {
868: va_list ap;
869: char *cp;
870: int r;
871:
872: va_start(ap, fmt);
873: r = vasprintf(&cp, fmt, ap);
874: va_end(ap);
875: if (r == -1)
876: fatal("replacearg: argument too long");
877:
878: if (which >= args->num)
879: fatal("replacearg: tried to replace invalid arg %d >= %d",
880: which, args->num);
1.8 christos 881: free(args->list[which]);
1.1 christos 882: args->list[which] = cp;
883: }
884:
885: void
886: freeargs(arglist *args)
887: {
888: u_int i;
889:
890: if (args->list != NULL) {
891: for (i = 0; i < args->num; i++)
1.8 christos 892: free(args->list[i]);
893: free(args->list);
1.1 christos 894: args->nalloc = args->num = 0;
895: args->list = NULL;
896: }
897: }
898:
899: /*
900: * Expands tildes in the file name. Returns data allocated by xmalloc.
901: * Warning: this calls getpw*.
902: */
903: char *
904: tilde_expand_filename(const char *filename, uid_t uid)
905: {
1.8 christos 906: const char *path, *sep;
907: char user[128], *ret, *homedir;
1.1 christos 908: struct passwd *pw;
909: u_int len, slash;
910:
911: if (*filename != '~')
912: return (xstrdup(filename));
913: filename++;
914:
915: path = strchr(filename, '/');
916: if (path != NULL && path > filename) { /* ~user/path */
917: slash = path - filename;
918: if (slash > sizeof(user) - 1)
919: fatal("tilde_expand_filename: ~username too long");
920: memcpy(user, filename, slash);
921: user[slash] = '\0';
922: if ((pw = getpwnam(user)) == NULL)
923: fatal("tilde_expand_filename: No such user %s", user);
1.2 christos 924: homedir = pw->pw_dir;
925: } else {
926: if ((pw = getpwuid(uid)) == NULL) /* ~/path */
927: fatal("tilde_expand_filename: No such uid %ld",
928: (long)uid);
929: homedir = pw->pw_dir;
930: }
1.1 christos 931:
932: /* Make sure directory has a trailing '/' */
1.2 christos 933: len = strlen(homedir);
1.8 christos 934: if (len == 0 || homedir[len - 1] != '/')
935: sep = "/";
936: else
937: sep = "";
1.1 christos 938:
939: /* Skip leading '/' from specified path */
940: if (path != NULL)
941: filename = path + 1;
1.8 christos 942:
1.10 christos 943: if (xasprintf(&ret, "%s%s%s", homedir, sep, filename) >= PATH_MAX)
1.1 christos 944: fatal("tilde_expand_filename: Path too long");
945:
1.8 christos 946: return (ret);
1.1 christos 947: }
948:
949: /*
950: * Expand a string with a set of %[char] escapes. A number of escapes may be
951: * specified as (char *escape_chars, char *replacement) pairs. The list must
952: * be terminated by a NULL escape_char. Returns replaced string in memory
953: * allocated by xmalloc.
954: */
955: char *
956: percent_expand(const char *string, ...)
957: {
958: #define EXPAND_MAX_KEYS 16
1.4 adam 959: u_int num_keys, i, j;
1.1 christos 960: struct {
961: const char *key;
962: const char *repl;
963: } keys[EXPAND_MAX_KEYS];
964: char buf[4096];
965: va_list ap;
966:
967: /* Gather keys */
968: va_start(ap, string);
969: for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
970: keys[num_keys].key = va_arg(ap, char *);
971: if (keys[num_keys].key == NULL)
972: break;
973: keys[num_keys].repl = va_arg(ap, char *);
974: if (keys[num_keys].repl == NULL)
1.4 adam 975: fatal("%s: NULL replacement", __func__);
1.1 christos 976: }
1.4 adam 977: if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
978: fatal("%s: too many keys", __func__);
1.1 christos 979: va_end(ap);
980:
981: /* Expand string */
982: *buf = '\0';
983: for (i = 0; *string != '\0'; string++) {
984: if (*string != '%') {
985: append:
986: buf[i++] = *string;
987: if (i >= sizeof(buf))
1.4 adam 988: fatal("%s: string too long", __func__);
1.1 christos 989: buf[i] = '\0';
990: continue;
991: }
992: string++;
1.4 adam 993: /* %% case */
1.1 christos 994: if (*string == '%')
995: goto append;
1.12 christos 996: if (*string == '\0')
997: fatal("%s: invalid format", __func__);
1.1 christos 998: for (j = 0; j < num_keys; j++) {
999: if (strchr(keys[j].key, *string) != NULL) {
1000: i = strlcat(buf, keys[j].repl, sizeof(buf));
1001: if (i >= sizeof(buf))
1.4 adam 1002: fatal("%s: string too long", __func__);
1.1 christos 1003: break;
1004: }
1005: }
1006: if (j >= num_keys)
1.4 adam 1007: fatal("%s: unknown key %%%c", __func__, *string);
1.1 christos 1008: }
1009: return (xstrdup(buf));
1010: #undef EXPAND_MAX_KEYS
1011: }
1012:
1013: int
1.16.2.1 pgoyette 1014: tun_open(int tun, int mode, char **ifname)
1.1 christos 1015: {
1016: struct ifreq ifr;
1.12 christos 1017: char name[100];
1018: int fd = -1, sock;
1019: const char *tunbase = "tun";
1020:
1.16.2.1 pgoyette 1021: if (ifname != NULL)
1022: *ifname = NULL;
1023:
1.12 christos 1024: if (mode == SSH_TUNMODE_ETHERNET)
1025: tunbase = "tap";
1.1 christos 1026:
1027: /* Open the tunnel device */
1028: if (tun <= SSH_TUNID_MAX) {
1.12 christos 1029: snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
1030: fd = open(name, O_RDWR);
1.1 christos 1031: } else if (tun == SSH_TUNID_ANY) {
1032: for (tun = 100; tun >= 0; tun--) {
1.12 christos 1033: snprintf(name, sizeof(name), "/dev/%s%d",
1034: tunbase, tun);
1035: if ((fd = open(name, O_RDWR)) >= 0)
1.1 christos 1036: break;
1037: }
1038: } else {
1039: debug("%s: invalid tunnel %u", __func__, tun);
1.12 christos 1040: return -1;
1.1 christos 1041: }
1042:
1043: if (fd < 0) {
1.12 christos 1044: debug("%s: %s open: %s", __func__, name, strerror(errno));
1045: return -1;
1.1 christos 1046: }
1047:
1048:
1.12 christos 1049: #ifdef TUNSIFHEAD
1.2 christos 1050: /* Turn on tunnel headers */
1.12 christos 1051: int flag = 1;
1.2 christos 1052: if (mode != SSH_TUNMODE_ETHERNET &&
1053: ioctl(fd, TUNSIFHEAD, &flag) == -1) {
1054: debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd,
1055: strerror(errno));
1056: close(fd);
1057: return -1;
1058: }
1.12 christos 1059: #endif
1.2 christos 1060:
1061: debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd);
1.12 christos 1062: /* Bring interface up if it is not already */
1.3 jnemeth 1063: snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
1.1 christos 1064: if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
1065: goto failed;
1066:
1.12 christos 1067: if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
1068: debug("%s: get interface %s flags: %s", __func__,
1069: ifr.ifr_name, strerror(errno));
1.1 christos 1070: goto failed;
1.12 christos 1071: }
1.1 christos 1072:
1.12 christos 1073: if (!(ifr.ifr_flags & IFF_UP)) {
1074: ifr.ifr_flags |= IFF_UP;
1075: if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
1076: debug("%s: activate interface %s: %s", __func__,
1077: ifr.ifr_name, strerror(errno));
1078: goto failed;
1079: }
1080: }
1.1 christos 1081:
1.16.2.1 pgoyette 1082: if (ifname != NULL)
1083: *ifname = xstrdup(ifr.ifr_name);
1084:
1.1 christos 1085: close(sock);
1.12 christos 1086: return fd;
1.1 christos 1087:
1088: failed:
1089: if (fd >= 0)
1090: close(fd);
1091: if (sock >= 0)
1092: close(sock);
1.2 christos 1093: debug("%s: failed to set %s mode %d: %s", __func__, ifr.ifr_name,
1.1 christos 1094: mode, strerror(errno));
1.12 christos 1095: return -1;
1.1 christos 1096: }
1097:
1098: void
1099: sanitise_stdfd(void)
1100: {
1101: int nullfd, dupfd;
1102:
1103: if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
1104: fprintf(stderr, "Couldn't open /dev/null: %s\n",
1105: strerror(errno));
1106: exit(1);
1107: }
1.13 christos 1108: while (++dupfd <= STDERR_FILENO) {
1109: /* Only populate closed fds. */
1110: if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) {
1111: if (dup2(nullfd, dupfd) == -1) {
1112: fprintf(stderr, "dup2: %s\n", strerror(errno));
1113: exit(1);
1114: }
1.1 christos 1115: }
1116: }
1.13 christos 1117: if (nullfd > STDERR_FILENO)
1.1 christos 1118: close(nullfd);
1119: }
1120:
1121: char *
1122: tohex(const void *vp, size_t l)
1123: {
1124: const u_char *p = (const u_char *)vp;
1125: char b[3], *r;
1126: size_t i, hl;
1127:
1128: if (l > 65536)
1129: return xstrdup("tohex: length > 65536");
1130:
1131: hl = l * 2 + 1;
1132: r = xcalloc(1, hl);
1133: for (i = 0; i < l; i++) {
1134: snprintf(b, sizeof(b), "%02x", p[i]);
1135: strlcat(r, b, hl);
1136: }
1137: return (r);
1138: }
1139:
1140: u_int64_t
1141: get_u64(const void *vp)
1142: {
1143: const u_char *p = (const u_char *)vp;
1144: u_int64_t v;
1145:
1146: v = (u_int64_t)p[0] << 56;
1147: v |= (u_int64_t)p[1] << 48;
1148: v |= (u_int64_t)p[2] << 40;
1149: v |= (u_int64_t)p[3] << 32;
1150: v |= (u_int64_t)p[4] << 24;
1151: v |= (u_int64_t)p[5] << 16;
1152: v |= (u_int64_t)p[6] << 8;
1153: v |= (u_int64_t)p[7];
1154:
1155: return (v);
1156: }
1157:
1158: u_int32_t
1159: get_u32(const void *vp)
1160: {
1161: const u_char *p = (const u_char *)vp;
1162: u_int32_t v;
1163:
1164: v = (u_int32_t)p[0] << 24;
1165: v |= (u_int32_t)p[1] << 16;
1166: v |= (u_int32_t)p[2] << 8;
1167: v |= (u_int32_t)p[3];
1168:
1169: return (v);
1170: }
1171:
1.9 christos 1172: u_int32_t
1173: get_u32_le(const void *vp)
1174: {
1175: const u_char *p = (const u_char *)vp;
1176: u_int32_t v;
1177:
1178: v = (u_int32_t)p[0];
1179: v |= (u_int32_t)p[1] << 8;
1180: v |= (u_int32_t)p[2] << 16;
1181: v |= (u_int32_t)p[3] << 24;
1182:
1183: return (v);
1184: }
1185:
1.1 christos 1186: u_int16_t
1187: get_u16(const void *vp)
1188: {
1189: const u_char *p = (const u_char *)vp;
1190: u_int16_t v;
1191:
1192: v = (u_int16_t)p[0] << 8;
1193: v |= (u_int16_t)p[1];
1194:
1195: return (v);
1196: }
1197:
1198: void
1199: put_u64(void *vp, u_int64_t v)
1200: {
1201: u_char *p = (u_char *)vp;
1202:
1203: p[0] = (u_char)(v >> 56) & 0xff;
1204: p[1] = (u_char)(v >> 48) & 0xff;
1205: p[2] = (u_char)(v >> 40) & 0xff;
1206: p[3] = (u_char)(v >> 32) & 0xff;
1207: p[4] = (u_char)(v >> 24) & 0xff;
1208: p[5] = (u_char)(v >> 16) & 0xff;
1209: p[6] = (u_char)(v >> 8) & 0xff;
1210: p[7] = (u_char)v & 0xff;
1211: }
1212:
1213: void
1214: put_u32(void *vp, u_int32_t v)
1215: {
1216: u_char *p = (u_char *)vp;
1217:
1218: p[0] = (u_char)(v >> 24) & 0xff;
1219: p[1] = (u_char)(v >> 16) & 0xff;
1220: p[2] = (u_char)(v >> 8) & 0xff;
1221: p[3] = (u_char)v & 0xff;
1222: }
1223:
1.9 christos 1224: void
1225: put_u32_le(void *vp, u_int32_t v)
1226: {
1227: u_char *p = (u_char *)vp;
1228:
1229: p[0] = (u_char)v & 0xff;
1230: p[1] = (u_char)(v >> 8) & 0xff;
1231: p[2] = (u_char)(v >> 16) & 0xff;
1232: p[3] = (u_char)(v >> 24) & 0xff;
1233: }
1.1 christos 1234:
1235: void
1236: put_u16(void *vp, u_int16_t v)
1237: {
1238: u_char *p = (u_char *)vp;
1239:
1240: p[0] = (u_char)(v >> 8) & 0xff;
1241: p[1] = (u_char)v & 0xff;
1242: }
1243:
1244: void
1245: ms_subtract_diff(struct timeval *start, int *ms)
1246: {
1247: struct timeval diff, finish;
1248:
1.16.2.1 pgoyette 1249: monotime_tv(&finish);
1250: timersub(&finish, start, &diff);
1.1 christos 1251: *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
1252: }
1253:
1254: void
1255: ms_to_timeval(struct timeval *tv, int ms)
1256: {
1257: if (ms < 0)
1258: ms = 0;
1259: tv->tv_sec = ms / 1000;
1260: tv->tv_usec = (ms % 1000) * 1000;
1261: }
1262:
1.16.2.1 pgoyette 1263: void
1264: monotime_ts(struct timespec *ts)
1265: {
1266: if (clock_gettime(CLOCK_MONOTONIC, ts) != 0)
1267: fatal("clock_gettime: %s", strerror(errno));
1268: }
1269:
1270: void
1271: monotime_tv(struct timeval *tv)
1272: {
1273: struct timespec ts;
1274:
1275: monotime_ts(&ts);
1276: tv->tv_sec = ts.tv_sec;
1277: tv->tv_usec = ts.tv_nsec / 1000;
1278: }
1279:
1.8 christos 1280: time_t
1281: monotime(void)
1282: {
1283: struct timespec ts;
1284:
1.16.2.1 pgoyette 1285: monotime_ts(&ts);
1.8 christos 1286: return (ts.tv_sec);
1287: }
1288:
1.13 christos 1289: double
1290: monotime_double(void)
1291: {
1292: struct timespec ts;
1293:
1.16.2.1 pgoyette 1294: monotime_ts(&ts);
1295: return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
1.13 christos 1296: }
1297:
1.5 christos 1298: void
1299: bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
1300: {
1301: bw->buflen = buflen;
1302: bw->rate = kbps;
1303: bw->thresh = bw->rate;
1304: bw->lamt = 0;
1305: timerclear(&bw->bwstart);
1306: timerclear(&bw->bwend);
1307: }
1308:
1309: /* Callback from read/write loop to insert bandwidth-limiting delays */
1310: void
1311: bandwidth_limit(struct bwlimit *bw, size_t read_len)
1312: {
1313: u_int64_t waitlen;
1314: struct timespec ts, rm;
1315:
1316: if (!timerisset(&bw->bwstart)) {
1.16.2.1 pgoyette 1317: monotime_tv(&bw->bwstart);
1.5 christos 1318: return;
1319: }
1320:
1321: bw->lamt += read_len;
1322: if (bw->lamt < bw->thresh)
1323: return;
1324:
1.16.2.1 pgoyette 1325: monotime_tv(&bw->bwend);
1.5 christos 1326: timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
1327: if (!timerisset(&bw->bwend))
1328: return;
1329:
1330: bw->lamt *= 8;
1331: waitlen = (double)1000000L * bw->lamt / bw->rate;
1332:
1333: bw->bwstart.tv_sec = waitlen / 1000000L;
1334: bw->bwstart.tv_usec = waitlen % 1000000L;
1335:
1336: if (timercmp(&bw->bwstart, &bw->bwend, >)) {
1337: timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
1338:
1339: /* Adjust the wait time */
1340: if (bw->bwend.tv_sec) {
1341: bw->thresh /= 2;
1342: if (bw->thresh < bw->buflen / 4)
1343: bw->thresh = bw->buflen / 4;
1344: } else if (bw->bwend.tv_usec < 10000) {
1345: bw->thresh *= 2;
1346: if (bw->thresh > bw->buflen * 8)
1347: bw->thresh = bw->buflen * 8;
1348: }
1349:
1350: TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
1351: while (nanosleep(&ts, &rm) == -1) {
1352: if (errno != EINTR)
1353: break;
1354: ts = rm;
1355: }
1356: }
1357:
1358: bw->lamt = 0;
1.16.2.1 pgoyette 1359: monotime_tv(&bw->bwstart);
1.5 christos 1360: }
1361:
1362: /* Make a template filename for mk[sd]temp() */
1363: void
1364: mktemp_proto(char *s, size_t len)
1365: {
1366: const char *tmpdir;
1367: int r;
1368:
1369: if ((tmpdir = getenv("TMPDIR")) != NULL) {
1370: r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
1371: if (r > 0 && (size_t)r < len)
1372: return;
1373: }
1374: r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
1375: if (r < 0 || (size_t)r >= len)
1376: fatal("%s: template string too short", __func__);
1377: }
1378:
1379: static const struct {
1380: const char *name;
1381: int value;
1382: } ipqos[] = {
1.16 christos 1383: { "none", INT_MAX }, /* can't use 0 here; that's CS0 */
1.5 christos 1384: { "af11", IPTOS_DSCP_AF11 },
1385: { "af12", IPTOS_DSCP_AF12 },
1386: { "af13", IPTOS_DSCP_AF13 },
1.7 christos 1387: { "af21", IPTOS_DSCP_AF21 },
1.5 christos 1388: { "af22", IPTOS_DSCP_AF22 },
1389: { "af23", IPTOS_DSCP_AF23 },
1390: { "af31", IPTOS_DSCP_AF31 },
1391: { "af32", IPTOS_DSCP_AF32 },
1392: { "af33", IPTOS_DSCP_AF33 },
1393: { "af41", IPTOS_DSCP_AF41 },
1394: { "af42", IPTOS_DSCP_AF42 },
1395: { "af43", IPTOS_DSCP_AF43 },
1396: { "cs0", IPTOS_DSCP_CS0 },
1397: { "cs1", IPTOS_DSCP_CS1 },
1398: { "cs2", IPTOS_DSCP_CS2 },
1399: { "cs3", IPTOS_DSCP_CS3 },
1400: { "cs4", IPTOS_DSCP_CS4 },
1401: { "cs5", IPTOS_DSCP_CS5 },
1402: { "cs6", IPTOS_DSCP_CS6 },
1403: { "cs7", IPTOS_DSCP_CS7 },
1404: { "ef", IPTOS_DSCP_EF },
1405: { "lowdelay", IPTOS_LOWDELAY },
1406: { "throughput", IPTOS_THROUGHPUT },
1407: { "reliability", IPTOS_RELIABILITY },
1408: { NULL, -1 }
1409: };
1410:
1411: int
1412: parse_ipqos(const char *cp)
1413: {
1414: u_int i;
1415: char *ep;
1416: long val;
1417:
1418: if (cp == NULL)
1419: return -1;
1420: for (i = 0; ipqos[i].name != NULL; i++) {
1421: if (strcasecmp(cp, ipqos[i].name) == 0)
1422: return ipqos[i].value;
1423: }
1424: /* Try parsing as an integer */
1425: val = strtol(cp, &ep, 0);
1426: if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
1427: return -1;
1428: return val;
1429: }
1430:
1.6 christos 1431: const char *
1432: iptos2str(int iptos)
1433: {
1434: int i;
1435: static char iptos_str[sizeof "0xff"];
1436:
1437: for (i = 0; ipqos[i].name != NULL; i++) {
1438: if (ipqos[i].value == iptos)
1439: return ipqos[i].name;
1440: }
1441: snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
1442: return iptos_str;
1443: }
1444:
1.9 christos 1445: void
1446: lowercase(char *s)
1447: {
1448: for (; *s; s++)
1449: *s = tolower((u_char)*s);
1450: }
1451:
1.4 adam 1452: int
1.9 christos 1453: unix_listener(const char *path, int backlog, int unlink_first)
1.4 adam 1454: {
1.9 christos 1455: struct sockaddr_un sunaddr;
1456: int saved_errno, sock;
1.4 adam 1457:
1.9 christos 1458: memset(&sunaddr, 0, sizeof(sunaddr));
1459: sunaddr.sun_family = AF_UNIX;
1.16.2.1 pgoyette 1460: if (strlcpy(sunaddr.sun_path, path,
1461: sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
1462: error("%s: path \"%s\" too long for Unix domain socket",
1463: __func__, path);
1.9 christos 1464: errno = ENAMETOOLONG;
1465: return -1;
1466: }
1467:
1468: sock = socket(PF_UNIX, SOCK_STREAM, 0);
1469: if (sock < 0) {
1470: saved_errno = errno;
1.16.2.1 pgoyette 1471: error("%s: socket: %.100s", __func__, strerror(errno));
1.9 christos 1472: errno = saved_errno;
1473: return -1;
1474: }
1475: if (unlink_first == 1) {
1476: if (unlink(path) != 0 && errno != ENOENT)
1477: error("unlink(%s): %.100s", path, strerror(errno));
1478: }
1479: if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
1480: saved_errno = errno;
1.16.2.1 pgoyette 1481: error("%s: cannot bind to path %s: %s",
1482: __func__, path, strerror(errno));
1.9 christos 1483: close(sock);
1484: errno = saved_errno;
1485: return -1;
1486: }
1487: if (listen(sock, backlog) < 0) {
1488: saved_errno = errno;
1.16.2.1 pgoyette 1489: error("%s: cannot listen on path %s: %s",
1490: __func__, path, strerror(errno));
1.9 christos 1491: close(sock);
1492: unlink(path);
1493: errno = saved_errno;
1494: return -1;
1495: }
1496: return sock;
1.4 adam 1497: }
1.13 christos 1498:
1499: /*
1500: * Compares two strings that maybe be NULL. Returns non-zero if strings
1501: * are both NULL or are identical, returns zero otherwise.
1502: */
1503: static int
1504: strcmp_maybe_null(const char *a, const char *b)
1505: {
1506: if ((a == NULL && b != NULL) || (a != NULL && b == NULL))
1507: return 0;
1508: if (a != NULL && strcmp(a, b) != 0)
1509: return 0;
1510: return 1;
1511: }
1512:
1513: /*
1514: * Compare two forwards, returning non-zero if they are identical or
1515: * zero otherwise.
1516: */
1517: int
1518: forward_equals(const struct Forward *a, const struct Forward *b)
1519: {
1520: if (strcmp_maybe_null(a->listen_host, b->listen_host) == 0)
1521: return 0;
1522: if (a->listen_port != b->listen_port)
1523: return 0;
1524: if (strcmp_maybe_null(a->listen_path, b->listen_path) == 0)
1525: return 0;
1526: if (strcmp_maybe_null(a->connect_host, b->connect_host) == 0)
1527: return 0;
1528: if (a->connect_port != b->connect_port)
1529: return 0;
1530: if (strcmp_maybe_null(a->connect_path, b->connect_path) == 0)
1531: return 0;
1532: /* allocated_port and handle are not checked */
1533: return 1;
1534: }
1535:
1.14 christos 1536: /* returns 1 if process is already daemonized, 0 otherwise */
1537: int
1538: daemonized(void)
1539: {
1540: int fd;
1541:
1542: if ((fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY)) >= 0) {
1543: close(fd);
1544: return 0; /* have controlling terminal */
1545: }
1546: if (getppid() != 1)
1547: return 0; /* parent is not init */
1548: if (getsid(0) != getpid())
1549: return 0; /* not session leader */
1550: debug3("already daemonized");
1551: return 1;
1552: }
1.16 christos 1553:
1554:
1555: /*
1556: * Splits 's' into an argument vector. Handles quoted string and basic
1557: * escape characters (\\, \", \'). Caller must free the argument vector
1558: * and its members.
1559: */
1560: int
1561: argv_split(const char *s, int *argcp, char ***argvp)
1562: {
1563: int r = SSH_ERR_INTERNAL_ERROR;
1564: int argc = 0, quote, i, j;
1565: char *arg, **argv = xcalloc(1, sizeof(*argv));
1566:
1567: *argvp = NULL;
1568: *argcp = 0;
1569:
1570: for (i = 0; s[i] != '\0'; i++) {
1571: /* Skip leading whitespace */
1572: if (s[i] == ' ' || s[i] == '\t')
1573: continue;
1574:
1575: /* Start of a token */
1576: quote = 0;
1577: if (s[i] == '\\' &&
1578: (s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
1579: i++;
1580: else if (s[i] == '\'' || s[i] == '"')
1581: quote = s[i++];
1582:
1583: argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
1584: arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
1585: argv[argc] = NULL;
1586:
1587: /* Copy the token in, removing escapes */
1588: for (j = 0; s[i] != '\0'; i++) {
1589: if (s[i] == '\\') {
1590: if (s[i + 1] == '\'' ||
1591: s[i + 1] == '\"' ||
1592: s[i + 1] == '\\') {
1593: i++; /* Skip '\' */
1594: arg[j++] = s[i];
1595: } else {
1596: /* Unrecognised escape */
1597: arg[j++] = s[i];
1598: }
1599: } else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
1600: break; /* done */
1601: else if (quote != 0 && s[i] == quote)
1602: break; /* done */
1603: else
1604: arg[j++] = s[i];
1605: }
1606: if (s[i] == '\0') {
1607: if (quote != 0) {
1608: /* Ran out of string looking for close quote */
1609: r = SSH_ERR_INVALID_FORMAT;
1610: goto out;
1611: }
1612: break;
1613: }
1614: }
1615: /* Success */
1616: *argcp = argc;
1617: *argvp = argv;
1618: argc = 0;
1619: argv = NULL;
1620: r = 0;
1621: out:
1622: if (argc != 0 && argv != NULL) {
1623: for (i = 0; i < argc; i++)
1624: free(argv[i]);
1625: free(argv);
1626: }
1627: return r;
1628: }
1629:
1630: /*
1631: * Reassemble an argument vector into a string, quoting and escaping as
1632: * necessary. Caller must free returned string.
1633: */
1634: char *
1635: argv_assemble(int argc, char **argv)
1636: {
1637: int i, j, ws, r;
1638: char c, *ret;
1639: struct sshbuf *buf, *arg;
1640:
1641: if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
1642: fatal("%s: sshbuf_new failed", __func__);
1643:
1644: for (i = 0; i < argc; i++) {
1645: ws = 0;
1646: sshbuf_reset(arg);
1647: for (j = 0; argv[i][j] != '\0'; j++) {
1648: r = 0;
1649: c = argv[i][j];
1650: switch (c) {
1651: case ' ':
1652: case '\t':
1653: ws = 1;
1654: r = sshbuf_put_u8(arg, c);
1655: break;
1656: case '\\':
1657: case '\'':
1658: case '"':
1659: if ((r = sshbuf_put_u8(arg, '\\')) != 0)
1660: break;
1661: /* FALLTHROUGH */
1662: default:
1663: r = sshbuf_put_u8(arg, c);
1664: break;
1665: }
1666: if (r != 0)
1667: fatal("%s: sshbuf_put_u8: %s",
1668: __func__, ssh_err(r));
1669: }
1670: if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
1671: (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
1672: (r = sshbuf_putb(buf, arg)) != 0 ||
1673: (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
1674: fatal("%s: buffer error: %s", __func__, ssh_err(r));
1675: }
1676: if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
1677: fatal("%s: malloc failed", __func__);
1678: memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
1679: ret[sshbuf_len(buf)] = '\0';
1680: sshbuf_free(buf);
1681: sshbuf_free(arg);
1682: return ret;
1683: }
1684:
1685: /* Returns 0 if pid exited cleanly, non-zero otherwise */
1686: int
1687: exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet)
1688: {
1689: int status;
1690:
1691: while (waitpid(pid, &status, 0) == -1) {
1692: if (errno != EINTR) {
1693: error("%s: waitpid: %s", tag, strerror(errno));
1694: return -1;
1695: }
1696: }
1697: if (WIFSIGNALED(status)) {
1698: error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
1699: return -1;
1700: } else if (WEXITSTATUS(status) != 0) {
1701: do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
1702: "%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
1703: return -1;
1704: }
1705: return 0;
1706: }
1707:
1708: /*
1709: * Check a given path for security. This is defined as all components
1710: * of the path to the file must be owned by either the owner of
1711: * of the file or root and no directories must be group or world writable.
1712: *
1713: * XXX Should any specific check be done for sym links ?
1714: *
1715: * Takes a file name, its stat information (preferably from fstat() to
1716: * avoid races), the uid of the expected owner, their home directory and an
1717: * error buffer plus max size as arguments.
1718: *
1719: * Returns 0 on success and -1 on failure
1720: */
1721: int
1722: safe_path(const char *name, struct stat *stp, const char *pw_dir,
1723: uid_t uid, char *err, size_t errlen)
1724: {
1725: char buf[PATH_MAX], homedir[PATH_MAX];
1726: char *cp;
1727: int comparehome = 0;
1728: struct stat st;
1729:
1730: if (realpath(name, buf) == NULL) {
1731: snprintf(err, errlen, "realpath %s failed: %s", name,
1732: strerror(errno));
1733: return -1;
1734: }
1735: if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
1736: comparehome = 1;
1737:
1738: if (!S_ISREG(stp->st_mode)) {
1739: snprintf(err, errlen, "%s is not a regular file", buf);
1740: return -1;
1741: }
1742: if ((stp->st_uid != 0 && stp->st_uid != uid) ||
1743: (stp->st_mode & 022) != 0) {
1744: snprintf(err, errlen, "bad ownership or modes for file %s",
1745: buf);
1746: return -1;
1747: }
1748:
1749: /* for each component of the canonical path, walking upwards */
1750: for (;;) {
1751: if ((cp = dirname(buf)) == NULL) {
1752: snprintf(err, errlen, "dirname() failed");
1753: return -1;
1754: }
1755: strlcpy(buf, cp, sizeof(buf));
1756:
1757: if (stat(buf, &st) < 0 ||
1758: (st.st_uid != 0 && st.st_uid != uid) ||
1759: (st.st_mode & 022) != 0) {
1760: snprintf(err, errlen,
1761: "bad ownership or modes for directory %s", buf);
1762: return -1;
1763: }
1764:
1765: /* If are past the homedir then we can stop */
1766: if (comparehome && strcmp(homedir, buf) == 0)
1767: break;
1768:
1769: /*
1770: * dirname should always complete with a "/" path,
1771: * but we can be paranoid and check for "." too
1772: */
1773: if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
1774: break;
1775: }
1776: return 0;
1777: }
1778:
1779: /*
1780: * Version of safe_path() that accepts an open file descriptor to
1781: * avoid races.
1782: *
1783: * Returns 0 on success and -1 on failure
1784: */
1785: int
1786: safe_path_fd(int fd, const char *file, struct passwd *pw,
1787: char *err, size_t errlen)
1788: {
1789: struct stat st;
1790:
1791: /* check the open file to avoid races */
1792: if (fstat(fd, &st) < 0) {
1793: snprintf(err, errlen, "cannot stat file %s: %s",
1794: file, strerror(errno));
1795: return -1;
1796: }
1797: return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
1798: }
1799:
1800: /*
1801: * Sets the value of the given variable in the environment. If the variable
1802: * already exists, its value is overridden.
1803: */
1804: void
1805: child_set_env(char ***envp, u_int *envsizep, const char *name,
1806: const char *value)
1807: {
1808: char **env;
1809: u_int envsize;
1810: u_int i, namelen;
1811:
1812: if (strchr(name, '=') != NULL) {
1813: error("Invalid environment variable \"%.100s\"", name);
1814: return;
1815: }
1816:
1817: /*
1818: * Find the slot where the value should be stored. If the variable
1819: * already exists, we reuse the slot; otherwise we append a new slot
1820: * at the end of the array, expanding if necessary.
1821: */
1822: env = *envp;
1823: namelen = strlen(name);
1824: for (i = 0; env[i]; i++)
1825: if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
1826: break;
1827: if (env[i]) {
1828: /* Reuse the slot. */
1829: free(env[i]);
1830: } else {
1831: /* New variable. Expand if necessary. */
1832: envsize = *envsizep;
1833: if (i >= envsize - 1) {
1834: if (envsize >= 1000)
1835: fatal("child_set_env: too many env vars");
1836: envsize += 50;
1837: env = (*envp) = xreallocarray(env, envsize, sizeof(char *));
1838: *envsizep = envsize;
1839: }
1840: /* Need to set the NULL pointer at end of array beyond the new slot. */
1841: env[i + 1] = NULL;
1842: }
1843:
1844: /* Allocate space and format the variable in the appropriate slot. */
1.16.2.1 pgoyette 1845: /* XXX xasprintf */
1.16 christos 1846: env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
1847: snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
1848: }
1849:
1.16.2.1 pgoyette 1850: /*
1851: * Check and optionally lowercase a domain name, also removes trailing '.'
1852: * Returns 1 on success and 0 on failure, storing an error message in errstr.
1853: */
1854: int
1855: valid_domain(char *name, int makelower, const char **errstr)
1856: {
1857: size_t i, l = strlen(name);
1858: u_char c, last = '\0';
1859: static char errbuf[256];
1860:
1861: if (l == 0) {
1862: strlcpy(errbuf, "empty domain name", sizeof(errbuf));
1863: goto bad;
1864: }
1865: if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0])) {
1866: snprintf(errbuf, sizeof(errbuf), "domain name \"%.100s\" "
1867: "starts with invalid character", name);
1868: goto bad;
1869: }
1870: for (i = 0; i < l; i++) {
1871: c = tolower((u_char)name[i]);
1872: if (makelower)
1873: name[i] = (char)c;
1874: if (last == '.' && c == '.') {
1875: snprintf(errbuf, sizeof(errbuf), "domain name "
1876: "\"%.100s\" contains consecutive separators", name);
1877: goto bad;
1878: }
1879: if (c != '.' && c != '-' && !isalnum(c) &&
1880: c != '_') /* technically invalid, but common */ {
1881: snprintf(errbuf, sizeof(errbuf), "domain name "
1882: "\"%.100s\" contains invalid characters", name);
1883: goto bad;
1884: }
1885: last = c;
1886: }
1887: if (name[l - 1] == '.')
1888: name[l - 1] = '\0';
1889: if (errstr != NULL)
1890: *errstr = NULL;
1891: return 1;
1892: bad:
1893: if (errstr != NULL)
1894: *errstr = errbuf;
1895: return 0;
1896: }
1897:
1898: const char *
1899: atoi_err(const char *nptr, int *val)
1900: {
1901: const char *errstr = NULL;
1902: long long num;
1903:
1904: if (nptr == NULL || *nptr == '\0')
1905: return "missing";
1906: num = strtonum(nptr, 0, INT_MAX, &errstr);
1907: if (errstr == NULL)
1908: *val = (int)num;
1909: return errstr;
1910: }
1911:
1912: int
1913: parse_absolute_time(const char *s, uint64_t *tp)
1914: {
1915: struct tm tm;
1916: time_t tt;
1917: char buf[32];
1918: const char *fmt;
1919:
1920: *tp = 0;
1921:
1922: /*
1923: * POSIX strptime says "The application shall ensure that there
1924: * is white-space or other non-alphanumeric characters between
1925: * any two conversion specifications" so arrange things this way.
1926: */
1927: switch (strlen(s)) {
1928: case 8: /* YYYYMMDD */
1929: fmt = "%Y-%m-%d";
1930: snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6);
1931: break;
1932: case 12: /* YYYYMMDDHHMM */
1933: fmt = "%Y-%m-%dT%H:%M";
1934: snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s",
1935: s, s + 4, s + 6, s + 8, s + 10);
1936: break;
1937: case 14: /* YYYYMMDDHHMMSS */
1938: fmt = "%Y-%m-%dT%H:%M:%S";
1939: snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s",
1940: s, s + 4, s + 6, s + 8, s + 10, s + 12);
1941: break;
1942: default:
1943: return SSH_ERR_INVALID_FORMAT;
1944: }
1945:
1946: memset(&tm, 0, sizeof(tm));
1947: if (strptime(buf, fmt, &tm) == NULL)
1948: return SSH_ERR_INVALID_FORMAT;
1949: if ((tt = mktime(&tm)) < 0)
1950: return SSH_ERR_INVALID_FORMAT;
1951: /* success */
1952: *tp = (uint64_t)tt;
1953: return 0;
1954: }
1955:
1956: void
1957: format_absolute_time(uint64_t t, char *buf, size_t len)
1958: {
1959: time_t tt = t > INT_MAX ? INT_MAX : t; /* XXX revisit in 2038 :P */
1960: struct tm tm;
1961:
1962: localtime_r(&tt, &tm);
1963: strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
1964: }
CVSweb <webmaster@jp.NetBSD.org>