Annotation of src/usr.bin/ssh/misc.c, Revision 1.86
1.86 ! djm 1: /* $OpenBSD: misc.c,v 1.85 2011/03/29 18:54:17 stevesk Exp $ */
1.1 markus 2: /*
3: * Copyright (c) 2000 Markus Friedl. All rights reserved.
1.52 djm 4: * Copyright (c) 2005,2006 Damien Miller. All rights reserved.
1.1 markus 5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
1.64 deraadt 27: #include <sys/types.h>
1.45 stevesk 28: #include <sys/ioctl.h>
1.53 stevesk 29: #include <sys/socket.h>
1.61 stevesk 30: #include <sys/param.h>
1.38 stevesk 31:
32: #include <net/if.h>
1.53 stevesk 33: #include <netinet/in.h>
1.83 djm 34: #include <netinet/in_systm.h>
35: #include <netinet/ip.h>
1.44 stevesk 36: #include <netinet/tcp.h>
1.43 stevesk 37:
1.58 stevesk 38: #include <errno.h>
1.55 stevesk 39: #include <fcntl.h>
1.66 dtucker 40: #include <netdb.h>
1.43 stevesk 41: #include <paths.h>
1.54 stevesk 42: #include <pwd.h>
1.57 stevesk 43: #include <stdarg.h>
1.63 stevesk 44: #include <stdio.h>
1.62 stevesk 45: #include <stdlib.h>
1.60 stevesk 46: #include <string.h>
1.59 stevesk 47: #include <unistd.h>
1.1 markus 48:
1.64 deraadt 49: #include "xmalloc.h"
1.1 markus 50: #include "misc.h"
51: #include "log.h"
1.56 dtucker 52: #include "ssh.h"
1.1 markus 53:
1.12 markus 54: /* remove newline at end of string */
1.1 markus 55: char *
56: chop(char *s)
57: {
58: char *t = s;
59: while (*t) {
1.13 deraadt 60: if (*t == '\n' || *t == '\r') {
1.1 markus 61: *t = '\0';
62: return s;
63: }
64: t++;
65: }
66: return s;
67:
68: }
69:
1.12 markus 70: /* set/unset filedescriptor to non-blocking */
1.24 djm 71: int
1.1 markus 72: set_nonblock(int fd)
73: {
74: int val;
1.8 markus 75:
1.1 markus 76: val = fcntl(fd, F_GETFL, 0);
77: if (val < 0) {
78: error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
1.24 djm 79: return (-1);
1.1 markus 80: }
81: if (val & O_NONBLOCK) {
1.24 djm 82: debug3("fd %d is O_NONBLOCK", fd);
83: return (0);
1.1 markus 84: }
1.21 markus 85: debug2("fd %d setting O_NONBLOCK", fd);
1.1 markus 86: val |= O_NONBLOCK;
1.24 djm 87: if (fcntl(fd, F_SETFL, val) == -1) {
88: debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
89: strerror(errno));
90: return (-1);
91: }
92: return (0);
1.8 markus 93: }
94:
1.24 djm 95: int
1.8 markus 96: unset_nonblock(int fd)
97: {
98: int val;
99:
100: val = fcntl(fd, F_GETFL, 0);
101: if (val < 0) {
102: error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
1.24 djm 103: return (-1);
1.8 markus 104: }
105: if (!(val & O_NONBLOCK)) {
1.24 djm 106: debug3("fd %d is not O_NONBLOCK", fd);
107: return (0);
1.8 markus 108: }
1.10 markus 109: debug("fd %d clearing O_NONBLOCK", fd);
1.8 markus 110: val &= ~O_NONBLOCK;
1.24 djm 111: if (fcntl(fd, F_SETFL, val) == -1) {
112: debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
1.18 markus 113: fd, strerror(errno));
1.24 djm 114: return (-1);
115: }
116: return (0);
1.66 dtucker 117: }
118:
119: const char *
120: ssh_gai_strerror(int gaierr)
121: {
1.67 dtucker 122: if (gaierr == EAI_SYSTEM)
123: return strerror(errno);
124: return gai_strerror(gaierr);
1.15 stevesk 125: }
126:
127: /* disable nagle on socket */
128: void
129: set_nodelay(int fd)
130: {
1.17 stevesk 131: int opt;
132: socklen_t optlen;
1.15 stevesk 133:
1.16 stevesk 134: optlen = sizeof opt;
135: if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
1.23 markus 136: debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
1.16 stevesk 137: return;
138: }
139: if (opt == 1) {
140: debug2("fd %d is TCP_NODELAY", fd);
141: return;
142: }
143: opt = 1;
1.20 markus 144: debug2("fd %d setting TCP_NODELAY", fd);
1.16 stevesk 145: if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
1.15 stevesk 146: error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
1.72 reyk 147: }
148:
1.1 markus 149: /* Characters considered whitespace in strsep calls. */
150: #define WHITESPACE " \t\r\n"
1.46 dtucker 151: #define QUOTE "\""
1.1 markus 152:
1.12 markus 153: /* return next token in configuration line */
1.1 markus 154: char *
155: strdelim(char **s)
156: {
157: char *old;
158: int wspace = 0;
159:
160: if (*s == NULL)
161: return NULL;
162:
163: old = *s;
164:
1.46 dtucker 165: *s = strpbrk(*s, WHITESPACE QUOTE "=");
1.1 markus 166: if (*s == NULL)
167: return (old);
168:
1.46 dtucker 169: if (*s[0] == '\"') {
170: memmove(*s, *s + 1, strlen(*s)); /* move nul too */
171: /* Find matching quote */
172: if ((*s = strpbrk(*s, QUOTE)) == NULL) {
173: return (NULL); /* no matching quote */
174: } else {
175: *s[0] = '\0';
1.77 djm 176: *s += strspn(*s + 1, WHITESPACE) + 1;
1.46 dtucker 177: return (old);
178: }
179: }
180:
1.1 markus 181: /* Allow only one '=' to be skipped */
182: if (*s[0] == '=')
183: wspace = 1;
184: *s[0] = '\0';
185:
1.46 dtucker 186: /* Skip any extra whitespace after first token */
1.1 markus 187: *s += strspn(*s + 1, WHITESPACE) + 1;
188: if (*s[0] == '=' && !wspace)
189: *s += strspn(*s + 1, WHITESPACE) + 1;
190:
191: return (old);
1.2 markus 192: }
193:
194: struct passwd *
195: pwcopy(struct passwd *pw)
196: {
1.49 djm 197: struct passwd *copy = xcalloc(1, sizeof(*copy));
1.4 deraadt 198:
1.2 markus 199: copy->pw_name = xstrdup(pw->pw_name);
200: copy->pw_passwd = xstrdup(pw->pw_passwd);
1.4 deraadt 201: copy->pw_gecos = xstrdup(pw->pw_gecos);
1.2 markus 202: copy->pw_uid = pw->pw_uid;
203: copy->pw_gid = pw->pw_gid;
1.11 markus 204: copy->pw_expire = pw->pw_expire;
205: copy->pw_change = pw->pw_change;
1.2 markus 206: copy->pw_class = xstrdup(pw->pw_class);
207: copy->pw_dir = xstrdup(pw->pw_dir);
208: copy->pw_shell = xstrdup(pw->pw_shell);
209: return copy;
1.5 stevesk 210: }
211:
1.12 markus 212: /*
213: * Convert ASCII string to TCP/IP port number.
1.70 djm 214: * Port must be >=0 and <=65535.
215: * Return -1 if invalid.
1.12 markus 216: */
217: int
218: a2port(const char *s)
1.5 stevesk 219: {
1.70 djm 220: long long port;
221: const char *errstr;
1.5 stevesk 222:
1.70 djm 223: port = strtonum(s, 0, 65535, &errstr);
224: if (errstr != NULL)
225: return -1;
226: return (int)port;
1.9 stevesk 227: }
228:
1.36 reyk 229: int
230: a2tun(const char *s, int *remote)
231: {
232: const char *errstr = NULL;
233: char *sp, *ep;
234: int tun;
235:
236: if (remote != NULL) {
1.37 reyk 237: *remote = SSH_TUNID_ANY;
1.36 reyk 238: sp = xstrdup(s);
239: if ((ep = strchr(sp, ':')) == NULL) {
240: xfree(sp);
241: return (a2tun(s, NULL));
242: }
243: ep[0] = '\0'; ep++;
244: *remote = a2tun(ep, NULL);
245: tun = a2tun(sp, NULL);
246: xfree(sp);
1.37 reyk 247: return (*remote == SSH_TUNID_ERR ? *remote : tun);
1.36 reyk 248: }
249:
250: if (strcasecmp(s, "any") == 0)
1.37 reyk 251: return (SSH_TUNID_ANY);
1.36 reyk 252:
1.37 reyk 253: tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
254: if (errstr != NULL)
255: return (SSH_TUNID_ERR);
1.36 reyk 256:
257: return (tun);
258: }
259:
1.9 stevesk 260: #define SECONDS 1
261: #define MINUTES (SECONDS * 60)
262: #define HOURS (MINUTES * 60)
263: #define DAYS (HOURS * 24)
264: #define WEEKS (DAYS * 7)
265:
1.12 markus 266: /*
267: * Convert a time string into seconds; format is
268: * a sequence of:
269: * time[qualifier]
270: *
271: * Valid time qualifiers are:
272: * <none> seconds
273: * s|S seconds
274: * m|M minutes
275: * h|H hours
276: * d|D days
277: * w|W weeks
278: *
279: * Examples:
280: * 90m 90 minutes
281: * 1h30m 90 minutes
282: * 2d 2 days
283: * 1w 1 week
284: *
285: * Return -1 if time string is invalid.
286: */
287: long
288: convtime(const char *s)
1.9 stevesk 289: {
290: long total, secs;
291: const char *p;
292: char *endp;
293:
294: errno = 0;
295: total = 0;
296: p = s;
297:
298: if (p == NULL || *p == '\0')
299: return -1;
300:
301: while (*p) {
302: secs = strtol(p, &endp, 10);
303: if (p == endp ||
304: (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
305: secs < 0)
306: return -1;
307:
308: switch (*endp++) {
309: case '\0':
310: endp--;
1.48 deraadt 311: break;
1.9 stevesk 312: case 's':
313: case 'S':
314: break;
315: case 'm':
316: case 'M':
317: secs *= MINUTES;
318: break;
319: case 'h':
320: case 'H':
321: secs *= HOURS;
322: break;
323: case 'd':
324: case 'D':
325: secs *= DAYS;
326: break;
327: case 'w':
328: case 'W':
329: secs *= WEEKS;
330: break;
331: default:
332: return -1;
333: }
334: total += secs;
335: if (total < 0)
336: return -1;
337: p = endp;
338: }
339:
340: return total;
1.56 dtucker 341: }
342:
343: /*
344: * Returns a standardized host+port identifier string.
345: * Caller must free returned string.
346: */
347: char *
348: put_host_port(const char *host, u_short port)
349: {
350: char *hoststr;
351:
352: if (port == 0 || port == SSH_DEFAULT_PORT)
353: return(xstrdup(host));
354: if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
355: fatal("put_host_port: asprintf: %s", strerror(errno));
356: debug3("put_host_port: %s", hoststr);
357: return hoststr;
1.28 djm 358: }
359:
360: /*
361: * Search for next delimiter between hostnames/addresses and ports.
362: * Argument may be modified (for termination).
363: * Returns *cp if parsing succeeds.
364: * *cp is set to the start of the next delimiter, if one was found.
365: * If this is the last field, *cp is set to NULL.
366: */
367: char *
368: hpdelim(char **cp)
369: {
370: char *s, *old;
371:
372: if (cp == NULL || *cp == NULL)
373: return NULL;
374:
375: old = s = *cp;
376: if (*s == '[') {
377: if ((s = strchr(s, ']')) == NULL)
378: return NULL;
379: else
380: s++;
381: } else if ((s = strpbrk(s, ":/")) == NULL)
382: s = *cp + strlen(*cp); /* skip to end (see first case below) */
383:
384: switch (*s) {
385: case '\0':
386: *cp = NULL; /* no more fields*/
387: break;
1.29 deraadt 388:
1.28 djm 389: case ':':
390: case '/':
391: *s = '\0'; /* terminate */
392: *cp = s + 1;
393: break;
1.29 deraadt 394:
1.28 djm 395: default:
396: return NULL;
397: }
398:
399: return old;
1.6 mouring 400: }
401:
402: char *
403: cleanhostname(char *host)
404: {
405: if (*host == '[' && host[strlen(host) - 1] == ']') {
406: host[strlen(host) - 1] = '\0';
407: return (host + 1);
408: } else
409: return host;
410: }
411:
412: char *
413: colon(char *cp)
414: {
415: int flag = 0;
416:
417: if (*cp == ':') /* Leading colon is part of file name. */
1.76 djm 418: return NULL;
1.6 mouring 419: if (*cp == '[')
420: flag = 1;
421:
422: for (; *cp; ++cp) {
423: if (*cp == '@' && *(cp+1) == '[')
424: flag = 1;
425: if (*cp == ']' && *(cp+1) == ':' && flag)
426: return (cp+1);
427: if (*cp == ':' && !flag)
428: return (cp);
429: if (*cp == '/')
1.76 djm 430: return NULL;
1.6 mouring 431: }
1.76 djm 432: return NULL;
1.7 mouring 433: }
434:
1.12 markus 435: /* function to assist building execv() arguments */
1.7 mouring 436: void
437: addargs(arglist *args, char *fmt, ...)
438: {
439: va_list ap;
1.42 djm 440: char *cp;
1.25 avsm 441: u_int nalloc;
1.42 djm 442: int r;
1.7 mouring 443:
444: va_start(ap, fmt);
1.42 djm 445: r = vasprintf(&cp, fmt, ap);
1.7 mouring 446: va_end(ap);
1.42 djm 447: if (r == -1)
448: fatal("addargs: argument too long");
1.7 mouring 449:
1.22 markus 450: nalloc = args->nalloc;
1.7 mouring 451: if (args->list == NULL) {
1.22 markus 452: nalloc = 32;
1.7 mouring 453: args->num = 0;
1.22 markus 454: } else if (args->num+2 >= nalloc)
455: nalloc *= 2;
1.7 mouring 456:
1.50 djm 457: args->list = xrealloc(args->list, nalloc, sizeof(char *));
1.22 markus 458: args->nalloc = nalloc;
1.42 djm 459: args->list[args->num++] = cp;
1.7 mouring 460: args->list[args->num] = NULL;
1.42 djm 461: }
462:
463: void
464: replacearg(arglist *args, u_int which, char *fmt, ...)
465: {
466: va_list ap;
467: char *cp;
468: int r;
469:
470: va_start(ap, fmt);
471: r = vasprintf(&cp, fmt, ap);
472: va_end(ap);
473: if (r == -1)
474: fatal("replacearg: argument too long");
475:
476: if (which >= args->num)
477: fatal("replacearg: tried to replace invalid arg %d >= %d",
478: which, args->num);
479: xfree(args->list[which]);
480: args->list[which] = cp;
481: }
482:
483: void
484: freeargs(arglist *args)
485: {
486: u_int i;
487:
488: if (args->list != NULL) {
489: for (i = 0; i < args->num; i++)
490: xfree(args->list[i]);
491: xfree(args->list);
492: args->nalloc = args->num = 0;
493: args->list = NULL;
494: }
1.30 djm 495: }
496:
497: /*
498: * Expands tildes in the file name. Returns data allocated by xmalloc.
499: * Warning: this calls getpw*.
500: */
501: char *
502: tilde_expand_filename(const char *filename, uid_t uid)
503: {
504: const char *path;
505: char user[128], ret[MAXPATHLEN];
506: struct passwd *pw;
1.32 djm 507: u_int len, slash;
1.30 djm 508:
509: if (*filename != '~')
510: return (xstrdup(filename));
511: filename++;
512:
513: path = strchr(filename, '/');
514: if (path != NULL && path > filename) { /* ~user/path */
1.32 djm 515: slash = path - filename;
516: if (slash > sizeof(user) - 1)
1.30 djm 517: fatal("tilde_expand_filename: ~username too long");
1.32 djm 518: memcpy(user, filename, slash);
519: user[slash] = '\0';
1.30 djm 520: if ((pw = getpwnam(user)) == NULL)
521: fatal("tilde_expand_filename: No such user %s", user);
522: } else if ((pw = getpwuid(uid)) == NULL) /* ~/path */
1.69 dtucker 523: fatal("tilde_expand_filename: No such uid %ld", (long)uid);
1.30 djm 524:
525: if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret))
526: fatal("tilde_expand_filename: Path too long");
527:
528: /* Make sure directory has a trailing '/' */
529: len = strlen(pw->pw_dir);
530: if ((len == 0 || pw->pw_dir[len - 1] != '/') &&
531: strlcat(ret, "/", sizeof(ret)) >= sizeof(ret))
532: fatal("tilde_expand_filename: Path too long");
533:
534: /* Skip leading '/' from specified path */
535: if (path != NULL)
536: filename = path + 1;
537: if (strlcat(ret, filename, sizeof(ret)) >= sizeof(ret))
538: fatal("tilde_expand_filename: Path too long");
539:
540: return (xstrdup(ret));
1.31 djm 541: }
542:
543: /*
544: * Expand a string with a set of %[char] escapes. A number of escapes may be
545: * specified as (char *escape_chars, char *replacement) pairs. The list must
1.34 dtucker 546: * be terminated by a NULL escape_char. Returns replaced string in memory
1.31 djm 547: * allocated by xmalloc.
548: */
549: char *
550: percent_expand(const char *string, ...)
551: {
552: #define EXPAND_MAX_KEYS 16
1.73 djm 553: u_int num_keys, i, j;
1.31 djm 554: struct {
555: const char *key;
556: const char *repl;
557: } keys[EXPAND_MAX_KEYS];
558: char buf[4096];
559: va_list ap;
560:
561: /* Gather keys */
562: va_start(ap, string);
563: for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
564: keys[num_keys].key = va_arg(ap, char *);
565: if (keys[num_keys].key == NULL)
566: break;
567: keys[num_keys].repl = va_arg(ap, char *);
568: if (keys[num_keys].repl == NULL)
1.73 djm 569: fatal("%s: NULL replacement", __func__);
1.31 djm 570: }
1.73 djm 571: if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
572: fatal("%s: too many keys", __func__);
1.31 djm 573: va_end(ap);
574:
575: /* Expand string */
576: *buf = '\0';
577: for (i = 0; *string != '\0'; string++) {
578: if (*string != '%') {
579: append:
580: buf[i++] = *string;
581: if (i >= sizeof(buf))
1.73 djm 582: fatal("%s: string too long", __func__);
1.31 djm 583: buf[i] = '\0';
584: continue;
585: }
586: string++;
1.73 djm 587: /* %% case */
1.31 djm 588: if (*string == '%')
589: goto append;
590: for (j = 0; j < num_keys; j++) {
591: if (strchr(keys[j].key, *string) != NULL) {
592: i = strlcat(buf, keys[j].repl, sizeof(buf));
593: if (i >= sizeof(buf))
1.73 djm 594: fatal("%s: string too long", __func__);
1.31 djm 595: break;
596: }
597: }
598: if (j >= num_keys)
1.73 djm 599: fatal("%s: unknown key %%%c", __func__, *string);
1.31 djm 600: }
601: return (xstrdup(buf));
602: #undef EXPAND_MAX_KEYS
1.26 dtucker 603: }
604:
605: /*
606: * Read an entire line from a public key file into a static buffer, discarding
607: * lines that exceed the buffer size. Returns 0 on success, -1 on failure.
608: */
609: int
610: read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
1.27 dtucker 611: u_long *lineno)
1.26 dtucker 612: {
613: while (fgets(buf, bufsz, f) != NULL) {
1.65 ray 614: if (buf[0] == '\0')
615: continue;
1.26 dtucker 616: (*lineno)++;
617: if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
618: return 0;
619: } else {
1.27 dtucker 620: debug("%s: %s line %lu exceeds size limit", __func__,
621: filename, *lineno);
1.26 dtucker 622: /* discard remainder of line */
1.29 deraadt 623: while (fgetc(f) != '\n' && !feof(f))
1.26 dtucker 624: ; /* nothing */
625: }
626: }
627: return -1;
1.36 reyk 628: }
629:
630: int
1.37 reyk 631: tun_open(int tun, int mode)
1.36 reyk 632: {
1.37 reyk 633: struct ifreq ifr;
1.36 reyk 634: char name[100];
1.37 reyk 635: int fd = -1, sock;
1.36 reyk 636:
1.37 reyk 637: /* Open the tunnel device */
638: if (tun <= SSH_TUNID_MAX) {
1.36 reyk 639: snprintf(name, sizeof(name), "/dev/tun%d", tun);
1.37 reyk 640: fd = open(name, O_RDWR);
641: } else if (tun == SSH_TUNID_ANY) {
642: for (tun = 100; tun >= 0; tun--) {
643: snprintf(name, sizeof(name), "/dev/tun%d", tun);
644: if ((fd = open(name, O_RDWR)) >= 0)
645: break;
1.36 reyk 646: }
647: } else {
1.39 stevesk 648: debug("%s: invalid tunnel %u", __func__, tun);
1.37 reyk 649: return (-1);
650: }
651:
652: if (fd < 0) {
653: debug("%s: %s open failed: %s", __func__, name, strerror(errno));
654: return (-1);
1.36 reyk 655: }
1.37 reyk 656:
657: debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
658:
659: /* Set the tunnel device operation mode */
660: snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun);
661: if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
662: goto failed;
663:
664: if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
665: goto failed;
1.40 reyk 666:
667: /* Set interface mode */
668: ifr.ifr_flags &= ~IFF_UP;
669: if (mode == SSH_TUNMODE_ETHERNET)
1.37 reyk 670: ifr.ifr_flags |= IFF_LINK0;
1.40 reyk 671: else
672: ifr.ifr_flags &= ~IFF_LINK0;
673: if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
674: goto failed;
675:
676: /* Bring interface up */
1.37 reyk 677: ifr.ifr_flags |= IFF_UP;
678: if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
679: goto failed;
680:
681: close(sock);
682: return (fd);
683:
684: failed:
685: if (fd >= 0)
686: close(fd);
687: if (sock >= 0)
688: close(sock);
689: debug("%s: failed to set %s mode %d: %s", __func__, name,
690: mode, strerror(errno));
1.36 reyk 691: return (-1);
1.35 djm 692: }
693:
694: void
695: sanitise_stdfd(void)
696: {
1.41 djm 697: int nullfd, dupfd;
1.35 djm 698:
1.41 djm 699: if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
1.71 tobias 700: fprintf(stderr, "Couldn't open /dev/null: %s\n",
701: strerror(errno));
1.35 djm 702: exit(1);
703: }
1.41 djm 704: while (++dupfd <= 2) {
705: /* Only clobber closed fds */
706: if (fcntl(dupfd, F_GETFL, 0) >= 0)
707: continue;
708: if (dup2(nullfd, dupfd) == -1) {
1.71 tobias 709: fprintf(stderr, "dup2: %s\n", strerror(errno));
1.35 djm 710: exit(1);
711: }
712: }
713: if (nullfd > 2)
714: close(nullfd);
1.1 markus 715: }
1.33 djm 716:
717: char *
1.52 djm 718: tohex(const void *vp, size_t l)
1.33 djm 719: {
1.52 djm 720: const u_char *p = (const u_char *)vp;
1.33 djm 721: char b[3], *r;
1.52 djm 722: size_t i, hl;
723:
724: if (l > 65536)
725: return xstrdup("tohex: length > 65536");
1.33 djm 726:
727: hl = l * 2 + 1;
1.49 djm 728: r = xcalloc(1, hl);
1.33 djm 729: for (i = 0; i < l; i++) {
1.52 djm 730: snprintf(b, sizeof(b), "%02x", p[i]);
1.33 djm 731: strlcat(r, b, hl);
732: }
733: return (r);
734: }
735:
1.52 djm 736: u_int64_t
737: get_u64(const void *vp)
738: {
739: const u_char *p = (const u_char *)vp;
740: u_int64_t v;
741:
742: v = (u_int64_t)p[0] << 56;
743: v |= (u_int64_t)p[1] << 48;
744: v |= (u_int64_t)p[2] << 40;
745: v |= (u_int64_t)p[3] << 32;
746: v |= (u_int64_t)p[4] << 24;
747: v |= (u_int64_t)p[5] << 16;
748: v |= (u_int64_t)p[6] << 8;
749: v |= (u_int64_t)p[7];
750:
751: return (v);
752: }
753:
754: u_int32_t
755: get_u32(const void *vp)
756: {
757: const u_char *p = (const u_char *)vp;
758: u_int32_t v;
759:
760: v = (u_int32_t)p[0] << 24;
761: v |= (u_int32_t)p[1] << 16;
762: v |= (u_int32_t)p[2] << 8;
763: v |= (u_int32_t)p[3];
764:
765: return (v);
766: }
767:
768: u_int16_t
769: get_u16(const void *vp)
770: {
771: const u_char *p = (const u_char *)vp;
772: u_int16_t v;
773:
774: v = (u_int16_t)p[0] << 8;
775: v |= (u_int16_t)p[1];
776:
777: return (v);
778: }
779:
780: void
781: put_u64(void *vp, u_int64_t v)
782: {
783: u_char *p = (u_char *)vp;
784:
785: p[0] = (u_char)(v >> 56) & 0xff;
786: p[1] = (u_char)(v >> 48) & 0xff;
787: p[2] = (u_char)(v >> 40) & 0xff;
788: p[3] = (u_char)(v >> 32) & 0xff;
789: p[4] = (u_char)(v >> 24) & 0xff;
790: p[5] = (u_char)(v >> 16) & 0xff;
791: p[6] = (u_char)(v >> 8) & 0xff;
792: p[7] = (u_char)v & 0xff;
793: }
794:
795: void
796: put_u32(void *vp, u_int32_t v)
797: {
798: u_char *p = (u_char *)vp;
799:
800: p[0] = (u_char)(v >> 24) & 0xff;
801: p[1] = (u_char)(v >> 16) & 0xff;
802: p[2] = (u_char)(v >> 8) & 0xff;
803: p[3] = (u_char)v & 0xff;
804: }
805:
806:
807: void
808: put_u16(void *vp, u_int16_t v)
809: {
810: u_char *p = (u_char *)vp;
811:
812: p[0] = (u_char)(v >> 8) & 0xff;
813: p[1] = (u_char)v & 0xff;
814: }
1.68 dtucker 815:
816: void
817: ms_subtract_diff(struct timeval *start, int *ms)
818: {
819: struct timeval diff, finish;
820:
821: gettimeofday(&finish, NULL);
822: timersub(&finish, start, &diff);
823: *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
824: }
825:
826: void
827: ms_to_timeval(struct timeval *tv, int ms)
828: {
829: if (ms < 0)
830: ms = 0;
831: tv->tv_sec = ms / 1000;
832: tv->tv_usec = (ms % 1000) * 1000;
1.81 djm 833: }
834:
835: void
836: bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
837: {
838: bw->buflen = buflen;
839: bw->rate = kbps;
840: bw->thresh = bw->rate;
841: bw->lamt = 0;
842: timerclear(&bw->bwstart);
843: timerclear(&bw->bwend);
844: }
845:
846: /* Callback from read/write loop to insert bandwidth-limiting delays */
847: void
848: bandwidth_limit(struct bwlimit *bw, size_t read_len)
849: {
850: u_int64_t waitlen;
851: struct timespec ts, rm;
852:
853: if (!timerisset(&bw->bwstart)) {
854: gettimeofday(&bw->bwstart, NULL);
855: return;
856: }
857:
858: bw->lamt += read_len;
859: if (bw->lamt < bw->thresh)
860: return;
861:
862: gettimeofday(&bw->bwend, NULL);
863: timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
864: if (!timerisset(&bw->bwend))
865: return;
866:
867: bw->lamt *= 8;
868: waitlen = (double)1000000L * bw->lamt / bw->rate;
869:
870: bw->bwstart.tv_sec = waitlen / 1000000L;
871: bw->bwstart.tv_usec = waitlen % 1000000L;
872:
873: if (timercmp(&bw->bwstart, &bw->bwend, >)) {
874: timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
875:
876: /* Adjust the wait time */
877: if (bw->bwend.tv_sec) {
878: bw->thresh /= 2;
879: if (bw->thresh < bw->buflen / 4)
880: bw->thresh = bw->buflen / 4;
881: } else if (bw->bwend.tv_usec < 10000) {
882: bw->thresh *= 2;
883: if (bw->thresh > bw->buflen * 8)
884: bw->thresh = bw->buflen * 8;
885: }
886:
887: TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
888: while (nanosleep(&ts, &rm) == -1) {
889: if (errno != EINTR)
890: break;
891: ts = rm;
892: }
893: }
894:
895: bw->lamt = 0;
896: gettimeofday(&bw->bwstart, NULL);
1.84 djm 897: }
898:
899: /* Make a template filename for mk[sd]temp() */
900: void
901: mktemp_proto(char *s, size_t len)
902: {
903: const char *tmpdir;
904: int r;
905:
906: if ((tmpdir = getenv("TMPDIR")) != NULL) {
907: r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
908: if (r > 0 && (size_t)r < len)
909: return;
910: }
911: r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
912: if (r < 0 || (size_t)r >= len)
913: fatal("%s: template string too short", __func__);
1.68 dtucker 914: }
1.83 djm 915:
916: static const struct {
917: const char *name;
918: int value;
919: } ipqos[] = {
920: { "af11", IPTOS_DSCP_AF11 },
921: { "af12", IPTOS_DSCP_AF12 },
922: { "af13", IPTOS_DSCP_AF13 },
1.86 ! djm 923: { "af21", IPTOS_DSCP_AF21 },
1.83 djm 924: { "af22", IPTOS_DSCP_AF22 },
925: { "af23", IPTOS_DSCP_AF23 },
926: { "af31", IPTOS_DSCP_AF31 },
927: { "af32", IPTOS_DSCP_AF32 },
928: { "af33", IPTOS_DSCP_AF33 },
929: { "af41", IPTOS_DSCP_AF41 },
930: { "af42", IPTOS_DSCP_AF42 },
931: { "af43", IPTOS_DSCP_AF43 },
932: { "cs0", IPTOS_DSCP_CS0 },
933: { "cs1", IPTOS_DSCP_CS1 },
934: { "cs2", IPTOS_DSCP_CS2 },
935: { "cs3", IPTOS_DSCP_CS3 },
936: { "cs4", IPTOS_DSCP_CS4 },
937: { "cs5", IPTOS_DSCP_CS5 },
938: { "cs6", IPTOS_DSCP_CS6 },
939: { "cs7", IPTOS_DSCP_CS7 },
940: { "ef", IPTOS_DSCP_EF },
941: { "lowdelay", IPTOS_LOWDELAY },
942: { "throughput", IPTOS_THROUGHPUT },
943: { "reliability", IPTOS_RELIABILITY },
944: { NULL, -1 }
945: };
946:
947: int
948: parse_ipqos(const char *cp)
949: {
950: u_int i;
951: char *ep;
952: long val;
953:
954: if (cp == NULL)
955: return -1;
956: for (i = 0; ipqos[i].name != NULL; i++) {
957: if (strcasecmp(cp, ipqos[i].name) == 0)
958: return ipqos[i].value;
959: }
960: /* Try parsing as an integer */
961: val = strtol(cp, &ep, 0);
962: if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
963: return -1;
964: return val;
965: }
966:
1.85 stevesk 967: const char *
968: iptos2str(int iptos)
969: {
970: int i;
971: static char iptos_str[sizeof "0xff"];
972:
973: for (i = 0; ipqos[i].name != NULL; i++) {
974: if (ipqos[i].value == iptos)
975: return ipqos[i].name;
976: }
977: snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
978: return iptos_str;
979: }