int process_config_line(Options *options, const char *host, char *line, const char *filename, int linenum, int *activep) { char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256]; int opcode, *intptr, value, value2, scale; LogLevel *log_level_ptr; long long orig, val64; size_t len; Forward fwd; /* Strip trailing whitespace */ for (len = strlen(line) - 1; len > 0; len--) { if (strchr(WHITESPACE, line[len]) == NULL) break; line[len] = '\0'; } s = line; /* Get the keyword. (Each line is supposed to begin with a keyword). */ if ((keyword = strdelim(&s)) == NULL) return 0; /* Ignore leading whitespace. */ if (*keyword == '\0') keyword = strdelim(&s); if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') return 0; opcode = parse_token(keyword, filename, linenum); switch (opcode) { case oBadOption: /* don't panic, but count bad options */ return -1; /* NOTREACHED */ case oConnectTimeout: intptr = &options->connection_timeout; parse_time: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%s line %d: missing time value.", filename, linenum); if ((value = convtime(arg)) == -1) fatal("%s line %d: invalid time value.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oForwardAgent: intptr = &options->forward_agent; parse_flag: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); value = 0; /* To avoid compiler warning... */ if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = 1; else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = 0; else fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oForwardX11: intptr = &options->forward_x11; goto parse_flag; case oForwardX11Trusted: intptr = &options->forward_x11_trusted; goto parse_flag; case oForwardX11Timeout: intptr = &options->forward_x11_timeout; goto parse_time; case oGatewayPorts: intptr = &options->gateway_ports; goto parse_flag; case oExitOnForwardFailure: intptr = &options->exit_on_forward_failure; goto parse_flag; case oUsePrivilegedPort: intptr = &options->use_privileged_port; goto parse_flag; case oPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; case oZeroKnowledgePasswordAuthentication: intptr = &options->zero_knowledge_password_authentication; goto parse_flag; case oKbdInteractiveAuthentication: intptr = &options->kbd_interactive_authentication; goto parse_flag; case oKbdInteractiveDevices: charptr = &options->kbd_interactive_devices; goto parse_string; case oPubkeyAuthentication: intptr = &options->pubkey_authentication; goto parse_flag; case oRSAAuthentication: intptr = &options->rsa_authentication; goto parse_flag; case oRhostsRSAAuthentication: intptr = &options->rhosts_rsa_authentication; goto parse_flag; case oHostbasedAuthentication: intptr = &options->hostbased_authentication; goto parse_flag; case oChallengeResponseAuthentication: intptr = &options->challenge_response_authentication; goto parse_flag; case oGssAuthentication: intptr = &options->gss_authentication; goto parse_flag; case oGssKeyEx: intptr = &options->gss_keyex; goto parse_flag; case oGssDelegateCreds: intptr = &options->gss_deleg_creds; goto parse_flag; case oGssTrustDns: intptr = &options->gss_trust_dns; goto parse_flag; case oGssClientIdentity: charptr = &options->gss_client_identity; goto parse_string; case oGssServerIdentity: charptr = &options->gss_server_identity; goto parse_string; case oGssRenewalRekey: intptr = &options->gss_renewal_rekey; goto parse_flag; case oBatchMode: intptr = &options->batch_mode; goto parse_flag; case oCheckHostIP: intptr = &options->check_host_ip; goto parse_flag; case oVerifyHostKeyDNS: intptr = &options->verify_host_key_dns; goto parse_yesnoask; case oStrictHostKeyChecking: intptr = &options->strict_host_key_checking; parse_yesnoask: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing yes/no/ask argument.", filename, linenum); value = 0; /* To avoid compiler warning... */ if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = 1; else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = 0; else if (strcmp(arg, "ask") == 0) value = 2; else fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oCompression: intptr = &options->compression; goto parse_flag; case oTCPKeepAlive: intptr = &options->tcp_keep_alive; goto parse_flag; case oNoHostAuthenticationForLocalhost: intptr = &options->no_host_authentication_for_localhost; goto parse_flag; case oNumberOfPasswordPrompts: intptr = &options->number_of_password_prompts; goto parse_int; case oCompressionLevel: intptr = &options->compression_level; goto parse_int; case oRekeyLimit: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (arg[0] < '0' || arg[0] > '9') fatal("%.200s line %d: Bad number.", filename, linenum); orig = val64 = strtoll(arg, &endofnumber, 10); if (arg == endofnumber) fatal("%.200s line %d: Bad number.", filename, linenum); switch (toupper(*endofnumber)) { case '\0': scale = 1; break; case 'K': scale = 1<<10; break; case 'M': scale = 1<<20; break; case 'G': scale = 1<<30; break; default: fatal("%.200s line %d: Invalid RekeyLimit suffix", filename, linenum); } val64 *= scale; /* detect integer wrap and too-large limits */ if ((val64 / scale) != orig || val64 > UINT_MAX) fatal("%.200s line %d: RekeyLimit too large", filename, linenum); if (val64 < 16) fatal("%.200s line %d: RekeyLimit too small", filename, linenum); if (*activep && options->rekey_limit == -1) options->rekey_limit = (u_int32_t)val64; break; case oIdentityFile: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (*activep) { intptr = &options->num_identity_files; if (*intptr >= SSH_MAX_IDENTITY_FILES) fatal("%.200s line %d: Too many identity files specified (max %d).", filename, linenum, SSH_MAX_IDENTITY_FILES); charptr = &options->identity_files[*intptr]; *charptr = xstrdup(arg); *intptr = *intptr + 1; } break; case oXAuthLocation: charptr=&options->xauth_location; goto parse_string; case oUser: charptr = &options->user; parse_string: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (*activep && *charptr == NULL) *charptr = xstrdup(arg); break; case oGlobalKnownHostsFile: charptr = &options->system_hostfile; goto parse_string; case oUserKnownHostsFile: charptr = &options->user_hostfile; goto parse_string; case oGlobalKnownHostsFile2: charptr = &options->system_hostfile2; goto parse_string; case oUserKnownHostsFile2: charptr = &options->user_hostfile2; goto parse_string; case oHostName: charptr = &options->hostname; goto parse_string; case oHostKeyAlias: charptr = &options->host_key_alias; goto parse_string; case oPreferredAuthentications: charptr = &options->preferred_authentications; goto parse_string; case oBindAddress: charptr = &options->bind_address; goto parse_string; case oPKCS11Provider: charptr = &options->pkcs11_provider; goto parse_string; case oProxyCommand: charptr = &options->proxy_command; parse_command: if (s == NULL) fatal("%.200s line %d: Missing argument.", filename, linenum); len = strspn(s, WHITESPACE "="); if (*activep && *charptr == NULL) *charptr = xstrdup(s + len); return 0; case oPort: intptr = &options->port; parse_int: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (arg[0] < '0' || arg[0] > '9') fatal("%.200s line %d: Bad number.", filename, linenum); /* Octal, decimal, or hex format? */ value = strtol(arg, &endofnumber, 0); if (arg == endofnumber) fatal("%.200s line %d: Bad number.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oConnectionAttempts: intptr = &options->connection_attempts; goto parse_int; case oCipher: intptr = &options->cipher; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); value = cipher_number(arg); if (value == -1) fatal("%.200s line %d: Bad cipher '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && *intptr == -1) *intptr = value; break; case oCiphers: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!ciphers_valid(arg)) fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->ciphers == NULL) options->ciphers = xstrdup(arg); break; case oMacs: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!mac_valid(arg)) fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->macs == NULL) options->macs = xstrdup(arg); break; case oKexAlgorithms: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!kex_names_valid(arg)) fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->kex_algorithms == NULL) options->kex_algorithms = xstrdup(arg); break; case oHostKeyAlgorithms: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!key_names_valid2(arg)) fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->hostkeyalgorithms == NULL) options->hostkeyalgorithms = xstrdup(arg); break; case oProtocol: intptr = &options->protocol; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); value = proto_spec(arg); if (value == SSH_PROTO_UNKNOWN) fatal("%.200s line %d: Bad protocol spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && *intptr == SSH_PROTO_UNKNOWN) *intptr = value; break; case oLogLevel: log_level_ptr = &options->log_level; arg = strdelim(&s); value = log_level_number(arg); if (value == SYSLOG_LEVEL_NOT_SET) fatal("%.200s line %d: unsupported log level '%s'", filename, linenum, arg ? arg : "<NONE>"); if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET) *log_level_ptr = (LogLevel) value; break; case oLocalForward: case oRemoteForward: case oDynamicForward: arg = strdelim(&s); if (arg == NULL || *arg == '\0') fatal("%.200s line %d: Missing port argument.", filename, linenum); if (opcode == oLocalForward || opcode == oRemoteForward) { arg2 = strdelim(&s); if (arg2 == NULL || *arg2 == '\0') fatal("%.200s line %d: Missing target argument.", filename, linenum); /* construct a string for parse_forward */ snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2); } else if (opcode == oDynamicForward) { strlcpy(fwdarg, arg, sizeof(fwdarg)); } if (parse_forward(&fwd, fwdarg, opcode == oDynamicForward ? 1 : 0, opcode == oRemoteForward ? 1 : 0) == 0) fatal("%.200s line %d: Bad forwarding specification.", filename, linenum); if (*activep) { if (opcode == oLocalForward || opcode == oDynamicForward) add_local_forward(options, &fwd); else if (opcode == oRemoteForward) add_remote_forward(options, &fwd); } break; case oClearAllForwardings: intptr = &options->clear_forwardings; goto parse_flag; case oHost: *activep = 0; while ((arg = strdelim(&s)) != NULL && *arg != '\0') if (match_pattern(host, arg)) { debug("Applying options for %.100s", arg); *activep = 1; break; } /* Avoid garbage check below, as strdelim is done. */ return 0; case oEscapeChar: intptr = &options->escape_char; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (arg[0] == '^' && arg[2] == 0 && (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) value = (u_char) arg[1] & 31; else if (strlen(arg) == 1) value = (u_char) arg[0]; else if (strcmp(arg, "none") == 0) value = SSH_ESCAPECHAR_NONE; else { fatal("%.200s line %d: Bad escape character.", filename, linenum); /* NOTREACHED */ value = 0; /* Avoid compiler warning. */ } if (*activep && *intptr == -1) *intptr = value; break; case oAddressFamily: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%s line %d: missing address family.", filename, linenum); intptr = &options->address_family; if (strcasecmp(arg, "inet") == 0) value = AF_INET; else if (strcasecmp(arg, "inet6") == 0) value = AF_INET6; else if (strcasecmp(arg, "any") == 0) value = AF_UNSPEC; else fatal("Unsupported AddressFamily \"%s\"", arg); if (*activep && *intptr == -1) *intptr = value; break; case oEnableSSHKeysign: intptr = &options->enable_ssh_keysign; goto parse_flag; case oIdentitiesOnly: intptr = &options->identities_only; goto parse_flag; case oServerAliveInterval: intptr = &options->server_alive_interval; goto parse_time; case oServerAliveCountMax: intptr = &options->server_alive_count_max; goto parse_int; case oSendEnv: while ((arg = strdelim(&s)) != NULL && *arg != '\0') { if (strchr(arg, '=') != NULL) fatal("%s line %d: Invalid environment name.", filename, linenum); if (!*activep) continue; if (options->num_send_env >= MAX_SEND_ENV) fatal("%s line %d: too many send env.", filename, linenum); options->send_env[options->num_send_env++] = xstrdup(arg); } break; case oControlPath: charptr = &options->control_path; goto parse_string; case oControlMaster: intptr = &options->control_master; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing ControlMaster argument.", filename, linenum); value = 0; /* To avoid compiler warning... */ if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = SSHCTL_MASTER_YES; else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = SSHCTL_MASTER_NO; else if (strcmp(arg, "auto") == 0) value = SSHCTL_MASTER_AUTO; else if (strcmp(arg, "ask") == 0) value = SSHCTL_MASTER_ASK; else if (strcmp(arg, "autoask") == 0) value = SSHCTL_MASTER_AUTO_ASK; else fatal("%.200s line %d: Bad ControlMaster argument.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oControlPersist: /* no/false/yes/true, or a time spec */ intptr = &options->control_persist; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing ControlPersist" " argument.", filename, linenum); value = 0; value2 = 0; /* timeout */ if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = 0; else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = 1; else if ((value2 = convtime(arg)) >= 0) value = 1; else fatal("%.200s line %d: Bad ControlPersist argument.", filename, linenum); if (*activep && *intptr == -1) { *intptr = value; options->control_persist_timeout = value2; } break; case oHashKnownHosts: intptr = &options->hash_known_hosts; goto parse_flag; case oTunnel: intptr = &options->tun_open; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%s line %d: Missing yes/point-to-point/" "ethernet/no argument.", filename, linenum); value = 0; /* silence compiler */ if (strcasecmp(arg, "ethernet") == 0) value = SSH_TUNMODE_ETHERNET; else if (strcasecmp(arg, "point-to-point") == 0) value = SSH_TUNMODE_POINTOPOINT; else if (strcasecmp(arg, "yes") == 0) value = SSH_TUNMODE_DEFAULT; else if (strcasecmp(arg, "no") == 0) value = SSH_TUNMODE_NO; else fatal("%s line %d: Bad yes/point-to-point/ethernet/" "no argument: %s", filename, linenum, arg); if (*activep) *intptr = value; break; case oTunnelDevice: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); value = a2tun(arg, &value2); if (value == SSH_TUNID_ERR) fatal("%.200s line %d: Bad tun device.", filename, linenum); if (*activep) { options->tun_local = value; options->tun_remote = value2; } break; case oLocalCommand: charptr = &options->local_command; goto parse_command; case oPermitLocalCommand: intptr = &options->permit_local_command; goto parse_flag; case oVisualHostKey: intptr = &options->visual_host_key; goto parse_flag; case oIPQoS: arg = strdelim(&s); if ((value = parse_ipqos(arg)) == -1) fatal("%s line %d: Bad IPQoS value: %s", filename, linenum, arg); arg = strdelim(&s); if (arg == NULL) value2 = value; else if ((value2 = parse_ipqos(arg)) == -1) fatal("%s line %d: Bad IPQoS value: %s", filename, linenum, arg); if (*activep) { options->ip_qos_interactive = value; options->ip_qos_bulk = value2; } break; case oUseRoaming: intptr = &options->use_roaming; goto parse_flag; case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); return 0; case oUnsupported: error("%s line %d: Unsupported option \"%s\"", filename, linenum, keyword); return 0; default: fatal("process_config_line: Unimplemented opcode %d", opcode); } /* Check that there is no garbage at end of line. */ if ((arg = strdelim(&s)) != NULL && *arg != '\0') { fatal("%.200s line %d: garbage at end of line; \"%.200s\".", filename, linenum, arg); } return 0; }
int process_server_config_line(ServerOptions *options, char *line, const char *filename, int linenum, int *activep, const char *user, const char *host, const char *address) { char *cp, **charptr, *arg, *p; int cmdline = 0, *intptr, value, n; SyslogFacility *log_facility_ptr; LogLevel *log_level_ptr; ServerOpCodes opcode; int port; u_int i, flags = 0; size_t len; cp = line; if ((arg = strdelim(&cp)) == NULL) return 0; /* Ignore leading whitespace */ if (*arg == '\0') arg = strdelim(&cp); if (!arg || !*arg || *arg == '#') return 0; intptr = NULL; charptr = NULL; opcode = parse_token(arg, filename, linenum, &flags); if (activep == NULL) { /* We are processing a command line directive */ cmdline = 1; activep = &cmdline; } if (*activep && opcode != sMatch) debug3("%s:%d setting %s %s", filename, linenum, arg, cp); if (*activep == 0 && !(flags & SSHCFG_MATCH)) { if (user == NULL) { fatal("%s line %d: Directive '%s' is not allowed " "within a Match block", filename, linenum, arg); } else { /* this is a directive we have already processed */ while (arg) arg = strdelim(&cp); return 0; } } switch (opcode) { /* Portable-specific options */ case sUsePAM: intptr = &options->use_pam; goto parse_flag; /* Standard Options */ case sBadOption: return -1; case sPort: /* ignore ports from configfile if cmdline specifies ports */ if (options->ports_from_cmdline) return 0; if (options->listen_addrs != NULL) fatal("%s line %d: ports must be specified before " "ListenAddress.", filename, linenum); if (options->num_ports >= MAX_PORTS) fatal("%s line %d: too many ports.", filename, linenum); arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing port number.", filename, linenum); options->ports[options->num_ports++] = a2port(arg); if (options->ports[options->num_ports-1] <= 0) fatal("%s line %d: Badly formatted port number.", filename, linenum); break; case sServerKeyBits: intptr = &options->server_key_bits; parse_int: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing integer value.", filename, linenum); value = atoi(arg); if (*activep && *intptr == -1) *intptr = value; break; case sLoginGraceTime: intptr = &options->login_grace_time; parse_time: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing time value.", filename, linenum); if ((value = convtime(arg)) == -1) fatal("%s line %d: invalid time value.", filename, linenum); if (*intptr == -1) *intptr = value; break; case sKeyRegenerationTime: intptr = &options->key_regeneration_time; goto parse_time; case sListenAddress: arg = strdelim(&cp); if (arg == NULL || *arg == '\0') fatal("%s line %d: missing address", filename, linenum); /* check for bare IPv6 address: no "[]" and 2 or more ":" */ if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL && strchr(p+1, ':') != NULL) { add_listen_addr(options, arg, 0); break; } p = hpdelim(&arg); if (p == NULL) fatal("%s line %d: bad address:port usage", filename, linenum); p = cleanhostname(p); if (arg == NULL) port = 0; else if ((port = a2port(arg)) <= 0) fatal("%s line %d: bad port number", filename, linenum); add_listen_addr(options, p, port); break; case sAddressFamily: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing address family.", filename, linenum); intptr = &options->address_family; if (options->listen_addrs != NULL) fatal("%s line %d: address family must be specified before " "ListenAddress.", filename, linenum); if (strcasecmp(arg, "inet") == 0) value = AF_INET; else if (strcasecmp(arg, "inet6") == 0) value = AF_INET6; else if (strcasecmp(arg, "any") == 0) value = AF_UNSPEC; else fatal("%s line %d: unsupported address family \"%s\".", filename, linenum, arg); if (*intptr == -1) *intptr = value; break; case sHostKeyFile: intptr = &options->num_host_key_files; if (*intptr >= MAX_HOSTKEYS) fatal("%s line %d: too many host keys specified (max %d).", filename, linenum, MAX_HOSTKEYS); charptr = &options->host_key_files[*intptr]; parse_filename: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing file name.", filename, linenum); if (*activep && *charptr == NULL) { *charptr = tilde_expand_filename(arg, getuid()); /* increase optional counter */ if (intptr != NULL) *intptr = *intptr + 1; } break; case sPidFile: charptr = &options->pid_file; goto parse_filename; case sPermitRootLogin: intptr = &options->permit_root_login; arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing yes/" "without-password/forced-commands-only/no " "argument.", filename, linenum); value = 0; /* silence compiler */ if (strcmp(arg, "without-password") == 0) value = PERMIT_NO_PASSWD; else if (strcmp(arg, "forced-commands-only") == 0) value = PERMIT_FORCED_ONLY; else if (strcmp(arg, "yes") == 0) value = PERMIT_YES; else if (strcmp(arg, "no") == 0) value = PERMIT_NO; else fatal("%s line %d: Bad yes/" "without-password/forced-commands-only/no " "argument: %s", filename, linenum, arg); if (*activep && *intptr == -1) *intptr = value; break; case sIgnoreRhosts: intptr = &options->ignore_rhosts; parse_flag: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing yes/no argument.", filename, linenum); value = 0; /* silence compiler */ if (strcmp(arg, "yes") == 0) value = 1; else if (strcmp(arg, "no") == 0) value = 0; else fatal("%s line %d: Bad yes/no argument: %s", filename, linenum, arg); if (*activep && *intptr == -1) *intptr = value; break; case sIgnoreUserKnownHosts: intptr = &options->ignore_user_known_hosts; goto parse_flag; case sRhostsRSAAuthentication: intptr = &options->rhosts_rsa_authentication; goto parse_flag; case sHostbasedAuthentication: intptr = &options->hostbased_authentication; goto parse_flag; case sHostbasedUsesNameFromPacketOnly: intptr = &options->hostbased_uses_name_from_packet_only; goto parse_flag; case sRSAAuthentication: intptr = &options->rsa_authentication; goto parse_flag; case sPubkeyAuthentication: intptr = &options->pubkey_authentication; goto parse_flag; case sKerberosAuthentication: intptr = &options->kerberos_authentication; goto parse_flag; case sKerberosOrLocalPasswd: intptr = &options->kerberos_or_local_passwd; goto parse_flag; case sKerberosTicketCleanup: intptr = &options->kerberos_ticket_cleanup; goto parse_flag; case sKerberosGetAFSToken: intptr = &options->kerberos_get_afs_token; goto parse_flag; case sGssAuthentication: intptr = &options->gss_authentication; goto parse_flag; case sGssKeyEx: intptr = &options->gss_keyex; goto parse_flag; case sGssCleanupCreds: intptr = &options->gss_cleanup_creds; goto parse_flag; case sGssStrictAcceptor: intptr = &options->gss_strict_acceptor; goto parse_flag; case sGssStoreRekey: intptr = &options->gss_store_rekey; goto parse_flag; case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; case sZeroKnowledgePasswordAuthentication: intptr = &options->zero_knowledge_password_authentication; goto parse_flag; case sKbdInteractiveAuthentication: intptr = &options->kbd_interactive_authentication; goto parse_flag; case sChallengeResponseAuthentication: intptr = &options->challenge_response_authentication; goto parse_flag; case sPrintMotd: intptr = &options->print_motd; goto parse_flag; case sPrintLastLog: intptr = &options->print_lastlog; goto parse_flag; case sX11Forwarding: intptr = &options->x11_forwarding; goto parse_flag; case sX11DisplayOffset: intptr = &options->x11_display_offset; goto parse_int; case sX11UseLocalhost: intptr = &options->x11_use_localhost; goto parse_flag; case sXAuthLocation: charptr = &options->xauth_location; goto parse_filename; case sStrictModes: intptr = &options->strict_modes; goto parse_flag; case sTCPKeepAlive: intptr = &options->tcp_keep_alive; goto parse_flag; case sEmptyPasswd: intptr = &options->permit_empty_passwd; goto parse_flag; case sPermitUserEnvironment: intptr = &options->permit_user_env; goto parse_flag; case sUseLogin: intptr = &options->use_login; goto parse_flag; case sCompression: intptr = &options->compression; arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing yes/no/delayed " "argument.", filename, linenum); value = 0; /* silence compiler */ if (strcmp(arg, "delayed") == 0) value = COMP_DELAYED; else if (strcmp(arg, "yes") == 0) value = COMP_ZLIB; else if (strcmp(arg, "no") == 0) value = COMP_NONE; else fatal("%s line %d: Bad yes/no/delayed " "argument: %s", filename, linenum, arg); if (*intptr == -1) *intptr = value; break; case sGatewayPorts: intptr = &options->gateway_ports; arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing yes/no/clientspecified " "argument.", filename, linenum); value = 0; /* silence compiler */ if (strcmp(arg, "clientspecified") == 0) value = 2; else if (strcmp(arg, "yes") == 0) value = 1; else if (strcmp(arg, "no") == 0) value = 0; else fatal("%s line %d: Bad yes/no/clientspecified " "argument: %s", filename, linenum, arg); if (*activep && *intptr == -1) *intptr = value; break; case sUseDNS: intptr = &options->use_dns; goto parse_flag; case sLogFacility: log_facility_ptr = &options->log_facility; arg = strdelim(&cp); value = log_facility_number(arg); if (value == SYSLOG_FACILITY_NOT_SET) fatal("%.200s line %d: unsupported log facility '%s'", filename, linenum, arg ? arg : "<NONE>"); if (*log_facility_ptr == -1) *log_facility_ptr = (SyslogFacility) value; break; case sLogLevel: log_level_ptr = &options->log_level; arg = strdelim(&cp); value = log_level_number(arg); if (value == SYSLOG_LEVEL_NOT_SET) fatal("%.200s line %d: unsupported log level '%s'", filename, linenum, arg ? arg : "<NONE>"); if (*log_level_ptr == -1) *log_level_ptr = (LogLevel) value; break; case sAllowTcpForwarding: intptr = &options->allow_tcp_forwarding; goto parse_flag; case sAllowAgentForwarding: intptr = &options->allow_agent_forwarding; goto parse_flag; case sUsePrivilegeSeparation: intptr = &use_privsep; goto parse_flag; case sAllowUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_allow_users >= MAX_ALLOW_USERS) fatal("%s line %d: too many allow users.", filename, linenum); options->allow_users[options->num_allow_users++] = xstrdup(arg); } break; case sDenyUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_deny_users >= MAX_DENY_USERS) fatal("%s line %d: too many deny users.", filename, linenum); options->deny_users[options->num_deny_users++] = xstrdup(arg); } break; case sAllowGroups: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_allow_groups >= MAX_ALLOW_GROUPS) fatal("%s line %d: too many allow groups.", filename, linenum); options->allow_groups[options->num_allow_groups++] = xstrdup(arg); } break; case sDenyGroups: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_deny_groups >= MAX_DENY_GROUPS) fatal("%s line %d: too many deny groups.", filename, linenum); options->deny_groups[options->num_deny_groups++] = xstrdup(arg); } break; case sCiphers: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); if (!ciphers_valid(arg)) fatal("%s line %d: Bad SSH2 cipher spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (options->ciphers == NULL) options->ciphers = xstrdup(arg); break; case sMacs: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); if (!mac_valid(arg)) fatal("%s line %d: Bad SSH2 mac spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (options->macs == NULL) options->macs = xstrdup(arg); break; case sProtocol: intptr = &options->protocol; arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); value = proto_spec(arg); if (value == SSH_PROTO_UNKNOWN) fatal("%s line %d: Bad protocol spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*intptr == SSH_PROTO_UNKNOWN) *intptr = value; break; case sSubsystem: if (options->num_subsystems >= MAX_SUBSYSTEMS) { fatal("%s line %d: too many subsystems defined.", filename, linenum); } arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing subsystem name.", filename, linenum); if (!*activep) { arg = strdelim(&cp); break; } for (i = 0; i < options->num_subsystems; i++) if (strcmp(arg, options->subsystem_name[i]) == 0) fatal("%s line %d: Subsystem '%s' already defined.", filename, linenum, arg); options->subsystem_name[options->num_subsystems] = xstrdup(arg); arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing subsystem command.", filename, linenum); options->subsystem_command[options->num_subsystems] = xstrdup(arg); /* Collect arguments (separate to executable) */ p = xstrdup(arg); len = strlen(p) + 1; while ((arg = strdelim(&cp)) != NULL && *arg != '\0') { len += 1 + strlen(arg); p = xrealloc(p, 1, len); strlcat(p, " ", len); strlcat(p, arg, len); } options->subsystem_args[options->num_subsystems] = p; options->num_subsystems++; break; case sMaxStartups: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing MaxStartups spec.", filename, linenum); if ((n = sscanf(arg, "%d:%d:%d", &options->max_startups_begin, &options->max_startups_rate, &options->max_startups)) == 3) { if (options->max_startups_begin > options->max_startups || options->max_startups_rate > 100 || options->max_startups_rate < 1) fatal("%s line %d: Illegal MaxStartups spec.", filename, linenum); } else if (n != 1) fatal("%s line %d: Illegal MaxStartups spec.", filename, linenum); else options->max_startups = options->max_startups_begin; break; case sMaxAuthTries: intptr = &options->max_authtries; goto parse_int; case sMaxSessions: intptr = &options->max_sessions; goto parse_int; case sBanner: charptr = &options->banner; goto parse_filename; /* * These options can contain %X options expanded at * connect time, so that you can specify paths like: * * AuthorizedKeysFile /etc/ssh_keys/%u */ case sAuthorizedKeysFile: case sAuthorizedKeysFile2: charptr = (opcode == sAuthorizedKeysFile) ? &options->authorized_keys_file : &options->authorized_keys_file2; goto parse_filename; case sClientAliveInterval: intptr = &options->client_alive_interval; goto parse_time; case sClientAliveCountMax: intptr = &options->client_alive_count_max; goto parse_int; case sAcceptEnv: while ((arg = strdelim(&cp)) && *arg != '\0') { if (strchr(arg, '=') != NULL) fatal("%s line %d: Invalid environment name.", filename, linenum); if (options->num_accept_env >= MAX_ACCEPT_ENV) fatal("%s line %d: too many allow env.", filename, linenum); if (!*activep) break; options->accept_env[options->num_accept_env++] = xstrdup(arg); } break; case sPermitTunnel: intptr = &options->permit_tun; arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing yes/point-to-point/" "ethernet/no argument.", filename, linenum); value = -1; for (i = 0; tunmode_desc[i].val != -1; i++) if (strcmp(tunmode_desc[i].text, arg) == 0) { value = tunmode_desc[i].val; break; } if (value == -1) fatal("%s line %d: Bad yes/point-to-point/ethernet/" "no argument: %s", filename, linenum, arg); if (*intptr == -1) *intptr = value; break; case sMatch: if (cmdline) fatal("Match directive not supported as a command-line " "option"); value = match_cfg_line(&cp, linenum, user, host, address); if (value < 0) fatal("%s line %d: Bad Match condition", filename, linenum); *activep = value; break; case sPermitOpen: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing PermitOpen specification", filename, linenum); n = options->num_permitted_opens; /* modified later */ if (strcmp(arg, "any") == 0) { if (*activep && n == -1) { channel_clear_adm_permitted_opens(); options->num_permitted_opens = 0; } break; } if (*activep && n == -1) channel_clear_adm_permitted_opens(); for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) { p = hpdelim(&arg); if (p == NULL) fatal("%s line %d: missing host in PermitOpen", filename, linenum); p = cleanhostname(p); if (arg == NULL || (port = a2port(arg)) <= 0) fatal("%s line %d: bad port number in " "PermitOpen", filename, linenum); if (*activep && n == -1) options->num_permitted_opens = channel_add_adm_permitted_opens(p, port); } break; case sForceCommand: if (cp == NULL) fatal("%.200s line %d: Missing argument.", filename, linenum); len = strspn(cp, WHITESPACE); if (*activep && options->adm_forced_command == NULL) options->adm_forced_command = xstrdup(cp + len); return 0; case sChrootDirectory: charptr = &options->chroot_directory; arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing file name.", filename, linenum); if (*activep && *charptr == NULL) *charptr = xstrdup(arg); break; case sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); while (arg) arg = strdelim(&cp); break; case sUnsupported: logit("%s line %d: Unsupported option %s", filename, linenum, arg); while (arg) arg = strdelim(&cp); break; default: fatal("%s line %d: Missing handler for opcode %s (%d)", filename, linenum, arg, opcode); } if ((arg = strdelim(&cp)) != NULL && *arg != '\0') fatal("%s line %d: garbage at end of line; \"%.200s\".", filename, linenum, arg); return 0; }
int process_config_line(Options *options, const char *host, char *line, const char *filename, int linenum, int *activep, int userconfig) { char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; char **cpptr, fwdarg[256]; u_int i, *uintptr, max_entries = 0; int negated, opcode, *intptr, value, value2; LogLevel *log_level_ptr; long long val64; size_t len; Forward fwd; /* Strip trailing whitespace */ for (len = strlen(line) - 1; len > 0; len--) { if (strchr(WHITESPACE, line[len]) == NULL) break; line[len] = '\0'; } s = line; /* Get the keyword. (Each line is supposed to begin with a keyword). */ if ((keyword = strdelim(&s)) == NULL) return 0; /* Ignore leading whitespace. */ if (*keyword == '\0') keyword = strdelim(&s); if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') return 0; /* Match lowercase keyword */ for (i = 0; i < strlen(keyword); i++) keyword[i] = tolower(keyword[i]); opcode = parse_token(keyword, filename, linenum, options->ignored_unknown); switch (opcode) { case oBadOption: /* don't panic, but count bad options */ return -1; /* NOTREACHED */ case oIgnoredUnknownOption: debug("%s line %d: Ignored unknown option \"%s\"", filename, linenum, keyword); return 0; case oConnectTimeout: intptr = &options->connection_timeout; parse_time: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%s line %d: missing time value.", filename, linenum); if ((value = convtime(arg)) == -1) fatal("%s line %d: invalid time value.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oForwardAgent: intptr = &options->forward_agent; parse_flag: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); value = 0; /* To avoid compiler warning... */ if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = 1; else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = 0; else fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oForwardX11: intptr = &options->forward_x11; goto parse_flag; case oForwardX11Trusted: intptr = &options->forward_x11_trusted; goto parse_flag; case oForwardX11Timeout: intptr = &options->forward_x11_timeout; goto parse_time; case oGatewayPorts: intptr = &options->gateway_ports; goto parse_flag; case oExitOnForwardFailure: intptr = &options->exit_on_forward_failure; goto parse_flag; case oUsePrivilegedPort: intptr = &options->use_privileged_port; goto parse_flag; case oPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; case oZeroKnowledgePasswordAuthentication: intptr = &options->zero_knowledge_password_authentication; goto parse_flag; case oKbdInteractiveAuthentication: intptr = &options->kbd_interactive_authentication; goto parse_flag; case oKbdInteractiveDevices: charptr = &options->kbd_interactive_devices; goto parse_string; case oPubkeyAuthentication: intptr = &options->pubkey_authentication; goto parse_flag; case oRSAAuthentication: intptr = &options->rsa_authentication; goto parse_flag; case oRhostsRSAAuthentication: intptr = &options->rhosts_rsa_authentication; goto parse_flag; case oHostbasedAuthentication: intptr = &options->hostbased_authentication; goto parse_flag; case oChallengeResponseAuthentication: intptr = &options->challenge_response_authentication; goto parse_flag; case oGssAuthentication: intptr = &options->gss_authentication; goto parse_flag; case oGssDelegateCreds: intptr = &options->gss_deleg_creds; goto parse_flag; case oBatchMode: intptr = &options->batch_mode; goto parse_flag; case oCheckHostIP: intptr = &options->check_host_ip; goto parse_flag; case oVerifyHostKeyDNS: intptr = &options->verify_host_key_dns; goto parse_yesnoask; case oStrictHostKeyChecking: intptr = &options->strict_host_key_checking; parse_yesnoask: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing yes/no/ask argument.", filename, linenum); value = 0; /* To avoid compiler warning... */ if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = 1; else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = 0; else if (strcmp(arg, "ask") == 0) value = 2; else fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oCompression: intptr = &options->compression; goto parse_flag; case oTCPKeepAlive: intptr = &options->tcp_keep_alive; goto parse_flag; case oNoHostAuthenticationForLocalhost: intptr = &options->no_host_authentication_for_localhost; goto parse_flag; case oNumberOfPasswordPrompts: intptr = &options->number_of_password_prompts; goto parse_int; case oCompressionLevel: intptr = &options->compression_level; goto parse_int; case oRekeyLimit: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (strcmp(arg, "default") == 0) { val64 = 0; } else { if (scan_scaled(arg, &val64) == -1) fatal("%.200s line %d: Bad number '%s': %s", filename, linenum, arg, strerror(errno)); /* check for too-large or too-small limits */ if (val64 > UINT_MAX) fatal("%.200s line %d: RekeyLimit too large", filename, linenum); if (val64 != 0 && val64 < 16) fatal("%.200s line %d: RekeyLimit too small", filename, linenum); } if (*activep && options->rekey_limit == -1) options->rekey_limit = (u_int32_t)val64; if (s != NULL) { /* optional rekey interval present */ if (strcmp(s, "none") == 0) { (void)strdelim(&s); /* discard */ break; } intptr = &options->rekey_interval; goto parse_time; } break; case oIdentityFile: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (*activep) { intptr = &options->num_identity_files; if (*intptr >= SSH_MAX_IDENTITY_FILES) fatal("%.200s line %d: Too many identity files specified (max %d).", filename, linenum, SSH_MAX_IDENTITY_FILES); add_identity_file(options, NULL, arg, userconfig); } break; case oXAuthLocation: charptr=&options->xauth_location; goto parse_string; case oUser: charptr = &options->user; parse_string: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (*activep && *charptr == NULL) *charptr = xstrdup(arg); break; case oGlobalKnownHostsFile: cpptr = (char **)&options->system_hostfiles; 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') { if ((*uintptr) >= max_entries) fatal("%s line %d: " "too many authorized keys files.", filename, linenum); cpptr[(*uintptr)++] = xstrdup(arg); } } return 0; case oUserKnownHostsFile: cpptr = (char **)&options->user_hostfiles; uintptr = &options->num_user_hostfiles; max_entries = SSH_MAX_HOSTS_FILES; goto parse_char_array; case oHostName: charptr = &options->hostname; goto parse_string; case oHostKeyAlias: charptr = &options->host_key_alias; goto parse_string; case oPreferredAuthentications: charptr = &options->preferred_authentications; goto parse_string; case oBindAddress: charptr = &options->bind_address; goto parse_string; case oPKCS11Provider: charptr = &options->pkcs11_provider; goto parse_string; case oProxyCommand: charptr = &options->proxy_command; parse_command: if (s == NULL) fatal("%.200s line %d: Missing argument.", filename, linenum); len = strspn(s, WHITESPACE "="); if (*activep && *charptr == NULL) *charptr = xstrdup(s + len); return 0; case oPort: intptr = &options->port; parse_int: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (arg[0] < '0' || arg[0] > '9') fatal("%.200s line %d: Bad number.", filename, linenum); /* Octal, decimal, or hex format? */ value = strtol(arg, &endofnumber, 0); if (arg == endofnumber) fatal("%.200s line %d: Bad number.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oConnectionAttempts: intptr = &options->connection_attempts; goto parse_int; case oCipher: intptr = &options->cipher; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); value = cipher_number(arg); if (value == -1) fatal("%.200s line %d: Bad cipher '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && *intptr == -1) *intptr = value; break; case oCiphers: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!ciphers_valid(arg)) fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->ciphers == NULL) options->ciphers = xstrdup(arg); break; case oMacs: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!mac_valid(arg)) fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->macs == NULL) options->macs = xstrdup(arg); break; case oKexAlgorithms: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!kex_names_valid(arg)) fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->kex_algorithms == NULL) options->kex_algorithms = xstrdup(arg); break; case oHostKeyAlgorithms: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!key_names_valid2(arg)) fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->hostkeyalgorithms == NULL) options->hostkeyalgorithms = xstrdup(arg); break; case oProtocol: intptr = &options->protocol; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); value = proto_spec(arg); if (value == SSH_PROTO_UNKNOWN) fatal("%.200s line %d: Bad protocol spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && *intptr == SSH_PROTO_UNKNOWN) *intptr = value; break; case oLogLevel: log_level_ptr = &options->log_level; arg = strdelim(&s); value = log_level_number(arg); if (value == SYSLOG_LEVEL_NOT_SET) fatal("%.200s line %d: unsupported log level '%s'", filename, linenum, arg ? arg : "<NONE>"); if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET) *log_level_ptr = (LogLevel) value; break; case oLocalForward: case oRemoteForward: case oDynamicForward: arg = strdelim(&s); if (arg == NULL || *arg == '\0') fatal("%.200s line %d: Missing port argument.", filename, linenum); if (opcode == oLocalForward || opcode == oRemoteForward) { arg2 = strdelim(&s); if (arg2 == NULL || *arg2 == '\0') fatal("%.200s line %d: Missing target argument.", filename, linenum); /* construct a string for parse_forward */ snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2); } else if (opcode == oDynamicForward) { strlcpy(fwdarg, arg, sizeof(fwdarg)); } if (parse_forward(&fwd, fwdarg, opcode == oDynamicForward ? 1 : 0, opcode == oRemoteForward ? 1 : 0) == 0) fatal("%.200s line %d: Bad forwarding specification.", filename, linenum); if (*activep) { if (opcode == oLocalForward || opcode == oDynamicForward) add_local_forward(options, &fwd); else if (opcode == oRemoteForward) add_remote_forward(options, &fwd); } break; case oClearAllForwardings: intptr = &options->clear_forwardings; goto parse_flag; case oHost: *activep = 0; arg2 = NULL; while ((arg = strdelim(&s)) != NULL && *arg != '\0') { negated = *arg == '!'; if (negated) arg++; if (match_pattern(host, arg)) { if (negated) { debug("%.200s line %d: Skipping Host " "block because of negated match " "for %.100s", filename, linenum, arg); *activep = 0; break; } if (!*activep) arg2 = arg; /* logged below */ *activep = 1; } } if (*activep) debug("%.200s line %d: Applying options for %.100s", filename, linenum, arg2); /* Avoid garbage check below, as strdelim is done. */ return 0; case oEscapeChar: intptr = &options->escape_char; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (arg[0] == '^' && arg[2] == 0 && (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) value = (u_char) arg[1] & 31; else if (strlen(arg) == 1) value = (u_char) arg[0]; else if (strcmp(arg, "none") == 0) value = SSH_ESCAPECHAR_NONE; else { fatal("%.200s line %d: Bad escape character.", filename, linenum); /* NOTREACHED */ value = 0; /* Avoid compiler warning. */ } if (*activep && *intptr == -1) *intptr = value; break; case oAddressFamily: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%s line %d: missing address family.", filename, linenum); intptr = &options->address_family; if (strcasecmp(arg, "inet") == 0) value = AF_INET; else if (strcasecmp(arg, "inet6") == 0) value = AF_INET6; else if (strcasecmp(arg, "any") == 0) value = AF_UNSPEC; else fatal("Unsupported AddressFamily \"%s\"", arg); if (*activep && *intptr == -1) *intptr = value; break; case oEnableSSHKeysign: intptr = &options->enable_ssh_keysign; goto parse_flag; case oIdentitiesOnly: intptr = &options->identities_only; goto parse_flag; case oServerAliveInterval: intptr = &options->server_alive_interval; goto parse_time; case oServerAliveCountMax: intptr = &options->server_alive_count_max; goto parse_int; case oSendEnv: while ((arg = strdelim(&s)) != NULL && *arg != '\0') { if (strchr(arg, '=') != NULL) fatal("%s line %d: Invalid environment name.", filename, linenum); if (!*activep) continue; if (options->num_send_env >= MAX_SEND_ENV) fatal("%s line %d: too many send env.", filename, linenum); options->send_env[options->num_send_env++] = xstrdup(arg); } break; case oControlPath: charptr = &options->control_path; goto parse_string; case oControlMaster: intptr = &options->control_master; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing ControlMaster argument.", filename, linenum); value = 0; /* To avoid compiler warning... */ if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = SSHCTL_MASTER_YES; else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = SSHCTL_MASTER_NO; else if (strcmp(arg, "auto") == 0) value = SSHCTL_MASTER_AUTO; else if (strcmp(arg, "ask") == 0) value = SSHCTL_MASTER_ASK; else if (strcmp(arg, "autoask") == 0) value = SSHCTL_MASTER_AUTO_ASK; else fatal("%.200s line %d: Bad ControlMaster argument.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oControlPersist: /* no/false/yes/true, or a time spec */ intptr = &options->control_persist; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing ControlPersist" " argument.", filename, linenum); value = 0; value2 = 0; /* timeout */ if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = 0; else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = 1; else if ((value2 = convtime(arg)) >= 0) value = 1; else fatal("%.200s line %d: Bad ControlPersist argument.", filename, linenum); if (*activep && *intptr == -1) { *intptr = value; options->control_persist_timeout = value2; } break; case oHashKnownHosts: intptr = &options->hash_known_hosts; goto parse_flag; case oTunnel: intptr = &options->tun_open; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%s line %d: Missing yes/point-to-point/" "ethernet/no argument.", filename, linenum); value = 0; /* silence compiler */ if (strcasecmp(arg, "ethernet") == 0) value = SSH_TUNMODE_ETHERNET; else if (strcasecmp(arg, "point-to-point") == 0) value = SSH_TUNMODE_POINTOPOINT; else if (strcasecmp(arg, "yes") == 0) value = SSH_TUNMODE_DEFAULT; else if (strcasecmp(arg, "no") == 0) value = SSH_TUNMODE_NO; else fatal("%s line %d: Bad yes/point-to-point/ethernet/" "no argument: %s", filename, linenum, arg); if (*activep) *intptr = value; break; case oTunnelDevice: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); value = a2tun(arg, &value2); if (value == SSH_TUNID_ERR) fatal("%.200s line %d: Bad tun device.", filename, linenum); if (*activep) { options->tun_local = value; options->tun_remote = value2; } break; case oLocalCommand: charptr = &options->local_command; goto parse_command; case oPermitLocalCommand: intptr = &options->permit_local_command; goto parse_flag; case oVisualHostKey: intptr = &options->visual_host_key; goto parse_flag; case oIPQoS: arg = strdelim(&s); if ((value = parse_ipqos(arg)) == -1) fatal("%s line %d: Bad IPQoS value: %s", filename, linenum, arg); arg = strdelim(&s); if (arg == NULL) value2 = value; else if ((value2 = parse_ipqos(arg)) == -1) fatal("%s line %d: Bad IPQoS value: %s", filename, linenum, arg); if (*activep) { options->ip_qos_interactive = value; options->ip_qos_bulk = value2; } break; case oUseRoaming: intptr = &options->use_roaming; goto parse_flag; case oRequestTTY: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%s line %d: missing argument.", filename, linenum); intptr = &options->request_tty; if (strcasecmp(arg, "yes") == 0) value = REQUEST_TTY_YES; else if (strcasecmp(arg, "no") == 0) value = REQUEST_TTY_NO; else if (strcasecmp(arg, "force") == 0) value = REQUEST_TTY_FORCE; else if (strcasecmp(arg, "auto") == 0) value = REQUEST_TTY_AUTO; else fatal("Unsupported RequestTTY \"%s\"", arg); if (*activep && *intptr == -1) *intptr = value; break; case oHPNDisabled: intptr = &options->hpn_disabled; goto parse_flag; case oHPNBufferSize: intptr = &options->hpn_buffer_size; goto parse_int; case oTcpRcvBufPoll: intptr = &options->tcp_rcv_buf_poll; goto parse_flag; case oTcpRcvBuf: intptr = &options->tcp_rcv_buf; goto parse_int; #ifdef NONE_CIPHER_ENABLED case oNoneEnabled: intptr = &options->none_enabled; goto parse_flag; /* * We check to see if the command comes from the command line or not. * If it does then enable it otherwise fail. NONE must never be a * default configuration. */ case oNoneSwitch: if (strcmp(filename,"command-line") == 0) { intptr = &options->none_switch; goto parse_flag; } else { debug("NoneSwitch directive found in %.200s.", filename); error("NoneSwitch is found in %.200s.\n" "You may only use this configuration option " "from the command line", filename); error("Continuing..."); return 0; } #endif case oVersionAddendum: if (s == NULL) fatal("%.200s line %d: Missing argument.", filename, linenum); len = strspn(s, WHITESPACE); if (*activep && options->version_addendum == NULL) { if (strcasecmp(s + len, "none") == 0) options->version_addendum = xstrdup(""); else if (strchr(s + len, '\r') != NULL) fatal("%.200s line %d: Invalid argument", filename, linenum); else options->version_addendum = xstrdup(s + len); } return 0; case oIgnoreUnknown: charptr = &options->ignored_unknown; goto parse_string; case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); return 0; case oUnsupported: error("%s line %d: Unsupported option \"%s\"", filename, linenum, keyword); return 0; default: fatal("process_config_line: Unimplemented opcode %d", opcode); } /* Check that there is no garbage at end of line. */ if ((arg = strdelim(&s)) != NULL && *arg != '\0') { fatal("%.200s line %d: garbage at end of line; \"%.200s\".", filename, linenum, arg); } return 0; }
int process_config_line(Options *options, const char *host, char *line, const char *filename, int linenum, int *activep) { char buf[256], *s, **charptr, *endofnumber, *keyword, *arg; int opcode, *intptr, value; size_t len; u_short fwd_port, fwd_host_port; char sfwd_host_port[6]; /* Strip trailing whitespace */ for(len = strlen(line) - 1; len > 0; len--) { if (strchr(WHITESPACE, line[len]) == NULL) break; line[len] = '\0'; } s = line; /* Get the keyword. (Each line is supposed to begin with a keyword). */ keyword = strdelim(&s); /* Ignore leading whitespace. */ if (*keyword == '\0') keyword = strdelim(&s); if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') return 0; opcode = parse_token(keyword, filename, linenum); switch (opcode) { case oBadOption: /* don't panic, but count bad options */ return -1; /* NOTREACHED */ case oConnectTimeout: intptr = &options->connection_timeout; parse_time: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%s line %d: missing time value.", filename, linenum); if ((value = convtime(arg)) == -1) fatal("%s line %d: invalid time value.", filename, linenum); if (*intptr == -1) *intptr = value; break; case oForwardAgent: intptr = &options->forward_agent; parse_flag: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); value = 0; /* To avoid compiler warning... */ if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = 1; else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = 0; else fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oForwardX11: intptr = &options->forward_x11; goto parse_flag; case oForwardX11Trusted: intptr = &options->forward_x11_trusted; goto parse_flag; case oGatewayPorts: intptr = &options->gateway_ports; goto parse_flag; case oUsePrivilegedPort: intptr = &options->use_privileged_port; goto parse_flag; case oPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; case oKbdInteractiveAuthentication: intptr = &options->kbd_interactive_authentication; goto parse_flag; case oKbdInteractiveDevices: charptr = &options->kbd_interactive_devices; goto parse_string; case oPubkeyAuthentication: intptr = &options->pubkey_authentication; goto parse_flag; case oRSAAuthentication: intptr = &options->rsa_authentication; goto parse_flag; case oRhostsRSAAuthentication: intptr = &options->rhosts_rsa_authentication; goto parse_flag; case oHostbasedAuthentication: intptr = &options->hostbased_authentication; goto parse_flag; case oChallengeResponseAuthentication: intptr = &options->challenge_response_authentication; goto parse_flag; case oGssAuthentication: intptr = &options->gss_authentication; goto parse_flag; case oGssDelegateCreds: intptr = &options->gss_deleg_creds; goto parse_flag; case oBatchMode: intptr = &options->batch_mode; goto parse_flag; case oCheckHostIP: intptr = &options->check_host_ip; goto parse_flag; case oVerifyHostKeyDNS: intptr = &options->verify_host_key_dns; goto parse_yesnoask; case oStrictHostKeyChecking: intptr = &options->strict_host_key_checking; parse_yesnoask: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing yes/no/ask argument.", filename, linenum); value = 0; /* To avoid compiler warning... */ if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = 1; else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = 0; else if (strcmp(arg, "ask") == 0) value = 2; else fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oCompression: intptr = &options->compression; goto parse_flag; case oTCPKeepAlive: intptr = &options->tcp_keep_alive; goto parse_flag; case oNoHostAuthenticationForLocalhost: intptr = &options->no_host_authentication_for_localhost; goto parse_flag; case oNumberOfPasswordPrompts: intptr = &options->number_of_password_prompts; goto parse_int; case oCompressionLevel: intptr = &options->compression_level; goto parse_int; case oRekeyLimit: intptr = &options->rekey_limit; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (arg[0] < '0' || arg[0] > '9') fatal("%.200s line %d: Bad number.", filename, linenum); value = strtol(arg, &endofnumber, 10); if (arg == endofnumber) fatal("%.200s line %d: Bad number.", filename, linenum); switch (toupper(*endofnumber)) { case 'K': value *= 1<<10; break; case 'M': value *= 1<<20; break; case 'G': value *= 1<<30; break; } if (*activep && *intptr == -1) *intptr = value; break; case oIdentityFile: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (*activep) { intptr = &options->num_identity_files; if (*intptr >= SSH_MAX_IDENTITY_FILES) fatal("%.200s line %d: Too many identity files specified (max %d).", filename, linenum, SSH_MAX_IDENTITY_FILES); charptr = &options->identity_files[*intptr]; *charptr = xstrdup(arg); *intptr = *intptr + 1; } break; case oXAuthLocation: charptr=&options->xauth_location; goto parse_string; case oUser: charptr = &options->user; parse_string: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (*activep && *charptr == NULL) *charptr = xstrdup(arg); break; case oGlobalKnownHostsFile: charptr = &options->system_hostfile; goto parse_string; case oUserKnownHostsFile: charptr = &options->user_hostfile; goto parse_string; case oGlobalKnownHostsFile2: charptr = &options->system_hostfile2; goto parse_string; case oUserKnownHostsFile2: charptr = &options->user_hostfile2; goto parse_string; case oHostName: charptr = &options->hostname; goto parse_string; case oHostKeyAlias: charptr = &options->host_key_alias; goto parse_string; case oPreferredAuthentications: charptr = &options->preferred_authentications; goto parse_string; case oBindAddress: charptr = &options->bind_address; goto parse_string; case oSmartcardDevice: charptr = &options->smartcard_device; goto parse_string; case oProxyCommand: if (s == NULL) fatal("%.200s line %d: Missing argument.", filename, linenum); charptr = &options->proxy_command; len = strspn(s, WHITESPACE "="); if (*activep && *charptr == NULL) *charptr = xstrdup(s + len); return 0; case oPort: intptr = &options->port; parse_int: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (arg[0] < '0' || arg[0] > '9') fatal("%.200s line %d: Bad number.", filename, linenum); /* Octal, decimal, or hex format? */ value = strtol(arg, &endofnumber, 0); if (arg == endofnumber) fatal("%.200s line %d: Bad number.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; break; case oConnectionAttempts: intptr = &options->connection_attempts; goto parse_int; case oCipher: intptr = &options->cipher; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); value = cipher_number(arg); if (value == -1) fatal("%.200s line %d: Bad cipher '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && *intptr == -1) *intptr = value; break; case oCiphers: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!ciphers_valid(arg)) fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->ciphers == NULL) options->ciphers = xstrdup(arg); break; case oMacs: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!mac_valid(arg)) fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->macs == NULL) options->macs = xstrdup(arg); break; case oHostKeyAlgorithms: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (!key_names_valid2(arg)) fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && options->hostkeyalgorithms == NULL) options->hostkeyalgorithms = xstrdup(arg); break; case oProtocol: intptr = &options->protocol; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); value = proto_spec(arg); if (value == SSH_PROTO_UNKNOWN) fatal("%.200s line %d: Bad protocol spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*activep && *intptr == SSH_PROTO_UNKNOWN) *intptr = value; break; case oLogLevel: intptr = (int *) &options->log_level; arg = strdelim(&s); value = log_level_number(arg); if (value == SYSLOG_LEVEL_NOT_SET) fatal("%.200s line %d: unsupported log level '%s'", filename, linenum, arg ? arg : "<NONE>"); if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET) *intptr = (LogLevel) value; break; case oLocalForward: case oRemoteForward: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing port argument.", filename, linenum); if ((fwd_port = a2port(arg)) == 0) fatal("%.200s line %d: Bad listen port.", filename, linenum); arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing second argument.", filename, linenum); if (sscanf(arg, "%255[^:]:%5[0-9]", buf, sfwd_host_port) != 2 && sscanf(arg, "%255[^/]/%5[0-9]", buf, sfwd_host_port) != 2) fatal("%.200s line %d: Bad forwarding specification.", filename, linenum); if ((fwd_host_port = a2port(sfwd_host_port)) == 0) fatal("%.200s line %d: Bad forwarding port.", filename, linenum); if (*activep) { if (opcode == oLocalForward) add_local_forward(options, fwd_port, buf, fwd_host_port); else if (opcode == oRemoteForward) add_remote_forward(options, fwd_port, buf, fwd_host_port); } break; case oDynamicForward: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing port argument.", filename, linenum); fwd_port = a2port(arg); if (fwd_port == 0) fatal("%.200s line %d: Badly formatted port number.", filename, linenum); if (*activep) add_local_forward(options, fwd_port, "socks", 0); break; case oClearAllForwardings: intptr = &options->clear_forwardings; goto parse_flag; case oHost: *activep = 0; while ((arg = strdelim(&s)) != NULL && *arg != '\0') if (match_pattern(host, arg)) { debug("Applying options for %.100s", arg); *activep = 1; break; } /* Avoid garbage check below, as strdelim is done. */ return 0; case oEscapeChar: intptr = &options->escape_char; arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (arg[0] == '^' && arg[2] == 0 && (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) value = (u_char) arg[1] & 31; else if (strlen(arg) == 1) value = (u_char) arg[0]; else if (strcmp(arg, "none") == 0) value = SSH_ESCAPECHAR_NONE; else { fatal("%.200s line %d: Bad escape character.", filename, linenum); /* NOTREACHED */ value = 0; /* Avoid compiler warning. */ } if (*activep && *intptr == -1) *intptr = value; break; case oAddressFamily: arg = strdelim(&s); intptr = &options->address_family; if (strcasecmp(arg, "inet") == 0) value = AF_INET; else if (strcasecmp(arg, "inet6") == 0) value = AF_INET6; else if (strcasecmp(arg, "any") == 0) value = AF_UNSPEC; else fatal("Unsupported AddressFamily \"%s\"", arg); if (*activep && *intptr == -1) *intptr = value; break; case oEnableSSHKeysign: intptr = &options->enable_ssh_keysign; goto parse_flag; case oIdentitiesOnly: intptr = &options->identities_only; goto parse_flag; case oServerAliveInterval: intptr = &options->server_alive_interval; goto parse_time; case oServerAliveCountMax: intptr = &options->server_alive_count_max; goto parse_int; case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); return 0; case oUnsupported: error("%s line %d: Unsupported option \"%s\"", filename, linenum, keyword); return 0; default: fatal("process_config_line: Unimplemented opcode %d", opcode); } /* Check that there is no garbage at end of line. */ if ((arg = strdelim(&s)) != NULL && *arg != '\0') { fatal("%.200s line %d: garbage at end of line; \"%.200s\".", filename, linenum, arg); } return 0; }
int process_server_config_line(ServerOptions *options, char *line, const char *filename, int linenum) { char *cp, **charptr, *arg, *p; int *intptr, value, i, n; ServerOpCodes opcode; cp = line; arg = strdelim(&cp); /* Ignore leading whitespace */ if (*arg == '\0') arg = strdelim(&cp); if (!arg || !*arg || *arg == '#') return 0; intptr = NULL; charptr = NULL; opcode = parse_token(arg, filename, linenum); switch (opcode) { /* Portable-specific options */ case sPAMAuthenticationViaKbdInt: intptr = &options->pam_authentication_via_kbd_int; goto parse_flag; /* Standard Options */ case sBadOption: return -1; case sPort: /* ignore ports from configfile if cmdline specifies ports */ if (options->ports_from_cmdline) return 0; if (options->listen_addrs != NULL) fatal("%s line %d: ports must be specified before " "ListenAddress.", filename, linenum); if (options->num_ports >= MAX_PORTS) fatal("%s line %d: too many ports.", filename, linenum); arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing port number.", filename, linenum); options->ports[options->num_ports++] = a2port(arg); if (options->ports[options->num_ports-1] == 0) fatal("%s line %d: Badly formatted port number.", filename, linenum); break; case sServerKeyBits: intptr = &options->server_key_bits; parse_int: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing integer value.", filename, linenum); value = atoi(arg); if (*intptr == -1) *intptr = value; break; case sLoginGraceTime: intptr = &options->login_grace_time; parse_time: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing time value.", filename, linenum); if ((value = convtime(arg)) == -1) fatal("%s line %d: invalid time value.", filename, linenum); if (*intptr == -1) *intptr = value; break; case sKeyRegenerationTime: intptr = &options->key_regeneration_time; goto parse_time; case sListenAddress: arg = strdelim(&cp); if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0) fatal("%s line %d: missing inet addr.", filename, linenum); if (*arg == '[') { if ((p = strchr(arg, ']')) == NULL) fatal("%s line %d: bad ipv6 inet addr usage.", filename, linenum); arg++; memmove(p, p+1, strlen(p+1)+1); } else if (((p = strchr(arg, ':')) == NULL) || (strchr(p+1, ':') != NULL)) { add_listen_addr(options, arg, 0); break; } if (*p == ':') { u_short port; p++; if (*p == '\0') fatal("%s line %d: bad inet addr:port usage.", filename, linenum); else { *(p-1) = '\0'; if ((port = a2port(p)) == 0) fatal("%s line %d: bad port number.", filename, linenum); add_listen_addr(options, arg, port); } } else if (*p == '\0') add_listen_addr(options, arg, 0); else fatal("%s line %d: bad inet addr usage.", filename, linenum); break; case sHostKeyFile: intptr = &options->num_host_key_files; if (*intptr >= MAX_HOSTKEYS) fatal("%s line %d: too many host keys specified (max %d).", filename, linenum, MAX_HOSTKEYS); charptr = &options->host_key_files[*intptr]; parse_filename: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing file name.", filename, linenum); if (*charptr == NULL) { *charptr = tilde_expand_filename(arg, getuid()); /* increase optional counter */ if (intptr != NULL) *intptr = *intptr + 1; } break; case sPidFile: charptr = &options->pid_file; goto parse_filename; case sPermitRootLogin: intptr = &options->permit_root_login; arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing yes/" "without-password/forced-commands-only/no " "argument.", filename, linenum); value = 0; /* silence compiler */ if (strcmp(arg, "without-password") == 0) value = PERMIT_NO_PASSWD; else if (strcmp(arg, "forced-commands-only") == 0) value = PERMIT_FORCED_ONLY; else if (strcmp(arg, "yes") == 0) value = PERMIT_YES; else if (strcmp(arg, "no") == 0) value = PERMIT_NO; else fatal("%s line %d: Bad yes/" "without-password/forced-commands-only/no " "argument: %s", filename, linenum, arg); if (*intptr == -1) *intptr = value; break; case sIgnoreRhosts: intptr = &options->ignore_rhosts; parse_flag: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing yes/no argument.", filename, linenum); value = 0; /* silence compiler */ if (strcmp(arg, "yes") == 0) value = 1; else if (strcmp(arg, "no") == 0) value = 0; else fatal("%s line %d: Bad yes/no argument: %s", filename, linenum, arg); if (*intptr == -1) *intptr = value; break; case sIgnoreUserKnownHosts: intptr = &options->ignore_user_known_hosts; goto parse_flag; case sRhostsAuthentication: intptr = &options->rhosts_authentication; goto parse_flag; case sRhostsRSAAuthentication: intptr = &options->rhosts_rsa_authentication; goto parse_flag; case sHostbasedAuthentication: intptr = &options->hostbased_authentication; goto parse_flag; case sHostbasedUsesNameFromPacketOnly: intptr = &options->hostbased_uses_name_from_packet_only; goto parse_flag; case sRSAAuthentication: intptr = &options->rsa_authentication; goto parse_flag; case sPubkeyAuthentication: intptr = &options->pubkey_authentication; goto parse_flag; #if defined(KRB4) || defined(KRB5) case sKerberosAuthentication: intptr = &options->kerberos_authentication; goto parse_flag; case sKerberosOrLocalPasswd: intptr = &options->kerberos_or_local_passwd; goto parse_flag; case sKerberosTicketCleanup: intptr = &options->kerberos_ticket_cleanup; goto parse_flag; #endif #if defined(AFS) || defined(KRB5) case sKerberosTgtPassing: intptr = &options->kerberos_tgt_passing; goto parse_flag; #endif #ifdef AFS case sAFSTokenPassing: intptr = &options->afs_token_passing; goto parse_flag; #endif case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; case sKbdInteractiveAuthentication: intptr = &options->kbd_interactive_authentication; goto parse_flag; case sChallengeResponseAuthentication: intptr = &options->challenge_response_authentication; goto parse_flag; case sPrintMotd: intptr = &options->print_motd; goto parse_flag; case sPrintLastLog: intptr = &options->print_lastlog; goto parse_flag; case sX11Forwarding: intptr = &options->x11_forwarding; goto parse_flag; case sX11DisplayOffset: intptr = &options->x11_display_offset; goto parse_int; case sX11UseLocalhost: intptr = &options->x11_use_localhost; goto parse_flag; case sXAuthLocation: charptr = &options->xauth_location; goto parse_filename; case sStrictModes: intptr = &options->strict_modes; goto parse_flag; case sKeepAlives: intptr = &options->keepalives; goto parse_flag; case sEmptyPasswd: intptr = &options->permit_empty_passwd; goto parse_flag; case sPermitUserEnvironment: intptr = &options->permit_user_env; goto parse_flag; case sUseLogin: intptr = &options->use_login; goto parse_flag; case sCompression: intptr = &options->compression; goto parse_flag; case sGatewayPorts: intptr = &options->gateway_ports; goto parse_flag; case sVerifyReverseMapping: intptr = &options->verify_reverse_mapping; goto parse_flag; case sLogFacility: intptr = (int *) &options->log_facility; arg = strdelim(&cp); value = log_facility_number(arg); if (value == SYSLOG_FACILITY_NOT_SET) fatal("%.200s line %d: unsupported log facility '%s'", filename, linenum, arg ? arg : "<NONE>"); if (*intptr == -1) *intptr = (SyslogFacility) value; break; case sLogLevel: intptr = (int *) &options->log_level; arg = strdelim(&cp); value = log_level_number(arg); if (value == SYSLOG_LEVEL_NOT_SET) fatal("%.200s line %d: unsupported log level '%s'", filename, linenum, arg ? arg : "<NONE>"); if (*intptr == -1) *intptr = (LogLevel) value; break; case sAllowTcpForwarding: intptr = &options->allow_tcp_forwarding; goto parse_flag; case sUsePrivilegeSeparation: intptr = &use_privsep; goto parse_flag; case sAllowUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_allow_users >= MAX_ALLOW_USERS) fatal("%s line %d: too many allow users.", filename, linenum); options->allow_users[options->num_allow_users++] = xstrdup(arg); } break; case sDenyUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_deny_users >= MAX_DENY_USERS) fatal( "%s line %d: too many deny users.", filename, linenum); options->deny_users[options->num_deny_users++] = xstrdup(arg); } break; case sAllowGroups: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_allow_groups >= MAX_ALLOW_GROUPS) fatal("%s line %d: too many allow groups.", filename, linenum); options->allow_groups[options->num_allow_groups++] = xstrdup(arg); } break; case sDenyGroups: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_deny_groups >= MAX_DENY_GROUPS) fatal("%s line %d: too many deny groups.", filename, linenum); options->deny_groups[options->num_deny_groups++] = xstrdup(arg); } break; case sCiphers: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); if (!ciphers_valid(arg)) fatal("%s line %d: Bad SSH2 cipher spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (options->ciphers == NULL) options->ciphers = xstrdup(arg); break; case sMacs: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); if (!mac_valid(arg)) fatal("%s line %d: Bad SSH2 mac spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (options->macs == NULL) options->macs = xstrdup(arg); break; case sProtocol: intptr = &options->protocol; arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); value = proto_spec(arg); if (value == SSH_PROTO_UNKNOWN) fatal("%s line %d: Bad protocol spec '%s'.", filename, linenum, arg ? arg : "<NONE>"); if (*intptr == SSH_PROTO_UNKNOWN) *intptr = value; break; case sSubsystem: if (options->num_subsystems >= MAX_SUBSYSTEMS) { fatal("%s line %d: too many subsystems defined.", filename, linenum); } arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing subsystem name.", filename, linenum); for (i = 0; i < options->num_subsystems; i++) if (strcmp(arg, options->subsystem_name[i]) == 0) fatal("%s line %d: Subsystem '%s' already defined.", filename, linenum, arg); options->subsystem_name[options->num_subsystems] = xstrdup(arg); arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing subsystem command.", filename, linenum); options->subsystem_command[options->num_subsystems] = xstrdup(arg); options->num_subsystems++; break; case sMaxStartups: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing MaxStartups spec.", filename, linenum); if ((n = sscanf(arg, "%d:%d:%d", &options->max_startups_begin, &options->max_startups_rate, &options->max_startups)) == 3) { if (options->max_startups_begin > options->max_startups || options->max_startups_rate > 100 || options->max_startups_rate < 1) fatal("%s line %d: Illegal MaxStartups spec.", filename, linenum); } else if (n != 1) fatal("%s line %d: Illegal MaxStartups spec.", filename, linenum); else options->max_startups = options->max_startups_begin; break; case sBanner: charptr = &options->banner; goto parse_filename; /* * These options can contain %X options expanded at * connect time, so that you can specify paths like: * * AuthorizedKeysFile /etc/ssh_keys/%u */ case sAuthorizedKeysFile: case sAuthorizedKeysFile2: charptr = (opcode == sAuthorizedKeysFile ) ? &options->authorized_keys_file : &options->authorized_keys_file2; goto parse_filename; case sClientAliveInterval: intptr = &options->client_alive_interval; goto parse_time; case sClientAliveCountMax: intptr = &options->client_alive_count_max; goto parse_int; case sDeprecated: log("%s line %d: Deprecated option %s", filename, linenum, arg); while (arg) arg = strdelim(&cp); break; default: fatal("%s line %d: Missing handler for opcode %s (%d)", filename, linenum, arg, opcode); } if ((arg = strdelim(&cp)) != NULL && *arg != '\0') fatal("%s line %d: garbage at end of line; \"%.200s\".", filename, linenum, arg); return 0; }