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