summaryrefslogtreecommitdiff
path: root/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'misc.c')
-rw-r--r--misc.c263
1 files changed, 205 insertions, 58 deletions
diff --git a/misc.c b/misc.c
index 554ceb0b1..4623b5755 100644
--- a/misc.c
+++ b/misc.c
@@ -1,29 +1,23 @@
1/* $OpenBSD: misc.c,v 1.147 2020/04/25 06:59:36 dtucker Exp $ */ 1/* $OpenBSD: misc.c,v 1.153 2020/06/26 05:16:38 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Copyright (c) 2005,2006 Damien Miller. All rights reserved. 4 * Copyright (c) 2005-2020 Damien Miller. All rights reserved.
5 * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
5 * 6 *
6 * Redistribution and use in source and binary forms, with or without 7 * Permission to use, copy, modify, and distribute this software for any
7 * modification, are permitted provided that the following conditions 8 * purpose with or without fee is hereby granted, provided that the above
8 * are met: 9 * copyright notice and this permission notice appear in all copies.
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 * 10 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
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 */ 18 */
26 19
20
27#include "includes.h" 21#include "includes.h"
28 22
29#include <sys/types.h> 23#include <sys/types.h>
@@ -259,7 +253,7 @@ waitfd(int fd, int *timeoutp, short events)
259 errno = oerrno; 253 errno = oerrno;
260 if (r > 0) 254 if (r > 0)
261 return 0; 255 return 0;
262 else if (r == -1 && errno != EAGAIN) 256 else if (r == -1 && errno != EAGAIN && errno != EINTR)
263 return -1; 257 return -1;
264 else if (r == 0) 258 else if (r == 0)
265 break; 259 break;
@@ -298,12 +292,17 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
298 return connect(sockfd, serv_addr, addrlen); 292 return connect(sockfd, serv_addr, addrlen);
299 293
300 set_nonblock(sockfd); 294 set_nonblock(sockfd);
301 if (connect(sockfd, serv_addr, addrlen) == 0) { 295 for (;;) {
302 /* Succeeded already? */ 296 if (connect(sockfd, serv_addr, addrlen) == 0) {
303 unset_nonblock(sockfd); 297 /* Succeeded already? */
304 return 0; 298 unset_nonblock(sockfd);
305 } else if (errno != EINPROGRESS) 299 return 0;
306 return -1; 300 } else if (errno == EINTR)
301 continue;
302 else if (errno != EINPROGRESS)
303 return -1;
304 break;
305 }
307 306
308 if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT) == -1) 307 if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT) == -1)
309 return -1; 308 return -1;
@@ -493,7 +492,7 @@ a2tun(const char *s, int *remote)
493long 492long
494convtime(const char *s) 493convtime(const char *s)
495{ 494{
496 long total, secs, multiplier = 1; 495 long total, secs, multiplier;
497 const char *p; 496 const char *p;
498 char *endp; 497 char *endp;
499 498
@@ -511,6 +510,7 @@ convtime(const char *s)
511 secs < 0) 510 secs < 0)
512 return -1; 511 return -1;
513 512
513 multiplier = 1;
514 switch (*endp++) { 514 switch (*endp++) {
515 case '\0': 515 case '\0':
516 endp--; 516 endp--;
@@ -551,6 +551,43 @@ convtime(const char *s)
551 return total; 551 return total;
552} 552}
553 553
554#define TF_BUFS 8
555#define TF_LEN 9
556
557const char *
558fmt_timeframe(time_t t)
559{
560 char *buf;
561 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */
562 static int idx = 0;
563 unsigned int sec, min, hrs, day;
564 unsigned long long week;
565
566 buf = tfbuf[idx++];
567 if (idx == TF_BUFS)
568 idx = 0;
569
570 week = t;
571
572 sec = week % 60;
573 week /= 60;
574 min = week % 60;
575 week /= 60;
576 hrs = week % 24;
577 week /= 24;
578 day = week % 7;
579 week /= 7;
580
581 if (week > 0)
582 snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
583 else if (day > 0)
584 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
585 else
586 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
587
588 return (buf);
589}
590
554/* 591/*
555 * Returns a standardized host+port identifier string. 592 * Returns a standardized host+port identifier string.
556 * Caller must free returned string. 593 * Caller must free returned string.
@@ -1052,45 +1089,90 @@ tilde_expand_filename(const char *filename, uid_t uid)
1052} 1089}
1053 1090
1054/* 1091/*
1055 * Expand a string with a set of %[char] escapes. A number of escapes may be 1092 * Expand a string with a set of %[char] escapes and/or ${ENVIRONMENT}
1056 * specified as (char *escape_chars, char *replacement) pairs. The list must 1093 * substitutions. A number of escapes may be specified as
1057 * be terminated by a NULL escape_char. Returns replaced string in memory 1094 * (char *escape_chars, char *replacement) pairs. The list must be terminated
1058 * allocated by xmalloc. 1095 * by a NULL escape_char. Returns replaced string in memory allocated by
1096 * xmalloc which the caller must free.
1059 */ 1097 */
1060char * 1098static char *
1061percent_expand(const char *string, ...) 1099vdollar_percent_expand(int *parseerror, int dollar, int percent,
1100 const char *string, va_list ap)
1062{ 1101{
1063#define EXPAND_MAX_KEYS 16 1102#define EXPAND_MAX_KEYS 16
1064 u_int num_keys, i; 1103 u_int num_keys = 0, i;
1065 struct { 1104 struct {
1066 const char *key; 1105 const char *key;
1067 const char *repl; 1106 const char *repl;
1068 } keys[EXPAND_MAX_KEYS]; 1107 } keys[EXPAND_MAX_KEYS];
1069 struct sshbuf *buf; 1108 struct sshbuf *buf;
1070 va_list ap; 1109 int r, missingvar = 0;
1071 int r; 1110 char *ret = NULL, *var, *varend, *val;
1072 char *ret; 1111 size_t len;
1073 1112
1074 if ((buf = sshbuf_new()) == NULL) 1113 if ((buf = sshbuf_new()) == NULL)
1075 fatal("%s: sshbuf_new failed", __func__); 1114 fatal("%s: sshbuf_new failed", __func__);
1076 1115 if (parseerror == NULL)
1077 /* Gather keys */ 1116 fatal("%s: null parseerror arg", __func__);
1078 va_start(ap, string); 1117 *parseerror = 1;
1079 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 1118
1080 keys[num_keys].key = va_arg(ap, char *); 1119 /* Gather keys if we're doing percent expansion. */
1081 if (keys[num_keys].key == NULL) 1120 if (percent) {
1082 break; 1121 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
1083 keys[num_keys].repl = va_arg(ap, char *); 1122 keys[num_keys].key = va_arg(ap, char *);
1084 if (keys[num_keys].repl == NULL) 1123 if (keys[num_keys].key == NULL)
1085 fatal("%s: NULL replacement", __func__); 1124 break;
1125 keys[num_keys].repl = va_arg(ap, char *);
1126 if (keys[num_keys].repl == NULL)
1127 fatal("%s: NULL replacement for token %s", __func__, keys[num_keys].key);
1128 }
1129 if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
1130 fatal("%s: too many keys", __func__);
1131 if (num_keys == 0)
1132 fatal("%s: percent expansion without token list",
1133 __func__);
1086 } 1134 }
1087 if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
1088 fatal("%s: too many keys", __func__);
1089 va_end(ap);
1090 1135
1091 /* Expand string */ 1136 /* Expand string */
1092 for (i = 0; *string != '\0'; string++) { 1137 for (i = 0; *string != '\0'; string++) {
1093 if (*string != '%') { 1138 /* Optionally process ${ENVIRONMENT} expansions. */
1139 if (dollar && string[0] == '$' && string[1] == '{') {
1140 string += 2; /* skip over '${' */
1141 if ((varend = strchr(string, '}')) == NULL) {
1142 error("%s: environment variable '%s' missing "
1143 "closing '}'", __func__, string);
1144 goto out;
1145 }
1146 len = varend - string;
1147 if (len == 0) {
1148 error("%s: zero-length environment variable",
1149 __func__);
1150 goto out;
1151 }
1152 var = xmalloc(len + 1);
1153 (void)strlcpy(var, string, len + 1);
1154 if ((val = getenv(var)) == NULL) {
1155 error("%s: env var ${%s} has no value",
1156 __func__, var);
1157 missingvar = 1;
1158 } else {
1159 debug3("%s: expand ${%s} -> '%s'", __func__,
1160 var, val);
1161 if ((r = sshbuf_put(buf, val, strlen(val))) !=0)
1162 fatal("%s: sshbuf_put: %s", __func__,
1163 ssh_err(r));
1164 }
1165 free(var);
1166 string += len;
1167 continue;
1168 }
1169
1170 /*
1171 * Process percent expansions if we have a list of TOKENs.
1172 * If we're not doing percent expansion everything just gets
1173 * appended here.
1174 */
1175 if (*string != '%' || !percent) {
1094 append: 1176 append:
1095 if ((r = sshbuf_put_u8(buf, *string)) != 0) { 1177 if ((r = sshbuf_put_u8(buf, *string)) != 0) {
1096 fatal("%s: sshbuf_put_u8: %s", 1178 fatal("%s: sshbuf_put_u8: %s",
@@ -1102,8 +1184,10 @@ percent_expand(const char *string, ...)
1102 /* %% case */ 1184 /* %% case */
1103 if (*string == '%') 1185 if (*string == '%')
1104 goto append; 1186 goto append;
1105 if (*string == '\0') 1187 if (*string == '\0') {
1106 fatal("%s: invalid format", __func__); 1188 error("%s: invalid format", __func__);
1189 goto out;
1190 }
1107 for (i = 0; i < num_keys; i++) { 1191 for (i = 0; i < num_keys; i++) {
1108 if (strchr(keys[i].key, *string) != NULL) { 1192 if (strchr(keys[i].key, *string) != NULL) {
1109 if ((r = sshbuf_put(buf, keys[i].repl, 1193 if ((r = sshbuf_put(buf, keys[i].repl,
@@ -1114,16 +1198,79 @@ percent_expand(const char *string, ...)
1114 break; 1198 break;
1115 } 1199 }
1116 } 1200 }
1117 if (i >= num_keys) 1201 if (i >= num_keys) {
1118 fatal("%s: unknown key %%%c", __func__, *string); 1202 error("%s: unknown key %%%c", __func__, *string);
1203 goto out;
1204 }
1119 } 1205 }
1120 if ((ret = sshbuf_dup_string(buf)) == NULL) 1206 if (!missingvar && (ret = sshbuf_dup_string(buf)) == NULL)
1121 fatal("%s: sshbuf_dup_string failed", __func__); 1207 fatal("%s: sshbuf_dup_string failed", __func__);
1208 *parseerror = 0;
1209 out:
1122 sshbuf_free(buf); 1210 sshbuf_free(buf);
1123 return ret; 1211 return *parseerror ? NULL : ret;
1124#undef EXPAND_MAX_KEYS 1212#undef EXPAND_MAX_KEYS
1125} 1213}
1126 1214
1215/*
1216 * Expand only environment variables.
1217 * Note that although this function is variadic like the other similar
1218 * functions, any such arguments will be unused.
1219 */
1220
1221char *
1222dollar_expand(int *parseerr, const char *string, ...)
1223{
1224 char *ret;
1225 int err;
1226 va_list ap;
1227
1228 va_start(ap, string);
1229 ret = vdollar_percent_expand(&err, 1, 0, string, ap);
1230 va_end(ap);
1231 if (parseerr != NULL)
1232 *parseerr = err;
1233 return ret;
1234}
1235
1236/*
1237 * Returns expanded string or NULL if a specified environment variable is
1238 * not defined, or calls fatal if the string is invalid.
1239 */
1240char *
1241percent_expand(const char *string, ...)
1242{
1243 char *ret;
1244 int err;
1245 va_list ap;
1246
1247 va_start(ap, string);
1248 ret = vdollar_percent_expand(&err, 0, 1, string, ap);
1249 va_end(ap);
1250 if (err)
1251 fatal("%s failed", __func__);
1252 return ret;
1253}
1254
1255/*
1256 * Returns expanded string or NULL if a specified environment variable is
1257 * not defined, or calls fatal if the string is invalid.
1258 */
1259char *
1260percent_dollar_expand(const char *string, ...)
1261{
1262 char *ret;
1263 int err;
1264 va_list ap;
1265
1266 va_start(ap, string);
1267 ret = vdollar_percent_expand(&err, 1, 1, string, ap);
1268 va_end(ap);
1269 if (err)
1270 fatal("%s failed", __func__);
1271 return ret;
1272}
1273
1127int 1274int
1128tun_open(int tun, int mode, char **ifname) 1275tun_open(int tun, int mode, char **ifname)
1129{ 1276{