version 1.149, 2020/05/29 01:20:46 |
version 1.150, 2020/05/29 04:25:40 |
|
|
} |
} |
|
|
/* |
/* |
* Expand a string with a set of %[char] escapes. A number of escapes may be |
* Expand a string with a set of %[char] escapes and/or ${ENVIRONMENT} |
* specified as (char *escape_chars, char *replacement) pairs. The list must |
* substitutions. A number of escapes may be specified as |
* be terminated by a NULL escape_char. Returns replaced string in memory |
* (char *escape_chars, char *replacement) pairs. The list must be terminated |
* allocated by xmalloc. |
* by a NULL escape_char. Returns replaced string in memory allocated by |
|
* xmalloc which the caller must free. |
*/ |
*/ |
char * |
static char * |
percent_expand(const char *string, ...) |
vdollar_percent_expand(int *parseerror, int dollar, int percent, |
|
const char *string, va_list ap) |
{ |
{ |
#define EXPAND_MAX_KEYS 16 |
#define EXPAND_MAX_KEYS 16 |
u_int num_keys, i; |
u_int num_keys = 0, i; |
struct { |
struct { |
const char *key; |
const char *key; |
const char *repl; |
const char *repl; |
} keys[EXPAND_MAX_KEYS]; |
} keys[EXPAND_MAX_KEYS]; |
struct sshbuf *buf; |
struct sshbuf *buf; |
va_list ap; |
int r, missingvar = 0; |
int r; |
char *ret = NULL, *var, *varend, *val; |
char *ret; |
size_t len; |
|
|
if ((buf = sshbuf_new()) == NULL) |
if ((buf = sshbuf_new()) == NULL) |
fatal("%s: sshbuf_new failed", __func__); |
fatal("%s: sshbuf_new failed", __func__); |
|
if (parseerror == NULL) |
|
fatal("%s: null parseerror arg", __func__); |
|
*parseerror = 1; |
|
|
/* Gather keys */ |
/* Gather keys if we're doing percent expansion. */ |
va_start(ap, string); |
if (percent) { |
for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { |
for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { |
keys[num_keys].key = va_arg(ap, char *); |
keys[num_keys].key = va_arg(ap, char *); |
if (keys[num_keys].key == NULL) |
if (keys[num_keys].key == NULL) |
break; |
break; |
keys[num_keys].repl = va_arg(ap, char *); |
keys[num_keys].repl = va_arg(ap, char *); |
if (keys[num_keys].repl == NULL) |
if (keys[num_keys].repl == NULL) |
fatal("%s: NULL replacement", __func__); |
fatal("%s: NULL replacement for token %s", __func__, keys[num_keys].key); |
|
} |
|
if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL) |
|
fatal("%s: too many keys", __func__); |
|
if (num_keys == 0) |
|
fatal("%s: percent expansion without token list", |
|
__func__); |
} |
} |
if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL) |
|
fatal("%s: too many keys", __func__); |
|
va_end(ap); |
|
|
|
/* Expand string */ |
/* Expand string */ |
for (i = 0; *string != '\0'; string++) { |
for (i = 0; *string != '\0'; string++) { |
if (*string != '%') { |
/* Optionally process ${ENVIRONMENT} expansions. */ |
|
if (dollar && string[0] == '$' && string[1] == '{') { |
|
string += 2; /* skip over '${' */ |
|
if ((varend = strchr(string, '}')) == NULL) { |
|
error("%s: environment variable '%s' missing " |
|
"closing '}'", __func__, string); |
|
goto out; |
|
} |
|
len = varend - string; |
|
if (len == 0) { |
|
error("%s: zero-length environment variable", |
|
__func__); |
|
goto out; |
|
} |
|
var = xmalloc(len + 1); |
|
(void)strlcpy(var, string, len + 1); |
|
if ((val = getenv(var)) == NULL) { |
|
error("%s: env var ${%s} has no value", |
|
__func__, var); |
|
missingvar = 1; |
|
} else { |
|
debug3("%s: expand ${%s} -> '%s'", __func__, |
|
var, val); |
|
if ((r = sshbuf_put(buf, val, strlen(val))) !=0) |
|
fatal("%s: sshbuf_put: %s", __func__, |
|
ssh_err(r)); |
|
} |
|
free(var); |
|
string += len; |
|
continue; |
|
} |
|
|
|
/* |
|
* Process percent expansions if we have a list of TOKENs. |
|
* If we're not doing percent expansion everything just gets |
|
* appended here. |
|
*/ |
|
if (*string != '%' || !percent) { |
append: |
append: |
if ((r = sshbuf_put_u8(buf, *string)) != 0) { |
if ((r = sshbuf_put_u8(buf, *string)) != 0) { |
fatal("%s: sshbuf_put_u8: %s", |
fatal("%s: sshbuf_put_u8: %s", |
|
|
/* %% case */ |
/* %% case */ |
if (*string == '%') |
if (*string == '%') |
goto append; |
goto append; |
if (*string == '\0') |
if (*string == '\0') { |
fatal("%s: invalid format", __func__); |
error("%s: invalid format", __func__); |
|
goto out; |
|
} |
for (i = 0; i < num_keys; i++) { |
for (i = 0; i < num_keys; i++) { |
if (strchr(keys[i].key, *string) != NULL) { |
if (strchr(keys[i].key, *string) != NULL) { |
if ((r = sshbuf_put(buf, keys[i].repl, |
if ((r = sshbuf_put(buf, keys[i].repl, |
|
|
break; |
break; |
} |
} |
} |
} |
if (i >= num_keys) |
if (i >= num_keys) { |
fatal("%s: unknown key %%%c", __func__, *string); |
error("%s: unknown key %%%c", __func__, *string); |
|
goto out; |
|
} |
} |
} |
if ((ret = sshbuf_dup_string(buf)) == NULL) |
if (!missingvar && (ret = sshbuf_dup_string(buf)) == NULL) |
fatal("%s: sshbuf_dup_string failed", __func__); |
fatal("%s: sshbuf_dup_string failed", __func__); |
|
*parseerror = 0; |
|
out: |
sshbuf_free(buf); |
sshbuf_free(buf); |
return ret; |
return *parseerror ? NULL : ret; |
#undef EXPAND_MAX_KEYS |
#undef EXPAND_MAX_KEYS |
|
} |
|
|
|
char * |
|
dollar_expand(int *parseerr, const char *string) |
|
{ |
|
char *ret; |
|
int err; |
|
va_list ap; |
|
|
|
memset(ap, 0, sizeof(ap)); /* unused */ |
|
ret = vdollar_percent_expand(&err, 1, 0, string, ap); |
|
if (parseerr != NULL) |
|
*parseerr = err; |
|
return ret; |
|
} |
|
|
|
/* |
|
* Returns expanded string or NULL if a specified environment variable is |
|
* not defined, or calls fatal if the string is invalid. |
|
*/ |
|
char * |
|
percent_expand(const char *string, ...) |
|
{ |
|
char *ret; |
|
int err; |
|
va_list ap; |
|
|
|
va_start(ap, string); |
|
ret = vdollar_percent_expand(&err, 0, 1, string, ap); |
|
va_end(ap); |
|
if (err) |
|
fatal("%s failed", __func__); |
|
return ret; |
|
} |
|
|
|
/* |
|
* Returns expanded string or NULL if a specified environment variable is |
|
* not defined, or calls fatal if the string is invalid. |
|
*/ |
|
char * |
|
percent_dollar_expand(const char *string, ...) |
|
{ |
|
char *ret; |
|
int err; |
|
va_list ap; |
|
|
|
va_start(ap, string); |
|
ret = vdollar_percent_expand(&err, 1, 1, string, ap); |
|
va_end(ap); |
|
if (err) |
|
fatal("%s failed", __func__); |
|
return ret; |
} |
} |
|
|
int |
int |