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 75fe4dfea..c75a795c2 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>
@@ -260,7 +254,7 @@ waitfd(int fd, int *timeoutp, short events)
260 errno = oerrno; 254 errno = oerrno;
261 if (r > 0) 255 if (r > 0)
262 return 0; 256 return 0;
263 else if (r == -1 && errno != EAGAIN) 257 else if (r == -1 && errno != EAGAIN && errno != EINTR)
264 return -1; 258 return -1;
265 else if (r == 0) 259 else if (r == 0)
266 break; 260 break;
@@ -299,12 +293,17 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
299 return connect(sockfd, serv_addr, addrlen); 293 return connect(sockfd, serv_addr, addrlen);
300 294
301 set_nonblock(sockfd); 295 set_nonblock(sockfd);
302 if (connect(sockfd, serv_addr, addrlen) == 0) { 296 for (;;) {
303 /* Succeeded already? */ 297 if (connect(sockfd, serv_addr, addrlen) == 0) {
304 unset_nonblock(sockfd); 298 /* Succeeded already? */
305 return 0; 299 unset_nonblock(sockfd);
306 } else if (errno != EINPROGRESS) 300 return 0;
307 return -1; 301 } else if (errno == EINTR)
302 continue;
303 else if (errno != EINPROGRESS)
304 return -1;
305 break;
306 }
308 307
309 if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT) == -1) 308 if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT) == -1)
310 return -1; 309 return -1;
@@ -494,7 +493,7 @@ a2tun(const char *s, int *remote)
494long 493long
495convtime(const char *s) 494convtime(const char *s)
496{ 495{
497 long total, secs, multiplier = 1; 496 long total, secs, multiplier;
498 const char *p; 497 const char *p;
499 char *endp; 498 char *endp;
500 499
@@ -512,6 +511,7 @@ convtime(const char *s)
512 secs < 0) 511 secs < 0)
513 return -1; 512 return -1;
514 513
514 multiplier = 1;
515 switch (*endp++) { 515 switch (*endp++) {
516 case '\0': 516 case '\0':
517 endp--; 517 endp--;
@@ -552,6 +552,43 @@ convtime(const char *s)
552 return total; 552 return total;
553} 553}
554 554
555#define TF_BUFS 8
556#define TF_LEN 9
557
558const char *
559fmt_timeframe(time_t t)
560{
561 char *buf;
562 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */
563 static int idx = 0;
564 unsigned int sec, min, hrs, day;
565 unsigned long long week;
566
567 buf = tfbuf[idx++];
568 if (idx == TF_BUFS)
569 idx = 0;
570
571 week = t;
572
573 sec = week % 60;
574 week /= 60;
575 min = week % 60;
576 week /= 60;
577 hrs = week % 24;
578 week /= 24;
579 day = week % 7;
580 week /= 7;
581
582 if (week > 0)
583 snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
584 else if (day > 0)
585 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
586 else
587 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
588
589 return (buf);
590}
591
555/* 592/*
556 * Returns a standardized host+port identifier string. 593 * Returns a standardized host+port identifier string.
557 * Caller must free returned string. 594 * Caller must free returned string.
@@ -1053,45 +1090,90 @@ tilde_expand_filename(const char *filename, uid_t uid)
1053} 1090}
1054 1091
1055/* 1092/*
1056 * Expand a string with a set of %[char] escapes. A number of escapes may be 1093 * Expand a string with a set of %[char] escapes and/or ${ENVIRONMENT}
1057 * specified as (char *escape_chars, char *replacement) pairs. The list must 1094 * substitutions. A number of escapes may be specified as
1058 * be terminated by a NULL escape_char. Returns replaced string in memory 1095 * (char *escape_chars, char *replacement) pairs. The list must be terminated
1059 * allocated by xmalloc. 1096 * by a NULL escape_char. Returns replaced string in memory allocated by
1097 * xmalloc which the caller must free.
1060 */ 1098 */
1061char * 1099static char *
1062percent_expand(const char *string, ...) 1100vdollar_percent_expand(int *parseerror, int dollar, int percent,
1101 const char *string, va_list ap)
1063{ 1102{
1064#define EXPAND_MAX_KEYS 16 1103#define EXPAND_MAX_KEYS 16
1065 u_int num_keys, i; 1104 u_int num_keys = 0, i;
1066 struct { 1105 struct {
1067 const char *key; 1106 const char *key;
1068 const char *repl; 1107 const char *repl;
1069 } keys[EXPAND_MAX_KEYS]; 1108 } keys[EXPAND_MAX_KEYS];
1070 struct sshbuf *buf; 1109 struct sshbuf *buf;
1071 va_list ap; 1110 int r, missingvar = 0;
1072 int r; 1111 char *ret = NULL, *var, *varend, *val;
1073 char *ret; 1112 size_t len;
1074 1113
1075 if ((buf = sshbuf_new()) == NULL) 1114 if ((buf = sshbuf_new()) == NULL)
1076 fatal("%s: sshbuf_new failed", __func__); 1115 fatal("%s: sshbuf_new failed", __func__);
1077 1116 if (parseerror == NULL)
1078 /* Gather keys */ 1117 fatal("%s: null parseerror arg", __func__);
1079 va_start(ap, string); 1118 *parseerror = 1;
1080 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 1119
1081 keys[num_keys].key = va_arg(ap, char *); 1120 /* Gather keys if we're doing percent expansion. */
1082 if (keys[num_keys].key == NULL) 1121 if (percent) {
1083 break; 1122 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
1084 keys[num_keys].repl = va_arg(ap, char *); 1123 keys[num_keys].key = va_arg(ap, char *);
1085 if (keys[num_keys].repl == NULL) 1124 if (keys[num_keys].key == NULL)
1086 fatal("%s: NULL replacement", __func__); 1125 break;
1126 keys[num_keys].repl = va_arg(ap, char *);
1127 if (keys[num_keys].repl == NULL)
1128 fatal("%s: NULL replacement for token %s", __func__, keys[num_keys].key);
1129 }
1130 if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
1131 fatal("%s: too many keys", __func__);
1132 if (num_keys == 0)
1133 fatal("%s: percent expansion without token list",
1134 __func__);
1087 } 1135 }
1088 if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
1089 fatal("%s: too many keys", __func__);
1090 va_end(ap);
1091 1136
1092 /* Expand string */ 1137 /* Expand string */
1093 for (i = 0; *string != '\0'; string++) { 1138 for (i = 0; *string != '\0'; string++) {
1094 if (*string != '%') { 1139 /* Optionally process ${ENVIRONMENT} expansions. */
1140 if (dollar && string[0] == '$' && string[1] == '{') {
1141 string += 2; /* skip over '${' */
1142 if ((varend = strchr(string, '}')) == NULL) {
1143 error("%s: environment variable '%s' missing "
1144 "closing '}'", __func__, string);
1145 goto out;
1146 }
1147 len = varend - string;
1148 if (len == 0) {
1149 error("%s: zero-length environment variable",
1150 __func__);
1151 goto out;
1152 }
1153 var = xmalloc(len + 1);
1154 (void)strlcpy(var, string, len + 1);
1155 if ((val = getenv(var)) == NULL) {
1156 error("%s: env var ${%s} has no value",
1157 __func__, var);
1158 missingvar = 1;
1159 } else {
1160 debug3("%s: expand ${%s} -> '%s'", __func__,
1161 var, val);
1162 if ((r = sshbuf_put(buf, val, strlen(val))) !=0)
1163 fatal("%s: sshbuf_put: %s", __func__,
1164 ssh_err(r));
1165 }
1166 free(var);
1167 string += len;
1168 continue;
1169 }
1170
1171 /*
1172 * Process percent expansions if we have a list of TOKENs.
1173 * If we're not doing percent expansion everything just gets
1174 * appended here.
1175 */
1176 if (*string != '%' || !percent) {
1095 append: 1177 append:
1096 if ((r = sshbuf_put_u8(buf, *string)) != 0) { 1178 if ((r = sshbuf_put_u8(buf, *string)) != 0) {
1097 fatal("%s: sshbuf_put_u8: %s", 1179 fatal("%s: sshbuf_put_u8: %s",
@@ -1103,8 +1185,10 @@ percent_expand(const char *string, ...)
1103 /* %% case */ 1185 /* %% case */
1104 if (*string == '%') 1186 if (*string == '%')
1105 goto append; 1187 goto append;
1106 if (*string == '\0') 1188 if (*string == '\0') {
1107 fatal("%s: invalid format", __func__); 1189 error("%s: invalid format", __func__);
1190 goto out;
1191 }
1108 for (i = 0; i < num_keys; i++) { 1192 for (i = 0; i < num_keys; i++) {
1109 if (strchr(keys[i].key, *string) != NULL) { 1193 if (strchr(keys[i].key, *string) != NULL) {
1110 if ((r = sshbuf_put(buf, keys[i].repl, 1194 if ((r = sshbuf_put(buf, keys[i].repl,
@@ -1115,16 +1199,79 @@ percent_expand(const char *string, ...)
1115 break; 1199 break;
1116 } 1200 }
1117 } 1201 }
1118 if (i >= num_keys) 1202 if (i >= num_keys) {
1119 fatal("%s: unknown key %%%c", __func__, *string); 1203 error("%s: unknown key %%%c", __func__, *string);
1204 goto out;
1205 }
1120 } 1206 }
1121 if ((ret = sshbuf_dup_string(buf)) == NULL) 1207 if (!missingvar && (ret = sshbuf_dup_string(buf)) == NULL)
1122 fatal("%s: sshbuf_dup_string failed", __func__); 1208 fatal("%s: sshbuf_dup_string failed", __func__);
1209 *parseerror = 0;
1210 out:
1123 sshbuf_free(buf); 1211 sshbuf_free(buf);
1124 return ret; 1212 return *parseerror ? NULL : ret;
1125#undef EXPAND_MAX_KEYS 1213#undef EXPAND_MAX_KEYS
1126} 1214}
1127 1215
1216/*
1217 * Expand only environment variables.
1218 * Note that although this function is variadic like the other similar
1219 * functions, any such arguments will be unused.
1220 */
1221
1222char *
1223dollar_expand(int *parseerr, const char *string, ...)
1224{
1225 char *ret;
1226 int err;
1227 va_list ap;
1228
1229 va_start(ap, string);
1230 ret = vdollar_percent_expand(&err, 1, 0, string, ap);
1231 va_end(ap);
1232 if (parseerr != NULL)
1233 *parseerr = err;
1234 return ret;
1235}
1236
1237/*
1238 * Returns expanded string or NULL if a specified environment variable is
1239 * not defined, or calls fatal if the string is invalid.
1240 */
1241char *
1242percent_expand(const char *string, ...)
1243{
1244 char *ret;
1245 int err;
1246 va_list ap;
1247
1248 va_start(ap, string);
1249 ret = vdollar_percent_expand(&err, 0, 1, string, ap);
1250 va_end(ap);
1251 if (err)
1252 fatal("%s failed", __func__);
1253 return ret;
1254}
1255
1256/*
1257 * Returns expanded string or NULL if a specified environment variable is
1258 * not defined, or calls fatal if the string is invalid.
1259 */
1260char *
1261percent_dollar_expand(const char *string, ...)
1262{
1263 char *ret;
1264 int err;
1265 va_list ap;
1266
1267 va_start(ap, string);
1268 ret = vdollar_percent_expand(&err, 1, 1, string, ap);
1269 va_end(ap);
1270 if (err)
1271 fatal("%s failed", __func__);
1272 return ret;
1273}
1274
1128int 1275int
1129secure_permissions(struct stat *st, uid_t uid) 1276secure_permissions(struct stat *st, uid_t uid)
1130{ 1277{