summaryrefslogtreecommitdiff
path: root/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'misc.c')
-rw-r--r--misc.c165
1 files changed, 134 insertions, 31 deletions
diff --git a/misc.c b/misc.c
index 5a34107f8..3ec02d79e 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: misc.c,v 1.149 2020/05/29 01:20:46 dtucker Exp $ */ 1/* $OpenBSD: misc.c,v 1.150 2020/05/29 04:25:40 dtucker 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-2020 Damien Miller. All rights reserved. 4 * Copyright (c) 2005-2020 Damien Miller. All rights reserved.
@@ -1084,45 +1084,90 @@ tilde_expand_filename(const char *filename, uid_t uid)
1084} 1084}
1085 1085
1086/* 1086/*
1087 * Expand a string with a set of %[char] escapes. A number of escapes may be 1087 * Expand a string with a set of %[char] escapes and/or ${ENVIRONMENT}
1088 * specified as (char *escape_chars, char *replacement) pairs. The list must 1088 * substitutions. A number of escapes may be specified as
1089 * be terminated by a NULL escape_char. Returns replaced string in memory 1089 * (char *escape_chars, char *replacement) pairs. The list must be terminated
1090 * allocated by xmalloc. 1090 * by a NULL escape_char. Returns replaced string in memory allocated by
1091 * xmalloc which the caller must free.
1091 */ 1092 */
1092char * 1093static char *
1093percent_expand(const char *string, ...) 1094vdollar_percent_expand(int *parseerror, int dollar, int percent,
1095 const char *string, va_list ap)
1094{ 1096{
1095#define EXPAND_MAX_KEYS 16 1097#define EXPAND_MAX_KEYS 16
1096 u_int num_keys, i; 1098 u_int num_keys = 0, i;
1097 struct { 1099 struct {
1098 const char *key; 1100 const char *key;
1099 const char *repl; 1101 const char *repl;
1100 } keys[EXPAND_MAX_KEYS]; 1102 } keys[EXPAND_MAX_KEYS];
1101 struct sshbuf *buf; 1103 struct sshbuf *buf;
1102 va_list ap; 1104 int r, missingvar = 0;
1103 int r; 1105 char *ret = NULL, *var, *varend, *val;
1104 char *ret; 1106 size_t len;
1105 1107
1106 if ((buf = sshbuf_new()) == NULL) 1108 if ((buf = sshbuf_new()) == NULL)
1107 fatal("%s: sshbuf_new failed", __func__); 1109 fatal("%s: sshbuf_new failed", __func__);
1108 1110 if (parseerror == NULL)
1109 /* Gather keys */ 1111 fatal("%s: null parseerror arg", __func__);
1110 va_start(ap, string); 1112 *parseerror = 1;
1111 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 1113
1112 keys[num_keys].key = va_arg(ap, char *); 1114 /* Gather keys if we're doing percent expansion. */
1113 if (keys[num_keys].key == NULL) 1115 if (percent) {
1114 break; 1116 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
1115 keys[num_keys].repl = va_arg(ap, char *); 1117 keys[num_keys].key = va_arg(ap, char *);
1116 if (keys[num_keys].repl == NULL) 1118 if (keys[num_keys].key == NULL)
1117 fatal("%s: NULL replacement", __func__); 1119 break;
1120 keys[num_keys].repl = va_arg(ap, char *);
1121 if (keys[num_keys].repl == NULL)
1122 fatal("%s: NULL replacement for token %s", __func__, keys[num_keys].key);
1123 }
1124 if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
1125 fatal("%s: too many keys", __func__);
1126 if (num_keys == 0)
1127 fatal("%s: percent expansion without token list",
1128 __func__);
1118 } 1129 }
1119 if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
1120 fatal("%s: too many keys", __func__);
1121 va_end(ap);
1122 1130
1123 /* Expand string */ 1131 /* Expand string */
1124 for (i = 0; *string != '\0'; string++) { 1132 for (i = 0; *string != '\0'; string++) {
1125 if (*string != '%') { 1133 /* Optionally process ${ENVIRONMENT} expansions. */
1134 if (dollar && string[0] == '$' && string[1] == '{') {
1135 string += 2; /* skip over '${' */
1136 if ((varend = strchr(string, '}')) == NULL) {
1137 error("%s: environment variable '%s' missing "
1138 "closing '}'", __func__, string);
1139 goto out;
1140 }
1141 len = varend - string;
1142 if (len == 0) {
1143 error("%s: zero-length environment variable",
1144 __func__);
1145 goto out;
1146 }
1147 var = xmalloc(len + 1);
1148 (void)strlcpy(var, string, len + 1);
1149 if ((val = getenv(var)) == NULL) {
1150 error("%s: env var ${%s} has no value",
1151 __func__, var);
1152 missingvar = 1;
1153 } else {
1154 debug3("%s: expand ${%s} -> '%s'", __func__,
1155 var, val);
1156 if ((r = sshbuf_put(buf, val, strlen(val))) !=0)
1157 fatal("%s: sshbuf_put: %s", __func__,
1158 ssh_err(r));
1159 }
1160 free(var);
1161 string += len;
1162 continue;
1163 }
1164
1165 /*
1166 * Process percent expansions if we have a list of TOKENs.
1167 * If we're not doing percent expansion everything just gets
1168 * appended here.
1169 */
1170 if (*string != '%' || !percent) {
1126 append: 1171 append:
1127 if ((r = sshbuf_put_u8(buf, *string)) != 0) { 1172 if ((r = sshbuf_put_u8(buf, *string)) != 0) {
1128 fatal("%s: sshbuf_put_u8: %s", 1173 fatal("%s: sshbuf_put_u8: %s",
@@ -1134,8 +1179,10 @@ percent_expand(const char *string, ...)
1134 /* %% case */ 1179 /* %% case */
1135 if (*string == '%') 1180 if (*string == '%')
1136 goto append; 1181 goto append;
1137 if (*string == '\0') 1182 if (*string == '\0') {
1138 fatal("%s: invalid format", __func__); 1183 error("%s: invalid format", __func__);
1184 goto out;
1185 }
1139 for (i = 0; i < num_keys; i++) { 1186 for (i = 0; i < num_keys; i++) {
1140 if (strchr(keys[i].key, *string) != NULL) { 1187 if (strchr(keys[i].key, *string) != NULL) {
1141 if ((r = sshbuf_put(buf, keys[i].repl, 1188 if ((r = sshbuf_put(buf, keys[i].repl,
@@ -1146,16 +1193,72 @@ percent_expand(const char *string, ...)
1146 break; 1193 break;
1147 } 1194 }
1148 } 1195 }
1149 if (i >= num_keys) 1196 if (i >= num_keys) {
1150 fatal("%s: unknown key %%%c", __func__, *string); 1197 error("%s: unknown key %%%c", __func__, *string);
1198 goto out;
1199 }
1151 } 1200 }
1152 if ((ret = sshbuf_dup_string(buf)) == NULL) 1201 if (!missingvar && (ret = sshbuf_dup_string(buf)) == NULL)
1153 fatal("%s: sshbuf_dup_string failed", __func__); 1202 fatal("%s: sshbuf_dup_string failed", __func__);
1203 *parseerror = 0;
1204 out:
1154 sshbuf_free(buf); 1205 sshbuf_free(buf);
1155 return ret; 1206 return *parseerror ? NULL : ret;
1156#undef EXPAND_MAX_KEYS 1207#undef EXPAND_MAX_KEYS
1157} 1208}
1158 1209
1210char *
1211dollar_expand(int *parseerr, const char *string)
1212{
1213 char *ret;
1214 int err;
1215 va_list ap;
1216
1217 memset(ap, 0, sizeof(ap)); /* unused */
1218 ret = vdollar_percent_expand(&err, 1, 0, string, ap);
1219 if (parseerr != NULL)
1220 *parseerr = err;
1221 return ret;
1222}
1223
1224/*
1225 * Returns expanded string or NULL if a specified environment variable is
1226 * not defined, or calls fatal if the string is invalid.
1227 */
1228char *
1229percent_expand(const char *string, ...)
1230{
1231 char *ret;
1232 int err;
1233 va_list ap;
1234
1235 va_start(ap, string);
1236 ret = vdollar_percent_expand(&err, 0, 1, string, ap);
1237 va_end(ap);
1238 if (err)
1239 fatal("%s failed", __func__);
1240 return ret;
1241}
1242
1243/*
1244 * Returns expanded string or NULL if a specified environment variable is
1245 * not defined, or calls fatal if the string is invalid.
1246 */
1247char *
1248percent_dollar_expand(const char *string, ...)
1249{
1250 char *ret;
1251 int err;
1252 va_list ap;
1253
1254 va_start(ap, string);
1255 ret = vdollar_percent_expand(&err, 1, 1, string, ap);
1256 va_end(ap);
1257 if (err)
1258 fatal("%s failed", __func__);
1259 return ret;
1260}
1261
1159int 1262int
1160tun_open(int tun, int mode, char **ifname) 1263tun_open(int tun, int mode, char **ifname)
1161{ 1264{