@@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.355 2021/06/08 07:02:46 dtucker Exp $ */
/* $OpenBSD: readconf.c,v 1.356 2021/06/08 07:07:15 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -603,25 +603,33 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
debug2 (" checking match for '%s ' host %s originally %s " ,
cp, host, original_host);
while ((oattrib = attrib = strdelim (&cp)) && *attrib != ' \0 ' ) {
criteria = NULL ;
/* Terminate on comment */
if (*attrib == ' #' ) {
cp = NULL ; /* mark all arguments consumed */
break ;
}
arg = criteria = NULL ;
this_result = 1 ;
if ((negate = attrib[0 ] == ' !' ))
attrib++;
/* criteria "all" and "canonical" have no argument */
/* Criterion "all" has no argument and must appear alone */
if (strcasecmp (attrib, " all" ) == 0 ) {
if (attributes > 1 ||
(( arg = strdelim (&cp)) != NULL && *arg != ' \0 ' )) {
if (attributes > 1 || ((arg = strdelim (&cp)) != NULL &&
* arg != ' \0 ' && *arg != ' # ' )) {
error (" %.200s line %d : '%s ' cannot be combined "
" with other Match attributes" ,
filename, linenum, oattrib);
result = -1 ;
goto out;
}
if (arg != NULL && *arg == ' #' )
cp = NULL ; /* mark all arguments consumed */
if (result)
result = negate ? 0 : 1 ;
goto out;
}
attributes++;
/* criteria "final" and "canonical" have no argument */
if (strcasecmp (attrib, " canonical" ) == 0 ||
strcasecmp (attrib, " final" ) == 0 ) {
/*
@@ -640,7 +648,8 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
continue ;
}
/* All other criteria require an argument */
if ((arg = strdelim (&cp)) == NULL || *arg == ' \0 ' ) {
if ((arg = strdelim (&cp)) == NULL ||
*arg == ' \0 ' || *arg == ' #' ) {
error (" Missing Match criteria for %s " , attrib);
result = -1 ;
goto out;
@@ -915,7 +924,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
const char *original_host, char *line, const char *filename,
int linenum, int *activep, int flags, int *want_final_pass, int depth)
{
char *s , **charptr, *endofnumber, *keyword, *arg, *arg2, *p, ch;
char *str , **charptr, *endofnumber, *keyword, *arg, *arg2, *p, ch;
char **cpptr, ***cppptr, fwdarg[256 ];
u_int i, *uintptr, uvalue, max_entries = 0 ;
int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0 ;
@@ -929,6 +938,9 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
struct allowed_cname *cname;
glob_t gl;
const char *errstr;
char **oav = NULL , **av;
int oac = 0 , ac;
int ret = -1 ;
if (activep == NULL ) { /* We are processing a command line directive */
cmdline = 1 ;
@@ -944,46 +956,62 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
line[len] = ' \0 ' ;
}
s = line;
str = line;
/* Get the keyword. (Each line is supposed to begin with a keyword). */
if ((keyword = strdelim (&s )) == NULL )
if ((keyword = strdelim (&str )) == NULL )
return 0 ;
/* Ignore leading whitespace. */
if (*keyword == ' \0 ' )
keyword = strdelim (&s );
keyword = strdelim (&str );
if (keyword == NULL || !*keyword || *keyword == ' \n ' || *keyword == ' #' )
return 0 ;
/* Match lowercase keyword */
lowercase (keyword);
/* Prepare to parse remainder of line */
if (str != NULL )
str += strspn (str, WHITESPACE);
if (str == NULL || *str == ' \0 ' ) {
error (" %s line %d : no argument after keyword \" %s \" " ,
filename, linenum, keyword);
return -1 ;
}
opcode = parse_token (keyword, filename, linenum,
options->ignored_unknown );
if (argv_split (str, &oac, &oav, 1 ) != 0 ) {
error (" %s line %d : invalid quotes" , filename, linenum);
return -1 ;
}
ac = oac;
av = oav;
switch (opcode) {
case oBadOption:
/* don't panic, but count bad options */
return - 1 ;
goto out ;
case oIgnore:
return 0 ;
argv_consume (&ac);
break ;
case oIgnoredUnknownOption:
debug (" %s line %d : Ignored unknown option \" %s \" " ,
filename, linenum, keyword);
return 0 ;
argv_consume (&ac);
break ;
case oConnectTimeout:
intptr = &options->connection_timeout ;
parse_time:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %s line %d : missing time value." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (strcmp (arg, " none" ) == 0 )
value = -1 ;
else if ((value = convtime (arg)) == -1 ) {
error (" %s line %d : invalid time value." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*activep && *intptr == -1 )
*intptr = value;
@@ -992,11 +1020,11 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oForwardAgent:
intptr = &options->forward_agent ;
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %s line %d : missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
value = -1 ;
@@ -1024,12 +1052,12 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
parse_flag:
multistate_ptr = multistate_flag;
parse_multistate:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if ((value = parse_multistate_value (arg, filename, linenum,
multistate_ptr)) == -1 ) {
error (" %s line %d : unsupported option \" %s \" ." ,
filename, linenum, arg);
return - 1 ;
goto out ;
}
if (*activep && *intptr == -1 )
*intptr = value;
@@ -1119,31 +1147,31 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
goto parse_int;
case oRekeyLimit:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." , filename,
linenum);
return - 1 ;
goto out ;
}
if (strcmp (arg, " default" ) == 0 ) {
val64 = 0 ;
} else {
if (scan_scaled (arg, &val64) == -1 ) {
error (" %.200s line %d : Bad number '%s ': %s " ,
filename, linenum, arg, strerror (errno));
return - 1 ;
goto out ;
}
if (val64 != 0 && val64 < 16 ) {
error (" %.200s line %d : RekeyLimit too small" ,
filename, linenum);
return - 1 ;
goto out ;
}
}
if (*activep && options->rekey_limit == -1 )
options->rekey_limit = val64;
if (s != NULL ) { /* optional rekey interval present */
if (strcmp (s , " none" ) == 0 ) {
(void )strdelim (&s ); /* discard */
if (ac != 0 ) { /* optional rekey interval present */
if (strcmp (av[ 0 ] , " none" ) == 0 ) {
(void )argv_next (&ac, &av ); /* discard */
break ;
}
intptr = &options->rekey_interval ;
@@ -1152,31 +1180,31 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
break ;
case oIdentityFile:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*activep) {
intptr = &options->num_identity_files ;
if (*intptr >= SSH_MAX_IDENTITY_FILES) {
error (" %.200s line %d : Too many identity files "
" specified (max %d )." , filename, linenum,
SSH_MAX_IDENTITY_FILES);
return - 1 ;
goto out ;
}
add_identity_file (options, NULL ,
arg, flags & SSHCONF_USERCONF);
}
break ;
case oCertificateFile:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*activep) {
intptr = &options->num_certificate_files ;
@@ -1185,7 +1213,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
" files specified (max %d )." ,
filename, linenum,
SSH_MAX_CERTIFICATE_FILES);
return - 1 ;
goto out ;
}
add_certificate_file (options, arg,
flags & SSHCONF_USERCONF);
@@ -1199,11 +1227,11 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oUser:
charptr = &options->user ;
parse_string:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*activep && *charptr == NULL )
*charptr = xstrdup (arg);
@@ -1214,17 +1242,34 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
uintptr = &options->num_system_hostfiles ;
max_entries = SSH_MAX_HOSTS_FILES;
parse_char_array:
if (*activep && *uintptr == 0 ) {
while ((arg = strdelim (&s)) != NULL && *arg != ' \0 ' ) {
i = 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 ) {
error (" %s line %d : keyword %s \" none\" "
" argument must appear alone." ,
filename, linenum, keyword);
goto out;
}
}
i++;
if (*activep && *uintptr == 0 ) {
if ((*uintptr) >= max_entries) {
error (" %s line %d : too many known "
" hosts files." , filename, linenum);
return -1 ;
error (" %s line %d : too many %s "
" entries." , filename, linenum,
keyword);
goto out;
}
cpptr[(*uintptr)++] = xstrdup (arg);
}
}
return 0 ;
break ;
case oUserKnownHostsFile:
cpptr = (char **)&options->user_hostfiles ;
@@ -1270,42 +1315,45 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
if (options->jump_host != NULL )
charptr = &options->jump_host ; /* Skip below */
parse_command:
if (s == NULL ) {
if (str == NULL ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
len = strspn (s , WHITESPACE " =" );
len = strspn (str , WHITESPACE " =" );
if (*activep && *charptr == NULL )
*charptr = xstrdup (s + len);
return 0 ;
*charptr = xstrdup (str + len);
argv_consume (&ac);
break ;
case oProxyJump:
if (s == NULL ) {
if (str == NULL ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
len = strspn (s, WHITESPACE " =" );
if (parse_jump (s + len, options, *activep) == -1 ) {
len = strspn (str, WHITESPACE " =" );
/* XXX use argv? */
if (parse_jump (str + len, options, *activep) == -1 ) {
error (" %.200s line %d : Invalid ProxyJump \" %s \" " ,
filename, linenum, s + len);
return - 1 ;
filename, linenum, str + len);
goto out ;
}
return 0 ;
argv_consume (&ac);
break ;
case oPort:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
value = a2port (arg);
if (value <= 0 ) {
error (" %.200s line %d : Bad port '%s '." ,
filename, linenum, arg);
return - 1 ;
goto out ;
}
if (*activep && options->port == -1 )
options->port = value;
@@ -1314,63 +1362,63 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oConnectionAttempts:
intptr = &options->connection_attempts ;
parse_int:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if ((errstr = atoi_err (arg, &value)) != NULL ) {
error (" %s line %d : integer value %s ." ,
filename, linenum, errstr);
return - 1 ;
goto out ;
}
if (*activep && *intptr == -1 )
*intptr = value;
break ;
case oCiphers:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*arg != ' -' &&
!ciphers_valid (*arg == ' +' || *arg == ' ^' ? arg + 1 : arg)){
error (" %.200s line %d : Bad SSH2 cipher spec '%s '." ,
filename, linenum, arg ? arg : " <NONE>" );
return - 1 ;
goto out ;
}
if (*activep && options->ciphers == NULL )
options->ciphers = xstrdup (arg);
break ;
case oMacs:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*arg != ' -' &&
!mac_valid (*arg == ' +' || *arg == ' ^' ? arg + 1 : arg)) {
error (" %.200s line %d : Bad SSH2 MAC spec '%s '." ,
filename, linenum, arg ? arg : " <NONE>" );
return - 1 ;
goto out ;
}
if (*activep && options->macs == NULL )
options->macs = xstrdup (arg);
break ;
case oKexAlgorithms:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*arg != ' -' &&
!kex_names_valid (*arg == ' +' || *arg == ' ^' ?
arg + 1 : arg)) {
error (" %.200s line %d : Bad SSH2 KexAlgorithms '%s '." ,
filename, linenum, arg ? arg : " <NONE>" );
return - 1 ;
goto out ;
}
if (*activep && options->kex_algorithms == NULL )
options->kex_algorithms = xstrdup (arg);
@@ -1379,18 +1427,18 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oHostKeyAlgorithms:
charptr = &options->hostkeyalgorithms ;
parse_pubkey_algos:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*arg != ' -' &&
!sshkey_names_valid2 (*arg == ' +' || *arg == ' ^' ?
arg + 1 : arg, 1 )) {
error (" %s line %d : Bad key types '%s '." ,
filename, linenum, arg ? arg : " <NONE>" );
return - 1 ;
goto out ;
}
if (*activep && *charptr == NULL )
*charptr = xstrdup (arg);
@@ -1402,25 +1450,25 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oLogLevel:
log_level_ptr = &options->log_level ;
arg = strdelim (&s );
arg = argv_next (&ac, &av );
value = log_level_number (arg);
if (value == SYSLOG_LEVEL_NOT_SET) {
error (" %.200s line %d : unsupported log level '%s '" ,
filename, linenum, arg ? arg : " <NONE>" );
return - 1 ;
goto out ;
}
if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
*log_level_ptr = (LogLevel) value;
break ;
case oLogFacility:
log_facility_ptr = &options->log_facility ;
arg = strdelim (&s );
arg = argv_next (&ac, &av );
value = log_facility_number (arg);
if (value == SYSLOG_FACILITY_NOT_SET) {
error (" %.200s line %d : unsupported log facility '%s '" ,
filename, linenum, arg ? arg : " <NONE>" );
return - 1 ;
goto out ;
}
if (*log_facility_ptr == -1 )
*log_facility_ptr = (SyslogFacility) value;
@@ -1429,37 +1477,53 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oLogVerbose:
cppptr = &options->log_verbose ;
uintptr = &options->num_log_verbose ;
if (*activep && *uintptr == 0 ) {
while ((arg = strdelim (&s)) != NULL && *arg != ' \0 ' ) {
i = 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 ) {
error (" %s line %d : keyword %s \" none\" "
" argument must appear alone." ,
filename, linenum, keyword);
goto out;
}
}
i++;
if (*activep && *uintptr == 0 ) {
*cppptr = xrecallocarray (*cppptr, *uintptr,
*uintptr + 1 , sizeof (**cppptr));
(*cppptr)[(*uintptr)++] = xstrdup (arg);
}
}
return 0 ;
break ;
case oLocalForward:
case oRemoteForward:
case oDynamicForward:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
remotefwd = (opcode == oRemoteForward);
dynamicfwd = (opcode == oDynamicForward);
if (!dynamicfwd) {
arg2 = strdelim (&s );
arg2 = argv_next (&ac, &av );
if (arg2 == NULL || *arg2 == ' \0 ' ) {
if (remotefwd)
dynamicfwd = 1 ;
else {
error (" %.200s line %d : Missing target "
" argument." , filename, linenum);
return - 1 ;
goto out ;
}
} else {
/* construct a string for parse_forward */
@@ -1473,7 +1537,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
if (parse_forward (&fwd, fwdarg, dynamicfwd, remotefwd) == 0 ) {
error (" %.200s line %d : Bad forwarding specification." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*activep) {
@@ -1488,7 +1552,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oPermitRemoteOpen:
uintptr = &options->num_permitted_remote_opens ;
cppptr = &options->permitted_remote_opens ;
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' )
fatal (" %s line %d : missing %s specification" ,
filename, linenum, lookup_opcode_name (opcode));
@@ -1501,7 +1565,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
}
break ;
}
for (; arg != NULL && *arg != ' \0 ' ; arg = strdelim (&s) ) {
while (( arg = argv_next (&ac, &av)) != NULL ) {
arg2 = xstrdup (arg);
ch = ' \0 ' ;
p = hpdelim2 (&arg, &ch);
@@ -1538,13 +1602,20 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
if (cmdline) {
error (" Host directive not supported as a command-line "
" option" );
return - 1 ;
goto out ;
}
*activep = 0 ;
arg2 = NULL ;
while ((arg = strdelim (&s)) != NULL && *arg != ' \0 ' ) {
if ((flags & SSHCONF_NEVERMATCH) != 0 )
while ((arg = argv_next (&ac, &av)) != NULL ) {
if (*arg == ' \0 ' ) {
error (" %s line %d : keyword %s empty argument" ,
filename, linenum, keyword);
goto out;
}
if ((flags & SSHCONF_NEVERMATCH) != 0 ) {
argv_consume (&ac);
break ;
}
negated = *arg == ' !' ;
if (negated)
arg++;
@@ -1555,6 +1626,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
" for %.100s " , filename, linenum,
arg);
*activep = 0 ;
argv_consume (&ac);
break ;
}
if (!*activep)
@@ -1565,33 +1637,39 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
if (*activep)
debug (" %.200s line %d : Applying options for %.100s " ,
filename, linenum, arg2);
/* Avoid garbage check below, as strdelim is done. */
return 0 ;
break ;
case oMatch:
if (cmdline) {
error (" Host directive not supported as a command-line "
" option" );
return - 1 ;
goto out ;
}
value = match_cfg_line (options, &s , pw, host, original_host,
value = match_cfg_line (options, &str , pw, host, original_host,
flags & SSHCONF_FINAL, want_final_pass,
filename, linenum);
if (value < 0 ) {
error (" %.200s line %d : Bad Match condition" , filename,
linenum);
return - 1 ;
goto out ;
}
*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
/*
* If match_cfg_line() didn't consume all its arguments then
* arrange for the extra arguments check below to fail.
*/
if (str == NULL || *str == ' \0 ' )
argv_consume (&ac);
break ;
case oEscapeChar:
intptr = &options->escape_char ;
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (strcmp (arg, " none" ) == 0 )
value = SSH_ESCAPECHAR_NONE;
@@ -1603,7 +1681,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
else {
error (" %.200s line %d : Bad escape character." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*activep && *intptr == -1 )
*intptr = value;
@@ -1631,11 +1709,11 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
goto parse_int;
case oSendEnv:
while ((arg = strdelim (&s )) != NULL && *arg != ' \0 ' ) {
if (strchr (arg, ' =' ) != NULL ) {
while ((arg = argv_next (&ac, &av )) != NULL ) {
if (*arg == ' \0 ' || strchr (arg, ' =' ) != NULL ) {
error (" %s line %d : Invalid environment name." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (!*activep)
continue ;
@@ -1648,7 +1726,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
if (options->num_send_env >= INT_MAX) {
error (" %s line %d : too many send env." ,
filename, linenum);
return - 1 ;
goto out ;
}
options->send_env = xrecallocarray (
options->send_env , options->num_send_env ,
@@ -1662,19 +1740,19 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oSetEnv:
value = options->num_setenv ;
while ((arg = strdelimw (&s )) != NULL && *arg != ' \0 ' ) {
while ((arg = argv_next (&ac, &av )) != NULL ) {
if (strchr (arg, ' =' ) == NULL ) {
error (" %s line %d : Invalid SetEnv." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (!*activep || value != 0 )
continue ;
/* Adding a setenv var */
if (options->num_setenv >= INT_MAX) {
error (" %s line %d : too many SetEnv." ,
filename, linenum);
return - 1 ;
goto out ;
}
options->setenv = xrecallocarray (
options->setenv , options->num_setenv ,
@@ -1695,11 +1773,11 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oControlPersist:
/* no/false/yes/true, or a time spec */
intptr = &options->control_persist ;
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing ControlPersist"
" argument." , filename, linenum);
return - 1 ;
goto out ;
}
value = 0 ;
value2 = 0 ; /* timeout */
@@ -1712,7 +1790,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
else {
error (" %.200s line %d : Bad ControlPersist argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*activep && *intptr == -1 ) {
*intptr = value;
@@ -1730,17 +1808,17 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
goto parse_multistate;
case oTunnelDevice:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
value = a2tun (arg, &value2);
if (value == SSH_TUNID_ERR) {
error (" %.200s line %d : Bad tun device." ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*activep && options->tun_local == -1 ) {
options->tun_local = value;
@@ -1768,10 +1846,15 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
if (cmdline) {
error (" Include directive not supported as a "
" command-line option" );
return - 1 ;
goto out ;
}
value = 0 ;
while ((arg = strdelim (&s)) != NULL && *arg != ' \0 ' ) {
while ((arg = argv_next (&ac, &av)) != NULL ) {
if (*arg == ' \0 ' ) {
error (" %s line %d : keyword %s empty argument" ,
filename, linenum, keyword);
goto out;
}
/*
* Ensure all paths are anchored. User configuration
* files may begin with '~/' but system configurations
@@ -1782,7 +1865,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
if (*arg == ' ~' && (flags & SSHCONF_USERCONF) == 0 ) {
error (" %.200s line %d : bad include path %s ." ,
filename, linenum, arg);
return - 1 ;
goto out ;
}
if (!path_absolute (arg) && *arg != ' ~' ) {
xasprintf (&arg2, " %s /%s " ,
@@ -1800,7 +1883,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
} else if (r != 0 ) {
error (" %.200s line %d : glob failed for %s ." ,
filename, linenum, arg2);
return - 1 ;
goto out ;
}
free (arg2);
oactive = *activep;
@@ -1819,7 +1902,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
" %.100s : %.100s " , gl.gl_pathv [i],
strerror (errno));
globfree (&gl);
return - 1 ;
goto out ;
}
/*
* don't let Match in includes clobber the
@@ -1832,23 +1915,23 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
globfree (&gl);
}
if (value != 0 )
return value;
ret = value;
break ;
case oIPQoS:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if ((value = parse_ipqos (arg)) == -1 ) {
error (" %s line %d : Bad IPQoS value: %s " ,
filename, linenum, arg);
return - 1 ;
goto out ;
}
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (arg == NULL )
value2 = value;
else if ((value2 = parse_ipqos (arg)) == -1 ) {
error (" %s line %d : Bad IPQoS value: %s " ,
filename, linenum, arg);
return - 1 ;
goto out ;
}
if (*activep && options->ip_qos_interactive == -1 ) {
options->ip_qos_interactive = value;
@@ -1871,19 +1954,35 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oCanonicalDomains:
value = options->num_canonical_domains != 0 ;
while ((arg = strdelim (&s)) != NULL && *arg != ' \0 ' ) {
i = 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 ) {
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);
return - 1 ;
goto out ;
}
if (!*activep || value)
continue ;
if (options->num_canonical_domains >=
MAX_CANON_DOMAINS) {
error (" %s line %d : too many hostname suffixes." ,
filename, linenum);
return - 1 ;
goto out ;
}
options->canonical_domains [
options->num_canonical_domains ++] = xstrdup (arg);
@@ -1892,7 +1991,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oCanonicalizePermittedCNAMEs:
value = options->num_permitted_cnames != 0 ;
while ((arg = strdelim (&s )) != NULL && *arg != ' \0 ' ) {
while ((arg = argv_next (&ac, &av )) != NULL ) {
/* Either '*' for everything or 'list:list' */
if (strcmp (arg, " *" ) == 0 )
arg2 = arg;
@@ -1903,7 +2002,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
error (" %s line %d : "
" Invalid permitted CNAME \" %s \" " ,
filename, linenum, arg);
return - 1 ;
goto out ;
}
*arg2 = ' \0 ' ;
arg2++;
@@ -1914,7 +2013,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
MAX_CANON_DOMAINS) {
error (" %s line %d : too many permitted CNAMEs." ,
filename, linenum);
return - 1 ;
goto out ;
}
cname = options->permitted_cnames +
options->num_permitted_cnames ++;
@@ -1937,17 +2036,17 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
goto parse_flag;
case oStreamLocalBindMask:
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing StreamLocalBindMask "
" argument." , filename, linenum);
return - 1 ;
goto out ;
}
/* Parse mode in octal format */
value = strtol (arg, &endofnumber, 8 );
if (arg == endofnumber || value < 0 || value > 0777 ) {
error (" %.200s line %d : Bad mask." , filename, linenum);
return - 1 ;
goto out ;
}
options->fwd_opts .streamlocal_bind_mask = (mode_t )value;
break ;
@@ -1962,16 +2061,16 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oFingerprintHash:
intptr = &options->fingerprint_hash ;
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
if ((value = ssh_digest_alg_by_name (arg)) == -1 ) {
error (" %.200s line %d : Invalid hash algorithm \" %s \" ." ,
filename, linenum, arg);
return - 1 ;
goto out ;
}
if (*activep && *intptr == -1 )
*intptr = value;
@@ -1991,8 +2090,8 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
goto parse_pubkey_algos;
case oAddKeysToAgent:
arg = strdelim (&s );
arg2 = strdelim (&s );
arg = argv_next (&ac, &av );
arg2 = argv_next (&ac, &av );
value = parse_multistate_value (arg, filename, linenum,
multistate_yesnoaskconfirm);
value2 = 0 ; /* unlimited lifespan by default */
@@ -2002,20 +2101,20 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
value2 > INT_MAX) {
error (" %s line %d : invalid time value." ,
filename, linenum);
return - 1 ;
goto out ;
}
} else if (value == -1 && arg2 == NULL ) {
if ((value2 = convtime (arg)) == -1 ||
value2 > INT_MAX) {
error (" %s line %d : unsupported option" ,
filename, linenum);
return - 1 ;
goto out ;
}
value = 1 ; /* yes */
} else if (value == -1 || arg2 != NULL ) {
error (" %s line %d : unsupported option" ,
filename, linenum);
return - 1 ;
goto out ;
}
if (*activep && options->add_keys_to_agent == -1 ) {
options->add_keys_to_agent = value;
@@ -2025,26 +2124,26 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oIdentityAgent:
charptr = &options->identity_agent ;
arg = strdelim (&s );
arg = argv_next (&ac, &av );
if (!arg || *arg == ' \0 ' ) {
error (" %.200s line %d : Missing argument." ,
filename, linenum);
return - 1 ;
goto out ;
}
parse_agent_path:
/* Extra validation if the string represents an env var. */
if ((arg2 = dollar_expand (&r, arg)) == NULL || r) {
error (" %.200s line %d : Invalid environment expansion "
" %s ." , filename, linenum, arg);
return - 1 ;
goto out ;
}
free (arg2);
/* check for legacy environment format */
if (arg[0 ] == ' $' && arg[1 ] != ' {' &&
!valid_env_name (arg + 1 )) {
error (" %.200s line %d : Invalid environment name %s ." ,
filename, linenum, arg);
return - 1 ;
goto out ;
}
if (*activep && *charptr == NULL )
*charptr = xstrdup (arg);
@@ -2053,25 +2152,33 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oDeprecated:
debug (" %s line %d : Deprecated option \" %s \" " ,
filename, linenum, keyword);
return 0 ;
argv_consume (&ac);
break ;
case oUnsupported:
error (" %s line %d : Unsupported option \" %s \" " ,
filename, linenum, keyword);
return 0 ;
argv_consume (&ac);
break ;
default :
error (" %s line %d : Unimplemented opcode %d " ,
filename, linenum, opcode);
goto out;
}
/* Check that there is no garbage at end of line. */
if ((arg = strdelim (&s)) != NULL && *arg != ' \0 ' ) {
error (" %.200s line %d : garbage at end of line; \" %.200s \" . " ,
filename, linenum, arg );
return - 1 ;
if (ac > 0 ) {
error (" %.200s line %d : keyword %s extra arguments "
" at end of line " , filename, linenum, keyword );
goto out ;
}
return 0 ;
/* success */
ret = 0 ;
out:
argv_free (oav, oac);
return ret;
}
/*
@@ -2097,7 +2204,7 @@ read_config_file_depth(const char *filename, struct passwd *pw,
int flags, int *activep, int *want_final_pass, int depth)
{
FILE *f;
char *cp, * line = NULL ;
char *line = NULL ;
size_t linesize = 0 ;
int linenum;
int bad_options = 0 ;
@@ -2133,8 +2240,6 @@ read_config_file_depth(const char *filename, struct passwd *pw,
* NB - preserve newlines, they are needed to reproduce
* line numbers later for error messages.
*/
if ((cp = strchr (line, ' #' )) != NULL )
*cp = ' \0 ' ;
if (process_config_line_depth (options, pw, host, original_host,
line, filename, linenum, activep, flags, want_final_pass,
depth) != 0 )
@@ -2812,7 +2917,10 @@ parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remo
if (fwd->connect_host != NULL &&
strlen (fwd->connect_host ) >= NI_MAXHOST)
goto fail_free;
/* XXX - if connecting to a remote socket, max sun len may not match this host */
/*
* XXX - if connecting to a remote socket, max sun len may not
* match this host
*/
if (fwd->connect_path != NULL &&
strlen (fwd->connect_path ) >= PATH_MAX_SUN)
goto fail_free;
@@ -2847,6 +2955,12 @@ parse_jump(const char *s, Options *o, int active)
active &= o->proxy_command == NULL && o->jump_host == NULL ;
orig = sdup = xstrdup (s);
/* Remove comment and trailing whitespace */
if ((cp = strchr (orig, ' #' )) != NULL )
*cp = ' \0 ' ;
rtrim (orig);
first = active;
do {
if (strcasecmp (s, " none" ) == 0 )
@@ -3019,6 +3133,8 @@ dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
u_int i;
printf (" %s " , lookup_opcode_name (code));
if (count == 0 )
printf (" none" );
for (i = 0 ; i < count; i++)
printf (" %s " , vals[i]);
printf (" \n " );