blob: b6503abbb26b017e8f084b781f7f7fdcf578e5a4 [file] [log] [blame]
djm@openbsd.org2905d6f2015-10-07 00:54:06 +00001/* $OpenBSD: misc.c,v 1.98 2015/10/07 00:54:06 djm Exp $ */
Damien Millere4340be2000-09-16 13:29:08 +11002/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
Damien Miller3f941882006-03-31 23:13:02 +11004 * Copyright (c) 2005,2006 Damien Miller. All rights reserved.
Damien Millere4340be2000-09-16 13:29:08 +11005 *
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
Damien Miller61c51502000-08-18 14:01:04 +100027#include "includes.h"
Damien Miller17e91c02006-03-15 11:28:34 +110028
Damien Miller9f2abc42006-07-10 20:53:08 +100029#include <sys/types.h>
Damien Millerd7834352006-08-05 12:39:39 +100030#include <sys/ioctl.h>
Damien Miller8ec8c3e2006-07-10 20:35:38 +100031#include <sys/socket.h>
Damien Miller7acefbb2014-07-18 14:11:24 +100032#include <sys/un.h>
Damien Miller8ec8c3e2006-07-10 20:35:38 +100033
deraadt@openbsd.org2ae4f332015-01-16 06:40:12 +000034#include <limits.h>
Darren Tucker5d196262006-07-12 22:15:16 +100035#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100036#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100037#include <stdlib.h>
Damien Millere3476ed2006-07-24 14:13:33 +100038#include <string.h>
Damien Miller1708cb72011-01-13 12:21:34 +110039#include <time.h>
Damien Millere6b3b612006-07-24 14:01:23 +100040#include <unistd.h>
Darren Tucker5d196262006-07-12 22:15:16 +100041
Damien Miller8ec8c3e2006-07-10 20:35:38 +100042#include <netinet/in.h>
Damien Miller0dac6fb2010-11-20 15:19:38 +110043#include <netinet/in_systm.h>
44#include <netinet/ip.h>
Damien Miller3a4051e2006-03-15 11:19:42 +110045#include <netinet/tcp.h>
Damien Miller8ec8c3e2006-07-10 20:35:38 +100046
Damien Millere9fc72e2013-10-15 12:14:12 +110047#include <ctype.h>
Darren Tucker39972492006-07-12 22:22:46 +100048#include <errno.h>
Damien Miller57cf6382006-07-10 21:13:46 +100049#include <fcntl.h>
Darren Tucker4abde772007-12-29 02:43:51 +110050#include <netdb.h>
Damien Miller03e20032006-03-15 11:16:59 +110051#ifdef HAVE_PATHS_H
Damien Millera9263d02006-03-15 11:18:26 +110052# include <paths.h>
Damien Miller9f2abc42006-07-10 20:53:08 +100053#include <pwd.h>
Damien Miller03e20032006-03-15 11:16:59 +110054#endif
Damien Miller3beb8522006-01-02 23:40:10 +110055#ifdef SSH_TUN_OPENBSD
56#include <net/if.h>
57#endif
Damien Miller61c51502000-08-18 14:01:04 +100058
Damien Millerd7834352006-08-05 12:39:39 +100059#include "xmalloc.h"
Kevin Stevesb6e773a2001-02-04 13:20:36 +000060#include "misc.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000061#include "log.h"
Darren Tuckerda345532006-07-10 23:04:19 +100062#include "ssh.h"
Damien Miller61c51502000-08-18 14:01:04 +100063
Ben Lindstrom4cc240d2001-07-04 04:46:56 +000064/* remove newline at end of string */
Damien Miller61c51502000-08-18 14:01:04 +100065char *
66chop(char *s)
67{
68 char *t = s;
69 while (*t) {
Ben Lindstrom1c37c6a2001-12-06 18:00:18 +000070 if (*t == '\n' || *t == '\r') {
Damien Miller61c51502000-08-18 14:01:04 +100071 *t = '\0';
72 return s;
73 }
74 t++;
75 }
76 return s;
77
78}
79
Ben Lindstrom4cc240d2001-07-04 04:46:56 +000080/* set/unset filedescriptor to non-blocking */
Damien Miller232711f2004-06-15 10:35:30 +100081int
Damien Miller61c51502000-08-18 14:01:04 +100082set_nonblock(int fd)
83{
84 int val;
Ben Lindstromc93e84c2001-05-12 00:08:37 +000085
Damien Miller61c51502000-08-18 14:01:04 +100086 val = fcntl(fd, F_GETFL, 0);
87 if (val < 0) {
88 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
Damien Miller232711f2004-06-15 10:35:30 +100089 return (-1);
Damien Miller61c51502000-08-18 14:01:04 +100090 }
Damien Miller69b69aa2000-10-28 14:19:58 +110091 if (val & O_NONBLOCK) {
Damien Miller232711f2004-06-15 10:35:30 +100092 debug3("fd %d is O_NONBLOCK", fd);
93 return (0);
Damien Miller69b69aa2000-10-28 14:19:58 +110094 }
Damien Milleref095ce2003-05-14 13:41:39 +100095 debug2("fd %d setting O_NONBLOCK", fd);
Damien Miller61c51502000-08-18 14:01:04 +100096 val |= O_NONBLOCK;
Damien Miller232711f2004-06-15 10:35:30 +100097 if (fcntl(fd, F_SETFL, val) == -1) {
98 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
99 strerror(errno));
100 return (-1);
101 }
102 return (0);
Damien Miller61c51502000-08-18 14:01:04 +1000103}
104
Damien Miller232711f2004-06-15 10:35:30 +1000105int
Ben Lindstromc93e84c2001-05-12 00:08:37 +0000106unset_nonblock(int fd)
107{
108 int val;
109
110 val = fcntl(fd, F_GETFL, 0);
111 if (val < 0) {
112 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
Damien Miller232711f2004-06-15 10:35:30 +1000113 return (-1);
Ben Lindstromc93e84c2001-05-12 00:08:37 +0000114 }
115 if (!(val & O_NONBLOCK)) {
Damien Miller232711f2004-06-15 10:35:30 +1000116 debug3("fd %d is not O_NONBLOCK", fd);
117 return (0);
Ben Lindstromc93e84c2001-05-12 00:08:37 +0000118 }
Ben Lindstrom352b1c22001-06-21 03:04:37 +0000119 debug("fd %d clearing O_NONBLOCK", fd);
Ben Lindstromc93e84c2001-05-12 00:08:37 +0000120 val &= ~O_NONBLOCK;
Damien Miller232711f2004-06-15 10:35:30 +1000121 if (fcntl(fd, F_SETFL, val) == -1) {
122 debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
Ben Lindstrom84fcb312002-03-05 01:48:09 +0000123 fd, strerror(errno));
Damien Miller232711f2004-06-15 10:35:30 +1000124 return (-1);
125 }
126 return (0);
Ben Lindstromc93e84c2001-05-12 00:08:37 +0000127}
128
Darren Tucker4abde772007-12-29 02:43:51 +1100129const char *
130ssh_gai_strerror(int gaierr)
131{
Damien Miller7313fc92013-07-18 16:13:19 +1000132 if (gaierr == EAI_SYSTEM && errno != 0)
Darren Tucker912428c2008-01-01 20:33:35 +1100133 return strerror(errno);
134 return gai_strerror(gaierr);
Darren Tucker4abde772007-12-29 02:43:51 +1100135}
136
Damien Miller398e1cf2002-02-05 11:52:13 +1100137/* disable nagle on socket */
138void
139set_nodelay(int fd)
140{
Ben Lindstrome86de512002-03-05 01:28:14 +0000141 int opt;
142 socklen_t optlen;
Damien Miller398e1cf2002-02-05 11:52:13 +1100143
Ben Lindstrom1ebd7a52002-02-26 18:12:51 +0000144 optlen = sizeof opt;
145 if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
Darren Tucker6db8f932003-11-03 20:07:14 +1100146 debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
Ben Lindstrom1ebd7a52002-02-26 18:12:51 +0000147 return;
148 }
149 if (opt == 1) {
150 debug2("fd %d is TCP_NODELAY", fd);
151 return;
152 }
153 opt = 1;
Ben Lindstrom1d568f92002-12-23 02:44:36 +0000154 debug2("fd %d setting TCP_NODELAY", fd);
Ben Lindstrom1ebd7a52002-02-26 18:12:51 +0000155 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
Damien Miller398e1cf2002-02-05 11:52:13 +1100156 error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
157}
158
Damien Miller61c51502000-08-18 14:01:04 +1000159/* Characters considered whitespace in strsep calls. */
160#define WHITESPACE " \t\r\n"
Damien Miller306d1182006-03-15 12:05:59 +1100161#define QUOTE "\""
Damien Miller61c51502000-08-18 14:01:04 +1000162
Ben Lindstrom4cc240d2001-07-04 04:46:56 +0000163/* return next token in configuration line */
Damien Miller61c51502000-08-18 14:01:04 +1000164char *
165strdelim(char **s)
166{
167 char *old;
168 int wspace = 0;
169
170 if (*s == NULL)
171 return NULL;
172
173 old = *s;
174
Damien Miller306d1182006-03-15 12:05:59 +1100175 *s = strpbrk(*s, WHITESPACE QUOTE "=");
Damien Miller61c51502000-08-18 14:01:04 +1000176 if (*s == NULL)
177 return (old);
178
Damien Miller306d1182006-03-15 12:05:59 +1100179 if (*s[0] == '\"') {
180 memmove(*s, *s + 1, strlen(*s)); /* move nul too */
181 /* Find matching quote */
182 if ((*s = strpbrk(*s, QUOTE)) == NULL) {
183 return (NULL); /* no matching quote */
184 } else {
185 *s[0] = '\0';
Damien Miller9308fc72010-07-16 13:56:01 +1000186 *s += strspn(*s + 1, WHITESPACE) + 1;
Damien Miller306d1182006-03-15 12:05:59 +1100187 return (old);
188 }
189 }
190
Damien Miller61c51502000-08-18 14:01:04 +1000191 /* Allow only one '=' to be skipped */
192 if (*s[0] == '=')
193 wspace = 1;
194 *s[0] = '\0';
195
Damien Miller306d1182006-03-15 12:05:59 +1100196 /* Skip any extra whitespace after first token */
Damien Miller61c51502000-08-18 14:01:04 +1000197 *s += strspn(*s + 1, WHITESPACE) + 1;
198 if (*s[0] == '=' && !wspace)
199 *s += strspn(*s + 1, WHITESPACE) + 1;
200
201 return (old);
202}
Kevin Stevesb6e773a2001-02-04 13:20:36 +0000203
Ben Lindstrom086cf212001-03-05 05:56:40 +0000204struct passwd *
205pwcopy(struct passwd *pw)
206{
Damien Miller07d86be2006-03-26 14:19:21 +1100207 struct passwd *copy = xcalloc(1, sizeof(*copy));
Ben Lindstrom40304422001-03-05 06:22:01 +0000208
Ben Lindstrom086cf212001-03-05 05:56:40 +0000209 copy->pw_name = xstrdup(pw->pw_name);
210 copy->pw_passwd = xstrdup(pw->pw_passwd);
Damien Miller6332da22013-04-23 14:25:52 +1000211#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
Ben Lindstrom40304422001-03-05 06:22:01 +0000212 copy->pw_gecos = xstrdup(pw->pw_gecos);
Damien Miller6332da22013-04-23 14:25:52 +1000213#endif
Ben Lindstrom086cf212001-03-05 05:56:40 +0000214 copy->pw_uid = pw->pw_uid;
215 copy->pw_gid = pw->pw_gid;
Damien Miller6332da22013-04-23 14:25:52 +1000216#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
Ben Lindstrom3af4d462001-06-21 03:11:27 +0000217 copy->pw_expire = pw->pw_expire;
Kevin Steves82456952001-06-22 21:14:18 +0000218#endif
Damien Miller6332da22013-04-23 14:25:52 +1000219#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
Ben Lindstrom3af4d462001-06-21 03:11:27 +0000220 copy->pw_change = pw->pw_change;
Kevin Steves82456952001-06-22 21:14:18 +0000221#endif
Damien Miller6332da22013-04-23 14:25:52 +1000222#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
Ben Lindstrom086cf212001-03-05 05:56:40 +0000223 copy->pw_class = xstrdup(pw->pw_class);
Ben Lindstrom0f68db42001-03-05 07:57:09 +0000224#endif
Ben Lindstrom086cf212001-03-05 05:56:40 +0000225 copy->pw_dir = xstrdup(pw->pw_dir);
226 copy->pw_shell = xstrdup(pw->pw_shell);
227 return copy;
228}
229
Ben Lindstrom4cc240d2001-07-04 04:46:56 +0000230/*
231 * Convert ASCII string to TCP/IP port number.
Damien Miller3dc71ad2009-01-28 16:31:22 +1100232 * Port must be >=0 and <=65535.
233 * Return -1 if invalid.
Ben Lindstrom4cc240d2001-07-04 04:46:56 +0000234 */
235int
236a2port(const char *s)
Ben Lindstrom19066a12001-04-12 23:39:26 +0000237{
Damien Miller3dc71ad2009-01-28 16:31:22 +1100238 long long port;
239 const char *errstr;
Ben Lindstrom19066a12001-04-12 23:39:26 +0000240
Damien Miller3dc71ad2009-01-28 16:31:22 +1100241 port = strtonum(s, 0, 65535, &errstr);
242 if (errstr != NULL)
243 return -1;
244 return (int)port;
Ben Lindstrom19066a12001-04-12 23:39:26 +0000245}
246
Damien Millerd27b9472005-12-13 19:29:02 +1100247int
248a2tun(const char *s, int *remote)
249{
250 const char *errstr = NULL;
251 char *sp, *ep;
252 int tun;
253
254 if (remote != NULL) {
Damien Miller7b58e802005-12-13 19:33:19 +1100255 *remote = SSH_TUNID_ANY;
Damien Millerd27b9472005-12-13 19:29:02 +1100256 sp = xstrdup(s);
257 if ((ep = strchr(sp, ':')) == NULL) {
Darren Tuckera627d422013-06-02 07:31:17 +1000258 free(sp);
Damien Millerd27b9472005-12-13 19:29:02 +1100259 return (a2tun(s, NULL));
260 }
261 ep[0] = '\0'; ep++;
262 *remote = a2tun(ep, NULL);
263 tun = a2tun(sp, NULL);
Darren Tuckera627d422013-06-02 07:31:17 +1000264 free(sp);
Damien Miller7b58e802005-12-13 19:33:19 +1100265 return (*remote == SSH_TUNID_ERR ? *remote : tun);
Damien Millerd27b9472005-12-13 19:29:02 +1100266 }
267
268 if (strcasecmp(s, "any") == 0)
Damien Miller7b58e802005-12-13 19:33:19 +1100269 return (SSH_TUNID_ANY);
Damien Millerd27b9472005-12-13 19:29:02 +1100270
Damien Miller7b58e802005-12-13 19:33:19 +1100271 tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
272 if (errstr != NULL)
273 return (SSH_TUNID_ERR);
Damien Millerd27b9472005-12-13 19:29:02 +1100274
275 return (tun);
276}
277
Ben Lindstrom1bda4c82001-06-05 19:59:08 +0000278#define SECONDS 1
279#define MINUTES (SECONDS * 60)
280#define HOURS (MINUTES * 60)
281#define DAYS (HOURS * 24)
282#define WEEKS (DAYS * 7)
283
Ben Lindstrom4cc240d2001-07-04 04:46:56 +0000284/*
285 * Convert a time string into seconds; format is
286 * a sequence of:
287 * time[qualifier]
288 *
289 * Valid time qualifiers are:
290 * <none> seconds
291 * s|S seconds
292 * m|M minutes
293 * h|H hours
294 * d|D days
295 * w|W weeks
296 *
297 * Examples:
298 * 90m 90 minutes
299 * 1h30m 90 minutes
300 * 2d 2 days
301 * 1w 1 week
302 *
303 * Return -1 if time string is invalid.
304 */
305long
306convtime(const char *s)
Ben Lindstrom1bda4c82001-06-05 19:59:08 +0000307{
308 long total, secs;
309 const char *p;
310 char *endp;
311
312 errno = 0;
313 total = 0;
314 p = s;
315
316 if (p == NULL || *p == '\0')
317 return -1;
318
319 while (*p) {
320 secs = strtol(p, &endp, 10);
321 if (p == endp ||
322 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
323 secs < 0)
324 return -1;
325
326 switch (*endp++) {
327 case '\0':
328 endp--;
Damien Miller69b72032006-03-26 14:02:35 +1100329 break;
Ben Lindstrom1bda4c82001-06-05 19:59:08 +0000330 case 's':
331 case 'S':
332 break;
333 case 'm':
334 case 'M':
335 secs *= MINUTES;
336 break;
337 case 'h':
338 case 'H':
339 secs *= HOURS;
340 break;
341 case 'd':
342 case 'D':
343 secs *= DAYS;
344 break;
345 case 'w':
346 case 'W':
347 secs *= WEEKS;
348 break;
349 default:
350 return -1;
351 }
352 total += secs;
353 if (total < 0)
354 return -1;
355 p = endp;
356 }
357
358 return total;
359}
360
Damien Millerf91ee4c2005-03-01 21:24:33 +1100361/*
Darren Tuckerda345532006-07-10 23:04:19 +1000362 * Returns a standardized host+port identifier string.
363 * Caller must free returned string.
364 */
365char *
366put_host_port(const char *host, u_short port)
367{
368 char *hoststr;
369
370 if (port == 0 || port == SSH_DEFAULT_PORT)
371 return(xstrdup(host));
372 if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
373 fatal("put_host_port: asprintf: %s", strerror(errno));
374 debug3("put_host_port: %s", hoststr);
375 return hoststr;
376}
377
378/*
Damien Millerf91ee4c2005-03-01 21:24:33 +1100379 * Search for next delimiter between hostnames/addresses and ports.
380 * Argument may be modified (for termination).
381 * Returns *cp if parsing succeeds.
382 * *cp is set to the start of the next delimiter, if one was found.
383 * If this is the last field, *cp is set to NULL.
384 */
385char *
386hpdelim(char **cp)
387{
388 char *s, *old;
389
390 if (cp == NULL || *cp == NULL)
391 return NULL;
392
393 old = s = *cp;
394 if (*s == '[') {
395 if ((s = strchr(s, ']')) == NULL)
396 return NULL;
397 else
398 s++;
399 } else if ((s = strpbrk(s, ":/")) == NULL)
400 s = *cp + strlen(*cp); /* skip to end (see first case below) */
401
402 switch (*s) {
403 case '\0':
404 *cp = NULL; /* no more fields*/
405 break;
Darren Tucker47eede72005-03-14 23:08:12 +1100406
Damien Millerf91ee4c2005-03-01 21:24:33 +1100407 case ':':
408 case '/':
409 *s = '\0'; /* terminate */
410 *cp = s + 1;
411 break;
Darren Tucker47eede72005-03-14 23:08:12 +1100412
Damien Millerf91ee4c2005-03-01 21:24:33 +1100413 default:
414 return NULL;
415 }
416
417 return old;
418}
419
Ben Lindstrom4529b702001-05-03 23:39:53 +0000420char *
421cleanhostname(char *host)
422{
423 if (*host == '[' && host[strlen(host) - 1] == ']') {
424 host[strlen(host) - 1] = '\0';
425 return (host + 1);
426 } else
427 return host;
428}
429
430char *
431colon(char *cp)
432{
433 int flag = 0;
434
435 if (*cp == ':') /* Leading colon is part of file name. */
Damien Miller2e774462010-06-26 09:30:47 +1000436 return NULL;
Ben Lindstrom4529b702001-05-03 23:39:53 +0000437 if (*cp == '[')
438 flag = 1;
439
440 for (; *cp; ++cp) {
441 if (*cp == '@' && *(cp+1) == '[')
442 flag = 1;
443 if (*cp == ']' && *(cp+1) == ':' && flag)
444 return (cp+1);
445 if (*cp == ':' && !flag)
446 return (cp);
447 if (*cp == '/')
Damien Miller2e774462010-06-26 09:30:47 +1000448 return NULL;
Ben Lindstrom4529b702001-05-03 23:39:53 +0000449 }
Damien Miller2e774462010-06-26 09:30:47 +1000450 return NULL;
Ben Lindstrom4529b702001-05-03 23:39:53 +0000451}
452
Ben Lindstrom4cc240d2001-07-04 04:46:56 +0000453/* function to assist building execv() arguments */
Ben Lindstrom387c4722001-05-08 20:27:25 +0000454void
455addargs(arglist *args, char *fmt, ...)
456{
457 va_list ap;
Damien Miller3eec6b72006-01-31 21:49:27 +1100458 char *cp;
Darren Tuckerc7a6fc42004-08-13 21:18:00 +1000459 u_int nalloc;
Damien Miller3eec6b72006-01-31 21:49:27 +1100460 int r;
Ben Lindstrom387c4722001-05-08 20:27:25 +0000461
462 va_start(ap, fmt);
Damien Miller3eec6b72006-01-31 21:49:27 +1100463 r = vasprintf(&cp, fmt, ap);
Ben Lindstrom387c4722001-05-08 20:27:25 +0000464 va_end(ap);
Damien Miller3eec6b72006-01-31 21:49:27 +1100465 if (r == -1)
466 fatal("addargs: argument too long");
Ben Lindstrom387c4722001-05-08 20:27:25 +0000467
Darren Tuckerfb16b242003-09-22 21:04:23 +1000468 nalloc = args->nalloc;
Ben Lindstrom387c4722001-05-08 20:27:25 +0000469 if (args->list == NULL) {
Darren Tuckerfb16b242003-09-22 21:04:23 +1000470 nalloc = 32;
Ben Lindstrom387c4722001-05-08 20:27:25 +0000471 args->num = 0;
Darren Tuckerfb16b242003-09-22 21:04:23 +1000472 } else if (args->num+2 >= nalloc)
473 nalloc *= 2;
Ben Lindstrom387c4722001-05-08 20:27:25 +0000474
deraadt@openbsd.org657a5fb2015-04-24 01:36:00 +0000475 args->list = xreallocarray(args->list, nalloc, sizeof(char *));
Darren Tuckerfb16b242003-09-22 21:04:23 +1000476 args->nalloc = nalloc;
Damien Miller3eec6b72006-01-31 21:49:27 +1100477 args->list[args->num++] = cp;
Ben Lindstrom387c4722001-05-08 20:27:25 +0000478 args->list[args->num] = NULL;
479}
Darren Tucker22cc7412004-12-06 22:47:41 +1100480
Damien Miller3eec6b72006-01-31 21:49:27 +1100481void
482replacearg(arglist *args, u_int which, char *fmt, ...)
483{
484 va_list ap;
485 char *cp;
486 int r;
487
488 va_start(ap, fmt);
489 r = vasprintf(&cp, fmt, ap);
490 va_end(ap);
491 if (r == -1)
492 fatal("replacearg: argument too long");
493
494 if (which >= args->num)
495 fatal("replacearg: tried to replace invalid arg %d >= %d",
496 which, args->num);
Darren Tuckera627d422013-06-02 07:31:17 +1000497 free(args->list[which]);
Damien Miller3eec6b72006-01-31 21:49:27 +1100498 args->list[which] = cp;
499}
500
501void
502freeargs(arglist *args)
503{
504 u_int i;
505
506 if (args->list != NULL) {
507 for (i = 0; i < args->num; i++)
Darren Tuckera627d422013-06-02 07:31:17 +1000508 free(args->list[i]);
509 free(args->list);
Damien Miller3eec6b72006-01-31 21:49:27 +1100510 args->nalloc = args->num = 0;
511 args->list = NULL;
512 }
513}
514
Darren Tucker22cc7412004-12-06 22:47:41 +1100515/*
Damien Miller5fd38c02005-05-26 12:02:14 +1000516 * Expands tildes in the file name. Returns data allocated by xmalloc.
517 * Warning: this calls getpw*.
518 */
519char *
520tilde_expand_filename(const char *filename, uid_t uid)
521{
Darren Tucker2ca51bf2013-05-16 20:22:46 +1000522 const char *path, *sep;
523 char user[128], *ret;
Damien Miller5fd38c02005-05-26 12:02:14 +1000524 struct passwd *pw;
Damien Millereccb9de2005-06-17 12:59:34 +1000525 u_int len, slash;
Damien Miller5fd38c02005-05-26 12:02:14 +1000526
527 if (*filename != '~')
528 return (xstrdup(filename));
529 filename++;
530
531 path = strchr(filename, '/');
532 if (path != NULL && path > filename) { /* ~user/path */
Damien Millereccb9de2005-06-17 12:59:34 +1000533 slash = path - filename;
534 if (slash > sizeof(user) - 1)
Damien Miller5fd38c02005-05-26 12:02:14 +1000535 fatal("tilde_expand_filename: ~username too long");
Damien Millereccb9de2005-06-17 12:59:34 +1000536 memcpy(user, filename, slash);
537 user[slash] = '\0';
Damien Miller5fd38c02005-05-26 12:02:14 +1000538 if ((pw = getpwnam(user)) == NULL)
539 fatal("tilde_expand_filename: No such user %s", user);
540 } else if ((pw = getpwuid(uid)) == NULL) /* ~/path */
Darren Tucker7517b5b2008-06-13 14:48:59 +1000541 fatal("tilde_expand_filename: No such uid %ld", (long)uid);
Damien Miller5fd38c02005-05-26 12:02:14 +1000542
Damien Miller5fd38c02005-05-26 12:02:14 +1000543 /* Make sure directory has a trailing '/' */
544 len = strlen(pw->pw_dir);
Darren Tucker026d9db2013-05-16 20:23:52 +1000545 if (len == 0 || pw->pw_dir[len - 1] != '/')
Darren Tucker2ca51bf2013-05-16 20:22:46 +1000546 sep = "/";
547 else
548 sep = "";
Damien Miller5fd38c02005-05-26 12:02:14 +1000549
550 /* Skip leading '/' from specified path */
551 if (path != NULL)
552 filename = path + 1;
Darren Tucker2ca51bf2013-05-16 20:22:46 +1000553
deraadt@openbsd.org2ae4f332015-01-16 06:40:12 +0000554 if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= PATH_MAX)
Damien Miller5fd38c02005-05-26 12:02:14 +1000555 fatal("tilde_expand_filename: Path too long");
556
Darren Tucker2ca51bf2013-05-16 20:22:46 +1000557 return (ret);
Damien Miller5fd38c02005-05-26 12:02:14 +1000558}
559
560/*
Damien Miller6476cad2005-06-16 13:18:34 +1000561 * Expand a string with a set of %[char] escapes. A number of escapes may be
562 * specified as (char *escape_chars, char *replacement) pairs. The list must
Darren Tuckerbee73d52005-07-14 17:05:02 +1000563 * be terminated by a NULL escape_char. Returns replaced string in memory
Damien Miller6476cad2005-06-16 13:18:34 +1000564 * allocated by xmalloc.
565 */
566char *
567percent_expand(const char *string, ...)
568{
569#define EXPAND_MAX_KEYS 16
Darren Tucker70d87692010-01-08 18:49:16 +1100570 u_int num_keys, i, j;
Damien Miller6476cad2005-06-16 13:18:34 +1000571 struct {
572 const char *key;
573 const char *repl;
574 } keys[EXPAND_MAX_KEYS];
Damien Miller6476cad2005-06-16 13:18:34 +1000575 char buf[4096];
576 va_list ap;
577
578 /* Gather keys */
579 va_start(ap, string);
580 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
581 keys[num_keys].key = va_arg(ap, char *);
582 if (keys[num_keys].key == NULL)
583 break;
584 keys[num_keys].repl = va_arg(ap, char *);
585 if (keys[num_keys].repl == NULL)
Darren Tucker70d87692010-01-08 18:49:16 +1100586 fatal("%s: NULL replacement", __func__);
Damien Miller6476cad2005-06-16 13:18:34 +1000587 }
Darren Tucker70d87692010-01-08 18:49:16 +1100588 if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
589 fatal("%s: too many keys", __func__);
Damien Miller6476cad2005-06-16 13:18:34 +1000590 va_end(ap);
591
Damien Miller6476cad2005-06-16 13:18:34 +1000592 /* Expand string */
593 *buf = '\0';
594 for (i = 0; *string != '\0'; string++) {
595 if (*string != '%') {
596 append:
597 buf[i++] = *string;
598 if (i >= sizeof(buf))
Darren Tucker70d87692010-01-08 18:49:16 +1100599 fatal("%s: string too long", __func__);
Damien Miller6476cad2005-06-16 13:18:34 +1000600 buf[i] = '\0';
601 continue;
602 }
603 string++;
Darren Tucker70d87692010-01-08 18:49:16 +1100604 /* %% case */
Damien Miller6476cad2005-06-16 13:18:34 +1000605 if (*string == '%')
606 goto append;
607 for (j = 0; j < num_keys; j++) {
608 if (strchr(keys[j].key, *string) != NULL) {
609 i = strlcat(buf, keys[j].repl, sizeof(buf));
610 if (i >= sizeof(buf))
Darren Tucker70d87692010-01-08 18:49:16 +1100611 fatal("%s: string too long", __func__);
Damien Miller6476cad2005-06-16 13:18:34 +1000612 break;
613 }
614 }
615 if (j >= num_keys)
Darren Tucker70d87692010-01-08 18:49:16 +1100616 fatal("%s: unknown key %%%c", __func__, *string);
Damien Miller6476cad2005-06-16 13:18:34 +1000617 }
618 return (xstrdup(buf));
619#undef EXPAND_MAX_KEYS
620}
621
622/*
Darren Tucker22cc7412004-12-06 22:47:41 +1100623 * Read an entire line from a public key file into a static buffer, discarding
624 * lines that exceed the buffer size. Returns 0 on success, -1 on failure.
625 */
626int
627read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
Darren Tuckerf0f90982004-12-11 13:39:50 +1100628 u_long *lineno)
Darren Tucker22cc7412004-12-06 22:47:41 +1100629{
630 while (fgets(buf, bufsz, f) != NULL) {
Damien Miller3ca8b772007-01-05 16:24:47 +1100631 if (buf[0] == '\0')
632 continue;
Darren Tucker22cc7412004-12-06 22:47:41 +1100633 (*lineno)++;
634 if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
635 return 0;
636 } else {
Darren Tuckerf0f90982004-12-11 13:39:50 +1100637 debug("%s: %s line %lu exceeds size limit", __func__,
638 filename, *lineno);
Darren Tucker22cc7412004-12-06 22:47:41 +1100639 /* discard remainder of line */
Darren Tucker47eede72005-03-14 23:08:12 +1100640 while (fgetc(f) != '\n' && !feof(f))
Darren Tucker22cc7412004-12-06 22:47:41 +1100641 ; /* nothing */
642 }
643 }
644 return -1;
645}
Damien Miller13390022005-07-06 09:44:19 +1000646
Damien Millerd27b9472005-12-13 19:29:02 +1100647int
Damien Miller7b58e802005-12-13 19:33:19 +1100648tun_open(int tun, int mode)
Damien Millerd27b9472005-12-13 19:29:02 +1100649{
Damien Miller62a31c92005-12-13 20:44:13 +1100650#if defined(CUSTOM_SYS_TUN_OPEN)
651 return (sys_tun_open(tun, mode));
Damien Miller2dcddbf2006-01-01 19:47:05 +1100652#elif defined(SSH_TUN_OPENBSD)
Damien Miller7b58e802005-12-13 19:33:19 +1100653 struct ifreq ifr;
Damien Millerd27b9472005-12-13 19:29:02 +1100654 char name[100];
Damien Miller7b58e802005-12-13 19:33:19 +1100655 int fd = -1, sock;
Damien Millerd27b9472005-12-13 19:29:02 +1100656
Damien Miller7b58e802005-12-13 19:33:19 +1100657 /* Open the tunnel device */
658 if (tun <= SSH_TUNID_MAX) {
Damien Millerd27b9472005-12-13 19:29:02 +1100659 snprintf(name, sizeof(name), "/dev/tun%d", tun);
Damien Miller7b58e802005-12-13 19:33:19 +1100660 fd = open(name, O_RDWR);
661 } else if (tun == SSH_TUNID_ANY) {
662 for (tun = 100; tun >= 0; tun--) {
663 snprintf(name, sizeof(name), "/dev/tun%d", tun);
664 if ((fd = open(name, O_RDWR)) >= 0)
665 break;
Damien Millerd27b9472005-12-13 19:29:02 +1100666 }
667 } else {
Damien Millera210d522006-01-02 23:40:30 +1100668 debug("%s: invalid tunnel %u", __func__, tun);
djm@openbsd.org2905d6f2015-10-07 00:54:06 +0000669 return -1;
Damien Millerd27b9472005-12-13 19:29:02 +1100670 }
Damien Miller7b58e802005-12-13 19:33:19 +1100671
672 if (fd < 0) {
djm@openbsd.org2905d6f2015-10-07 00:54:06 +0000673 debug("%s: %s open: %s", __func__, name, strerror(errno));
674 return -1;
Damien Miller7b58e802005-12-13 19:33:19 +1100675 }
676
677 debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
678
679 /* Set the tunnel device operation mode */
680 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun);
djm@openbsd.org2905d6f2015-10-07 00:54:06 +0000681 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
682 error("%s: socket: %s", __func__, strerror(errno));
Damien Miller7b58e802005-12-13 19:33:19 +1100683 goto failed;
djm@openbsd.org2905d6f2015-10-07 00:54:06 +0000684 }
Damien Miller7b58e802005-12-13 19:33:19 +1100685
djm@openbsd.org2905d6f2015-10-07 00:54:06 +0000686 if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
687 debug("%s: get interface %s flags: %s", __func__,
688 ifr.ifr_name, strerror(errno));
Damien Miller7b58e802005-12-13 19:33:19 +1100689 goto failed;
djm@openbsd.org2905d6f2015-10-07 00:54:06 +0000690 }
Damien Millera1d9a182006-01-02 23:41:21 +1100691
djm@openbsd.org2905d6f2015-10-07 00:54:06 +0000692 /* Set interface mode if not already in correct mode */
693 if ((mode == SSH_TUNMODE_ETHERNET && !(ifr.ifr_flags & IFF_LINK0)) ||
694 (mode != SSH_TUNMODE_ETHERNET && (ifr.ifr_flags & IFF_LINK0))) {
695 ifr.ifr_flags &= ~IFF_UP;
696 ifr.ifr_flags ^= IFF_LINK0;
697 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
698 debug("%s: reset interface %s flags: %s", __func__,
699 ifr.ifr_name, strerror(errno));
700 goto failed;
701 }
702 }
Damien Millera1d9a182006-01-02 23:41:21 +1100703
djm@openbsd.org2905d6f2015-10-07 00:54:06 +0000704 /* Bring interface up if it is not already */
705 if (!(ifr.ifr_flags & IFF_UP)) {
706 ifr.ifr_flags |= IFF_UP;
707 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
708 debug("%s: activate interface %s: %s", __func__,
709 ifr.ifr_name, strerror(errno));
710 goto failed;
711 }
712 }
Damien Miller7b58e802005-12-13 19:33:19 +1100713
714 close(sock);
djm@openbsd.org2905d6f2015-10-07 00:54:06 +0000715 return fd;
Damien Miller7b58e802005-12-13 19:33:19 +1100716
717 failed:
718 if (fd >= 0)
719 close(fd);
720 if (sock >= 0)
721 close(sock);
djm@openbsd.org2905d6f2015-10-07 00:54:06 +0000722 return -1;
Damien Miller62a31c92005-12-13 20:44:13 +1100723#else
724 error("Tunnel interfaces are not supported on this platform");
725 return (-1);
726#endif
Damien Millerd27b9472005-12-13 19:29:02 +1100727}
728
Darren Tuckerce321d82005-10-03 18:11:24 +1000729void
730sanitise_stdfd(void)
731{
Damien Miller72c5b7d2006-01-06 14:50:44 +1100732 int nullfd, dupfd;
Darren Tuckerce321d82005-10-03 18:11:24 +1000733
Damien Miller72c5b7d2006-01-06 14:50:44 +1100734 if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
Damien Miller9eab9562009-02-22 08:47:02 +1100735 fprintf(stderr, "Couldn't open /dev/null: %s\n",
736 strerror(errno));
Darren Tuckerce321d82005-10-03 18:11:24 +1000737 exit(1);
738 }
Damien Miller72c5b7d2006-01-06 14:50:44 +1100739 while (++dupfd <= 2) {
740 /* Only clobber closed fds */
741 if (fcntl(dupfd, F_GETFL, 0) >= 0)
742 continue;
743 if (dup2(nullfd, dupfd) == -1) {
Damien Miller9eab9562009-02-22 08:47:02 +1100744 fprintf(stderr, "dup2: %s\n", strerror(errno));
Darren Tuckerce321d82005-10-03 18:11:24 +1000745 exit(1);
746 }
Darren Tuckerce321d82005-10-03 18:11:24 +1000747 }
748 if (nullfd > 2)
749 close(nullfd);
750}
751
Damien Miller13390022005-07-06 09:44:19 +1000752char *
Damien Miller3f941882006-03-31 23:13:02 +1100753tohex(const void *vp, size_t l)
Damien Miller13390022005-07-06 09:44:19 +1000754{
Damien Miller3f941882006-03-31 23:13:02 +1100755 const u_char *p = (const u_char *)vp;
Damien Miller13390022005-07-06 09:44:19 +1000756 char b[3], *r;
Damien Miller3f941882006-03-31 23:13:02 +1100757 size_t i, hl;
758
759 if (l > 65536)
760 return xstrdup("tohex: length > 65536");
Damien Miller13390022005-07-06 09:44:19 +1000761
762 hl = l * 2 + 1;
Damien Miller07d86be2006-03-26 14:19:21 +1100763 r = xcalloc(1, hl);
Damien Miller13390022005-07-06 09:44:19 +1000764 for (i = 0; i < l; i++) {
Damien Miller3f941882006-03-31 23:13:02 +1100765 snprintf(b, sizeof(b), "%02x", p[i]);
Damien Miller13390022005-07-06 09:44:19 +1000766 strlcat(r, b, hl);
767 }
768 return (r);
769}
770
Damien Miller3f941882006-03-31 23:13:02 +1100771u_int64_t
772get_u64(const void *vp)
773{
774 const u_char *p = (const u_char *)vp;
775 u_int64_t v;
776
777 v = (u_int64_t)p[0] << 56;
778 v |= (u_int64_t)p[1] << 48;
779 v |= (u_int64_t)p[2] << 40;
780 v |= (u_int64_t)p[3] << 32;
781 v |= (u_int64_t)p[4] << 24;
782 v |= (u_int64_t)p[5] << 16;
783 v |= (u_int64_t)p[6] << 8;
784 v |= (u_int64_t)p[7];
785
786 return (v);
787}
788
789u_int32_t
790get_u32(const void *vp)
791{
792 const u_char *p = (const u_char *)vp;
793 u_int32_t v;
794
795 v = (u_int32_t)p[0] << 24;
796 v |= (u_int32_t)p[1] << 16;
797 v |= (u_int32_t)p[2] << 8;
798 v |= (u_int32_t)p[3];
799
800 return (v);
801}
802
Damien Miller88856692014-04-20 13:33:19 +1000803u_int32_t
804get_u32_le(const void *vp)
805{
806 const u_char *p = (const u_char *)vp;
807 u_int32_t v;
808
809 v = (u_int32_t)p[0];
810 v |= (u_int32_t)p[1] << 8;
811 v |= (u_int32_t)p[2] << 16;
812 v |= (u_int32_t)p[3] << 24;
813
814 return (v);
815}
816
Damien Miller3f941882006-03-31 23:13:02 +1100817u_int16_t
818get_u16(const void *vp)
819{
820 const u_char *p = (const u_char *)vp;
821 u_int16_t v;
822
823 v = (u_int16_t)p[0] << 8;
824 v |= (u_int16_t)p[1];
825
826 return (v);
827}
828
829void
830put_u64(void *vp, u_int64_t v)
831{
832 u_char *p = (u_char *)vp;
833
834 p[0] = (u_char)(v >> 56) & 0xff;
835 p[1] = (u_char)(v >> 48) & 0xff;
836 p[2] = (u_char)(v >> 40) & 0xff;
837 p[3] = (u_char)(v >> 32) & 0xff;
838 p[4] = (u_char)(v >> 24) & 0xff;
839 p[5] = (u_char)(v >> 16) & 0xff;
840 p[6] = (u_char)(v >> 8) & 0xff;
841 p[7] = (u_char)v & 0xff;
842}
843
844void
845put_u32(void *vp, u_int32_t v)
846{
847 u_char *p = (u_char *)vp;
848
849 p[0] = (u_char)(v >> 24) & 0xff;
850 p[1] = (u_char)(v >> 16) & 0xff;
851 p[2] = (u_char)(v >> 8) & 0xff;
852 p[3] = (u_char)v & 0xff;
853}
854
Damien Miller88856692014-04-20 13:33:19 +1000855void
856put_u32_le(void *vp, u_int32_t v)
857{
858 u_char *p = (u_char *)vp;
859
860 p[0] = (u_char)v & 0xff;
861 p[1] = (u_char)(v >> 8) & 0xff;
862 p[2] = (u_char)(v >> 16) & 0xff;
863 p[3] = (u_char)(v >> 24) & 0xff;
864}
Damien Miller3f941882006-03-31 23:13:02 +1100865
866void
867put_u16(void *vp, u_int16_t v)
868{
869 u_char *p = (u_char *)vp;
870
871 p[0] = (u_char)(v >> 8) & 0xff;
872 p[1] = (u_char)v & 0xff;
873}
Darren Tucker3fc464e2008-06-13 06:42:45 +1000874
875void
876ms_subtract_diff(struct timeval *start, int *ms)
877{
878 struct timeval diff, finish;
879
880 gettimeofday(&finish, NULL);
881 timersub(&finish, start, &diff);
882 *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
883}
884
885void
886ms_to_timeval(struct timeval *tv, int ms)
887{
888 if (ms < 0)
889 ms = 0;
890 tv->tv_sec = ms / 1000;
891 tv->tv_usec = (ms % 1000) * 1000;
892}
893
Darren Tuckerb759c9c2013-06-02 07:46:16 +1000894time_t
895monotime(void)
896{
Damien Miller795b8632014-05-21 17:12:53 +1000897#if defined(HAVE_CLOCK_GETTIME) && \
898 (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME))
Darren Tuckerb759c9c2013-06-02 07:46:16 +1000899 struct timespec ts;
Darren Tucker94396b72013-08-08 11:52:37 +1000900 static int gettime_failed = 0;
Darren Tuckerb759c9c2013-06-02 07:46:16 +1000901
Darren Tucker94396b72013-08-08 11:52:37 +1000902 if (!gettime_failed) {
Damien Miller795b8632014-05-21 17:12:53 +1000903#if defined(CLOCK_BOOTTIME)
904 if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0)
905 return (ts.tv_sec);
906#endif
907#if defined(CLOCK_MONOTONIC)
Darren Tucker94396b72013-08-08 11:52:37 +1000908 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
909 return (ts.tv_sec);
Damien Miller795b8632014-05-21 17:12:53 +1000910#endif
Darren Tucker94396b72013-08-08 11:52:37 +1000911 debug3("clock_gettime: %s", strerror(errno));
912 gettime_failed = 1;
913 }
Damien Miller795b8632014-05-21 17:12:53 +1000914#endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */
Darren Tucker94396b72013-08-08 11:52:37 +1000915
916 return time(NULL);
Darren Tuckerb759c9c2013-06-02 07:46:16 +1000917}
918
Damien Miller65e42f82010-09-24 22:15:11 +1000919void
920bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
921{
922 bw->buflen = buflen;
923 bw->rate = kbps;
924 bw->thresh = bw->rate;
925 bw->lamt = 0;
926 timerclear(&bw->bwstart);
927 timerclear(&bw->bwend);
928}
929
930/* Callback from read/write loop to insert bandwidth-limiting delays */
931void
932bandwidth_limit(struct bwlimit *bw, size_t read_len)
933{
934 u_int64_t waitlen;
935 struct timespec ts, rm;
936
937 if (!timerisset(&bw->bwstart)) {
938 gettimeofday(&bw->bwstart, NULL);
939 return;
940 }
941
942 bw->lamt += read_len;
943 if (bw->lamt < bw->thresh)
944 return;
945
946 gettimeofday(&bw->bwend, NULL);
947 timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
948 if (!timerisset(&bw->bwend))
949 return;
950
951 bw->lamt *= 8;
952 waitlen = (double)1000000L * bw->lamt / bw->rate;
953
954 bw->bwstart.tv_sec = waitlen / 1000000L;
955 bw->bwstart.tv_usec = waitlen % 1000000L;
956
957 if (timercmp(&bw->bwstart, &bw->bwend, >)) {
958 timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
959
960 /* Adjust the wait time */
961 if (bw->bwend.tv_sec) {
962 bw->thresh /= 2;
963 if (bw->thresh < bw->buflen / 4)
964 bw->thresh = bw->buflen / 4;
965 } else if (bw->bwend.tv_usec < 10000) {
966 bw->thresh *= 2;
967 if (bw->thresh > bw->buflen * 8)
968 bw->thresh = bw->buflen * 8;
969 }
970
971 TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
972 while (nanosleep(&ts, &rm) == -1) {
973 if (errno != EINTR)
974 break;
975 ts = rm;
976 }
977 }
978
979 bw->lamt = 0;
980 gettimeofday(&bw->bwstart, NULL);
981}
Damien Miller0dac6fb2010-11-20 15:19:38 +1100982
Damien Miller2cd62932010-12-01 11:50:35 +1100983/* Make a template filename for mk[sd]temp() */
984void
985mktemp_proto(char *s, size_t len)
986{
987 const char *tmpdir;
988 int r;
989
990 if ((tmpdir = getenv("TMPDIR")) != NULL) {
991 r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
992 if (r > 0 && (size_t)r < len)
993 return;
994 }
995 r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
996 if (r < 0 || (size_t)r >= len)
997 fatal("%s: template string too short", __func__);
998}
999
Damien Miller0dac6fb2010-11-20 15:19:38 +11001000static const struct {
1001 const char *name;
1002 int value;
1003} ipqos[] = {
1004 { "af11", IPTOS_DSCP_AF11 },
1005 { "af12", IPTOS_DSCP_AF12 },
1006 { "af13", IPTOS_DSCP_AF13 },
Damien Miller2918e032011-09-22 21:34:35 +10001007 { "af21", IPTOS_DSCP_AF21 },
Damien Miller0dac6fb2010-11-20 15:19:38 +11001008 { "af22", IPTOS_DSCP_AF22 },
1009 { "af23", IPTOS_DSCP_AF23 },
1010 { "af31", IPTOS_DSCP_AF31 },
1011 { "af32", IPTOS_DSCP_AF32 },
1012 { "af33", IPTOS_DSCP_AF33 },
1013 { "af41", IPTOS_DSCP_AF41 },
1014 { "af42", IPTOS_DSCP_AF42 },
1015 { "af43", IPTOS_DSCP_AF43 },
1016 { "cs0", IPTOS_DSCP_CS0 },
1017 { "cs1", IPTOS_DSCP_CS1 },
1018 { "cs2", IPTOS_DSCP_CS2 },
1019 { "cs3", IPTOS_DSCP_CS3 },
1020 { "cs4", IPTOS_DSCP_CS4 },
1021 { "cs5", IPTOS_DSCP_CS5 },
1022 { "cs6", IPTOS_DSCP_CS6 },
1023 { "cs7", IPTOS_DSCP_CS7 },
1024 { "ef", IPTOS_DSCP_EF },
1025 { "lowdelay", IPTOS_LOWDELAY },
1026 { "throughput", IPTOS_THROUGHPUT },
1027 { "reliability", IPTOS_RELIABILITY },
1028 { NULL, -1 }
1029};
1030
1031int
1032parse_ipqos(const char *cp)
1033{
1034 u_int i;
1035 char *ep;
1036 long val;
1037
1038 if (cp == NULL)
1039 return -1;
1040 for (i = 0; ipqos[i].name != NULL; i++) {
1041 if (strcasecmp(cp, ipqos[i].name) == 0)
1042 return ipqos[i].value;
1043 }
1044 /* Try parsing as an integer */
1045 val = strtol(cp, &ep, 0);
1046 if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
1047 return -1;
1048 return val;
1049}
1050
Damien Miller91475862011-05-05 14:14:34 +10001051const char *
1052iptos2str(int iptos)
1053{
1054 int i;
1055 static char iptos_str[sizeof "0xff"];
1056
1057 for (i = 0; ipqos[i].name != NULL; i++) {
1058 if (ipqos[i].value == iptos)
1059 return ipqos[i].name;
1060 }
1061 snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
1062 return iptos_str;
1063}
Damien Millere9fc72e2013-10-15 12:14:12 +11001064
1065void
1066lowercase(char *s)
1067{
1068 for (; *s; s++)
1069 *s = tolower((u_char)*s);
1070}
Damien Miller7acefbb2014-07-18 14:11:24 +10001071
1072int
1073unix_listener(const char *path, int backlog, int unlink_first)
1074{
1075 struct sockaddr_un sunaddr;
1076 int saved_errno, sock;
1077
1078 memset(&sunaddr, 0, sizeof(sunaddr));
1079 sunaddr.sun_family = AF_UNIX;
1080 if (strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
1081 error("%s: \"%s\" too long for Unix domain socket", __func__,
1082 path);
1083 errno = ENAMETOOLONG;
1084 return -1;
1085 }
1086
1087 sock = socket(PF_UNIX, SOCK_STREAM, 0);
1088 if (sock < 0) {
1089 saved_errno = errno;
1090 error("socket: %.100s", strerror(errno));
1091 errno = saved_errno;
1092 return -1;
1093 }
1094 if (unlink_first == 1) {
1095 if (unlink(path) != 0 && errno != ENOENT)
1096 error("unlink(%s): %.100s", path, strerror(errno));
1097 }
1098 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
1099 saved_errno = errno;
1100 error("bind: %.100s", strerror(errno));
1101 close(sock);
1102 error("%s: cannot bind to path: %s", __func__, path);
1103 errno = saved_errno;
1104 return -1;
1105 }
1106 if (listen(sock, backlog) < 0) {
1107 saved_errno = errno;
1108 error("listen: %.100s", strerror(errno));
1109 close(sock);
1110 unlink(path);
1111 error("%s: cannot listen on path: %s", __func__, path);
1112 errno = saved_errno;
1113 return -1;
1114 }
1115 return sock;
1116}
Damien Miller46878022014-08-30 03:29:19 +10001117
Damien Miller04ee0f82009-11-18 17:48:30 +11001118void
1119sock_set_v6only(int s)
1120{
1121#ifdef IPV6_V6ONLY
1122 int on = 1;
1123
1124 debug3("%s: set socket %d IPV6_V6ONLY", __func__, s);
1125 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)
1126 error("setsockopt IPV6_V6ONLY: %s", strerror(errno));
1127#endif
1128}