diff options
Diffstat (limited to '')
-rw-r--r-- | readconf.c | 165 |
1 files changed, 102 insertions, 63 deletions
@@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.383 2023/10/12 02:18:18 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.386 2024/03/04 04:13:18 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -890,6 +890,20 @@ parse_token(const char *cp, const char *filename, int linenum, return oBadOption; } +static void +free_canon_cnames(struct allowed_cname *cnames, u_int n) +{ + u_int i; + + if (cnames == NULL || n == 0) + return; + for (i = 0; i < n; i++) { + free(cnames[i].source_list); + free(cnames[i].target_list); + } + free(cnames); +} + /* Multistate option parsing */ struct multistate { char *key; @@ -1032,21 +1046,24 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, { char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p; char **cpptr, ***cppptr, fwdarg[256]; - u_int i, *uintptr, uvalue, max_entries = 0; + u_int i, *uintptr, max_entries = 0; int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0; - int remotefwd, dynamicfwd, ca_only = 0; + int remotefwd, dynamicfwd, ca_only = 0, found = 0; LogLevel *log_level_ptr; SyslogFacility *log_facility_ptr; long long val64; size_t len; struct Forward fwd; const struct multistate *multistate_ptr; - struct allowed_cname *cname; glob_t gl; const char *errstr; char **oav = NULL, **av; int oac = 0, ac; int ret = -1; + struct allowed_cname *cnames = NULL; + u_int ncnames = 0; + char **strs = NULL; /* string array arguments; freed implicitly */ + u_int nstrs = 0; if (activep == NULL) { /* We are processing a command line directive */ cmdline = 1; @@ -1662,14 +1679,13 @@ parse_pubkey_algos: case oPermitRemoteOpen: uintptr = &options->num_permitted_remote_opens; cppptr = &options->permitted_remote_opens; - uvalue = *uintptr; /* modified later */ - i = 0; + found = *uintptr == 0; while ((arg = argv_next(&ac, &av)) != NULL) { arg2 = xstrdup(arg); /* Allow any/none only in first position */ if (strcasecmp(arg, "none") == 0 || strcasecmp(arg, "any") == 0) { - if (i > 0 || ac > 0) { + if (nstrs > 0 || ac > 0) { error("%s line %d: keyword %s \"%s\" " "argument must appear alone.", filename, linenum, keyword, arg); @@ -1695,17 +1711,20 @@ parse_pubkey_algos: lookup_opcode_name(opcode)); } } - if (*activep && uvalue == 0) { - opt_array_append(filename, linenum, - lookup_opcode_name(opcode), - cppptr, uintptr, arg2); - } + opt_array_append(filename, linenum, + lookup_opcode_name(opcode), + &strs, &nstrs, arg2); free(arg2); - i++; } - if (i == 0) + if (nstrs == 0) fatal("%s line %d: missing %s specification", filename, linenum, lookup_opcode_name(opcode)); + if (found && *activep) { + *cppptr = strs; + *uintptr = nstrs; + strs = NULL; /* transferred */ + nstrs = 0; + } break; case oClearAllForwardings: @@ -1823,12 +1842,14 @@ parse_pubkey_algos: goto parse_int; case oSendEnv: + /* XXX appends to list; doesn't respect first-match-wins */ while ((arg = argv_next(&ac, &av)) != NULL) { if (*arg == '\0' || strchr(arg, '=') != NULL) { error("%s line %d: Invalid environment name.", filename, linenum); goto out; } + found = 1; if (!*activep) continue; if (*arg == '-') { @@ -1840,27 +1861,38 @@ parse_pubkey_algos: lookup_opcode_name(opcode), &options->send_env, &options->num_send_env, arg); } + if (!found) { + fatal("%s line %d: no %s specified", + filename, linenum, keyword); + } break; case oSetEnv: - value = options->num_setenv; + found = options->num_setenv == 0; while ((arg = argv_next(&ac, &av)) != NULL) { if (strchr(arg, '=') == NULL) { error("%s line %d: Invalid SetEnv.", filename, linenum); goto out; } - if (!*activep || value != 0) - continue; - if (lookup_setenv_in_list(arg, options->setenv, - options->num_setenv) != NULL) { + if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) { debug2("%s line %d: ignoring duplicate env " "name \"%.64s\"", filename, linenum, arg); continue; } opt_array_append(filename, linenum, lookup_opcode_name(opcode), - &options->setenv, &options->num_setenv, arg); + &strs, &nstrs, arg); + } + if (nstrs == 0) { + fatal("%s line %d: no %s specified", + filename, linenum, keyword); + } + if (found && *activep) { + options->setenv = strs; + options->num_setenv = nstrs; + strs = NULL; /* transferred */ + nstrs = 0; } break; @@ -2069,52 +2101,46 @@ parse_pubkey_algos: goto parse_flag; case oCanonicalDomains: - value = options->num_canonical_domains != 0; - i = 0; + found = options->num_canonical_domains == 0; while ((arg = argv_next(&ac, &av)) != NULL) { - if (*arg == '\0') { - error("%s line %d: keyword %s empty argument", - filename, linenum, keyword); - goto out; - } /* Allow "none" only in first position */ if (strcasecmp(arg, "none") == 0) { - if (i > 0 || ac > 0) { + if (nstrs > 0 || ac > 0) { error("%s line %d: keyword %s \"none\" " "argument must appear alone.", filename, linenum, keyword); goto out; } } - i++; if (!valid_domain(arg, 1, &errstr)) { error("%s line %d: %s", filename, linenum, errstr); goto out; } - if (!*activep || value) - continue; - if (options->num_canonical_domains >= - MAX_CANON_DOMAINS) { - error("%s line %d: too many hostname suffixes.", - filename, linenum); - goto out; - } - options->canonical_domains[ - options->num_canonical_domains++] = xstrdup(arg); + opt_array_append(filename, linenum, keyword, + &strs, &nstrs, arg); + } + if (nstrs == 0) { + fatal("%s line %d: no %s specified", + filename, linenum, keyword); + } + if (found && *activep) { + options->canonical_domains = strs; + options->num_canonical_domains = nstrs; + strs = NULL; /* transferred */ + nstrs = 0; } break; case oCanonicalizePermittedCNAMEs: - value = options->num_permitted_cnames != 0; - i = 0; + found = options->num_permitted_cnames == 0; while ((arg = argv_next(&ac, &av)) != NULL) { /* * Either 'none' (only in first position), '*' for * everything or 'list:list' */ if (strcasecmp(arg, "none") == 0) { - if (i > 0 || ac > 0) { + if (ncnames > 0 || ac > 0) { error("%s line %d: keyword %s \"none\" " "argument must appear alone.", filename, linenum, keyword); @@ -2135,20 +2161,23 @@ parse_pubkey_algos: *arg2 = '\0'; arg2++; } - i++; - if (!*activep || value) - continue; - if (options->num_permitted_cnames >= - MAX_CANON_DOMAINS) { - error("%s line %d: too many permitted CNAMEs.", - filename, linenum); - goto out; - } - cname = options->permitted_cnames + - options->num_permitted_cnames++; - cname->source_list = xstrdup(arg); - cname->target_list = xstrdup(arg2); - } + cnames = xrecallocarray(cnames, ncnames, ncnames + 1, + sizeof(*cnames)); + cnames[ncnames].source_list = xstrdup(arg); + cnames[ncnames].target_list = xstrdup(arg2); + ncnames++; + } + if (ncnames == 0) { + fatal("%s line %d: no %s specified", + filename, linenum, keyword); + } + if (found && *activep) { + options->permitted_cnames = cnames; + options->num_permitted_cnames = ncnames; + cnames = NULL; /* transferred */ + ncnames = 0; + } + /* un-transferred cnames is cleaned up before exit */ break; case oCanonicalizeHostname: @@ -2329,12 +2358,11 @@ parse_pubkey_algos: break; case oChannelTimeout: - uvalue = options->num_channel_timeouts; - i = 0; + found = options->num_channel_timeouts == 0; while ((arg = argv_next(&ac, &av)) != NULL) { /* Allow "none" only in first position */ if (strcasecmp(arg, "none") == 0) { - if (i > 0 || ac > 0) { + if (nstrs > 0 || ac > 0) { error("%s line %d: keyword %s \"none\" " "argument must appear alone.", filename, linenum, keyword); @@ -2345,11 +2373,18 @@ parse_pubkey_algos: fatal("%s line %d: invalid channel timeout %s", filename, linenum, arg); } - if (!*activep || uvalue != 0) - continue; opt_array_append(filename, linenum, keyword, - &options->channel_timeouts, - &options->num_channel_timeouts, arg); + &strs, &nstrs, arg); + } + if (nstrs == 0) { + fatal("%s line %d: no %s specified", + filename, linenum, keyword); + } + if (found && *activep) { + options->channel_timeouts = strs; + options->num_channel_timeouts = nstrs; + strs = NULL; /* transferred */ + nstrs = 0; } break; @@ -2381,6 +2416,8 @@ parse_pubkey_algos: /* success */ ret = 0; out: + free_canon_cnames(cnames, ncnames); + opt_array_free2(strs, NULL, nstrs); argv_free(oav, oac); return ret; } @@ -2711,7 +2748,9 @@ fill_default_options(Options * options) add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ED25519_SK, 0); add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0); +#ifdef WITH_DSA add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0); +#endif } if (options->escape_char == -1) options->escape_char = '~'; |