diff options
Diffstat (limited to 'misc.c')
-rw-r--r-- | misc.c | 263 |
1 files changed, 205 insertions, 58 deletions
@@ -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) | |||
493 | long | 492 | long |
494 | convtime(const char *s) | 493 | convtime(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 | |||
557 | const char * | ||
558 | fmt_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 | */ |
1060 | char * | 1098 | static char * |
1061 | percent_expand(const char *string, ...) | 1099 | vdollar_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 | |||
1221 | char * | ||
1222 | dollar_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 | */ | ||
1240 | char * | ||
1241 | percent_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 | */ | ||
1259 | char * | ||
1260 | percent_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 | |||
1127 | int | 1274 | int |
1128 | tun_open(int tun, int mode, char **ifname) | 1275 | tun_open(int tun, int mode, char **ifname) |
1129 | { | 1276 | { |