summaryrefslogtreecommitdiff
path: root/servconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'servconf.c')
-rw-r--r--servconf.c288
1 files changed, 201 insertions, 87 deletions
diff --git a/servconf.c b/servconf.c
index 0f0d090686b1..c0f6af0bee9a 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: servconf.c,v 1.326 2018/03/01 20:32:16 markus Exp $ */
+/* $OpenBSD: servconf.c,v 1.340 2018/08/12 20:19:13 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -45,13 +45,13 @@
#include "xmalloc.h"
#include "ssh.h"
#include "log.h"
-#include "buffer.h"
+#include "sshbuf.h"
#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "pathnames.h"
#include "cipher.h"
-#include "key.h"
+#include "sshkey.h"
#include "kex.h"
#include "mac.h"
#include "match.h"
@@ -59,6 +59,7 @@
#include "groupaccess.h"
#include "canohost.h"
#include "packet.h"
+#include "ssherr.h"
#include "hostfile.h"
#include "auth.h"
#include "myproposal.h"
@@ -71,7 +72,7 @@ static void add_one_listen_addr(ServerOptions *, const char *,
/* Use of privilege separation or not */
extern int use_privsep;
-extern Buffer cfg;
+extern struct sshbuf *cfg;
/* Initializes the server options to their default values. */
@@ -130,6 +131,7 @@ initialize_server_options(ServerOptions *options)
options->challenge_response_authentication = -1;
options->permit_empty_passwd = -1;
options->permit_user_env = -1;
+ options->permit_user_env_whitelist = NULL;
options->compression = -1;
options->rekey_limit = -1;
options->rekey_interval = -1;
@@ -158,8 +160,10 @@ initialize_server_options(ServerOptions *options)
options->client_alive_count_max = -1;
options->num_authkeys_files = 0;
options->num_accept_env = 0;
+ options->num_setenv = 0;
options->permit_tun = -1;
options->permitted_opens = NULL;
+ options->permitted_listens = NULL;
options->adm_forced_command = NULL;
options->chroot_directory = NULL;
options->authorized_keys_command = NULL;
@@ -187,15 +191,29 @@ option_clear_or_none(const char *o)
static void
assemble_algorithms(ServerOptions *o)
{
- if (kex_assemble_names(KEX_SERVER_ENCRYPT, &o->ciphers) != 0 ||
- kex_assemble_names(KEX_SERVER_MAC, &o->macs) != 0 ||
- kex_assemble_names(KEX_SERVER_KEX, &o->kex_algorithms) != 0 ||
- kex_assemble_names(KEX_DEFAULT_PK_ALG,
- &o->hostkeyalgorithms) != 0 ||
- kex_assemble_names(KEX_DEFAULT_PK_ALG,
- &o->hostbased_key_types) != 0 ||
- kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->pubkey_key_types) != 0)
- fatal("kex_assemble_names failed");
+ char *all_cipher, *all_mac, *all_kex, *all_key;
+ int r;
+
+ all_cipher = cipher_alg_list(',', 0);
+ all_mac = mac_alg_list(',');
+ all_kex = kex_alg_list(',');
+ all_key = sshkey_alg_list(0, 0, 1, ',');
+#define ASSEMBLE(what, defaults, all) \
+ do { \
+ if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
+ fatal("%s: %s: %s", __func__, #what, ssh_err(r)); \
+ } while (0)
+ ASSEMBLE(ciphers, KEX_SERVER_ENCRYPT, all_cipher);
+ ASSEMBLE(macs, KEX_SERVER_MAC, all_mac);
+ ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, all_kex);
+ ASSEMBLE(hostkeyalgorithms, KEX_DEFAULT_PK_ALG, all_key);
+ ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key);
+ ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key);
+#undef ASSEMBLE
+ free(all_cipher);
+ free(all_mac);
+ free(all_kex);
+ free(all_key);
}
static void
@@ -327,8 +345,10 @@ fill_default_server_options(ServerOptions *options)
options->challenge_response_authentication = 1;
if (options->permit_empty_passwd == -1)
options->permit_empty_passwd = 0;
- if (options->permit_user_env == -1)
+ if (options->permit_user_env == -1) {
options->permit_user_env = 0;
+ options->permit_user_env_whitelist = NULL;
+ }
if (options->compression == -1)
options->compression = COMP_DELAYED;
if (options->rekey_limit == -1)
@@ -372,9 +392,9 @@ fill_default_server_options(ServerOptions *options)
if (options->permit_tun == -1)
options->permit_tun = SSH_TUNMODE_NO;
if (options->ip_qos_interactive == -1)
- options->ip_qos_interactive = IPTOS_LOWDELAY;
+ options->ip_qos_interactive = IPTOS_DSCP_AF21;
if (options->ip_qos_bulk == -1)
- options->ip_qos_bulk = IPTOS_THROUGHPUT;
+ options->ip_qos_bulk = IPTOS_DSCP_CS1;
if (options->version_addendum == NULL)
options->version_addendum = xstrdup("");
if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
@@ -461,8 +481,8 @@ typedef enum {
sHostKeyAlgorithms,
sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
- sAcceptEnv, sPermitTunnel,
- sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
+ sAcceptEnv, sSetEnv, sPermitTunnel,
+ sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
sUsePrivilegeSeparation, sAllowAgentForwarding,
sHostCertificate,
sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
@@ -544,7 +564,7 @@ static struct {
{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
{ "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
- { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
+ { "skeyauthentication", sDeprecated, SSHCFG_GLOBAL },
{ "checkmail", sDeprecated, SSHCFG_GLOBAL },
{ "listenaddress", sListenAddress, SSHCFG_GLOBAL },
{ "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
@@ -592,11 +612,13 @@ static struct {
{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
{ "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL},
{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
+ { "setenv", sSetEnv, SSHCFG_ALL },
{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
{ "permittty", sPermitTTY, SSHCFG_ALL },
{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
{ "match", sMatch, SSHCFG_ALL },
{ "permitopen", sPermitOpen, SSHCFG_ALL },
+ { "permitlisten", sPermitListen, SSHCFG_ALL },
{ "forcecommand", sForceCommand, SSHCFG_ALL },
{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
@@ -632,6 +654,20 @@ static struct {
{ -1, NULL }
};
+/* Returns an opcode name from its number */
+
+static const char *
+lookup_opcode_name(ServerOpCodes code)
+{
+ u_int i;
+
+ for (i = 0; keywords[i].name != NULL; i++)
+ if (keywords[i].opcode == code)
+ return(keywords[i].name);
+ return "UNKNOWN";
+}
+
+
/*
* Returns the number of the token pointed to by cp or sBadOption.
*/
@@ -814,43 +850,59 @@ process_queued_listen_addrs(ServerOptions *options)
}
/*
- * Inform channels layer of permitopen options from configuration.
+ * Inform channels layer of permitopen options for a single forwarding
+ * direction (local/remote).
*/
-void
-process_permitopen(struct ssh *ssh, ServerOptions *options)
+static void
+process_permitopen_list(struct ssh *ssh, ServerOpCodes opcode,
+ char **opens, u_int num_opens)
{
u_int i;
int port;
char *host, *arg, *oarg;
+ int where = opcode == sPermitOpen ? FORWARD_LOCAL : FORWARD_REMOTE;
+ const char *what = lookup_opcode_name(opcode);
- channel_clear_adm_permitted_opens(ssh);
- if (options->num_permitted_opens == 0)
+ channel_clear_permission(ssh, FORWARD_ADM, where);
+ if (num_opens == 0)
return; /* permit any */
/* handle keywords: "any" / "none" */
- if (options->num_permitted_opens == 1 &&
- strcmp(options->permitted_opens[0], "any") == 0)
+ if (num_opens == 1 && strcmp(opens[0], "any") == 0)
return;
- if (options->num_permitted_opens == 1 &&
- strcmp(options->permitted_opens[0], "none") == 0) {
- channel_disable_adm_local_opens(ssh);
+ if (num_opens == 1 && strcmp(opens[0], "none") == 0) {
+ channel_disable_admin(ssh, where);
return;
}
/* Otherwise treat it as a list of permitted host:port */
- for (i = 0; i < options->num_permitted_opens; i++) {
- oarg = arg = xstrdup(options->permitted_opens[i]);
+ for (i = 0; i < num_opens; i++) {
+ oarg = arg = xstrdup(opens[i]);
host = hpdelim(&arg);
if (host == NULL)
- fatal("%s: missing host in PermitOpen", __func__);
+ fatal("%s: missing host in %s", __func__, what);
host = cleanhostname(host);
if (arg == NULL || ((port = permitopen_port(arg)) < 0))
- fatal("%s: bad port number in PermitOpen", __func__);
+ fatal("%s: bad port number in %s", __func__, what);
/* Send it to channels layer */
- channel_add_adm_permitted_opens(ssh, host, port);
+ channel_add_permission(ssh, FORWARD_ADM,
+ where, host, port);
free(oarg);
}
}
+/*
+ * Inform channels layer of permitopen options from configuration.
+ */
+void
+process_permitopen(struct ssh *ssh, ServerOptions *options)
+{
+ process_permitopen_list(ssh, sPermitOpen,
+ options->permitted_opens, options->num_permitted_opens);
+ process_permitopen_list(ssh, sPermitListen,
+ options->permitted_listens,
+ options->num_permitted_listens);
+}
+
struct connection_info *
get_connection_info(int populate, int use_dns)
{
@@ -1144,12 +1196,12 @@ process_server_config_line(ServerOptions *options, char *line,
const char *filename, int linenum, int *activep,
struct connection_info *connectinfo)
{
- char *cp, **charptr, *arg, *arg2, *p;
+ char *cp, ***chararrayptr, **charptr, *arg, *arg2, *p;
int cmdline = 0, *intptr, value, value2, n, port;
SyslogFacility *log_facility_ptr;
LogLevel *log_level_ptr;
ServerOpCodes opcode;
- u_int i, flags = 0;
+ u_int i, *uintptr, uvalue, flags = 0;
size_t len;
long long val64;
const struct multistate *multistate_ptr;
@@ -1480,7 +1532,29 @@ process_server_config_line(ServerOptions *options, char *line,
case sPermitUserEnvironment:
intptr = &options->permit_user_env;
- goto parse_flag;
+ charptr = &options->permit_user_env_whitelist;
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing argument.",
+ filename, linenum);
+ value = 0;
+ p = NULL;
+ if (strcmp(arg, "yes") == 0)
+ value = 1;
+ else if (strcmp(arg, "no") == 0)
+ value = 0;
+ else {
+ /* Pattern-list specified */
+ value = 1;
+ p = xstrdup(arg);
+ }
+ if (*activep && *intptr == -1) {
+ *intptr = value;
+ *charptr = p;
+ p = NULL;
+ }
+ free(p);
+ break;
case sCompression:
intptr = &options->compression;
@@ -1769,6 +1843,19 @@ process_server_config_line(ServerOptions *options, char *line,
}
break;
+ case sSetEnv:
+ uvalue = options->num_setenv;
+ while ((arg = strdelimw(&cp)) && *arg != '\0') {
+ if (strchr(arg, '=') == NULL)
+ fatal("%s line %d: Invalid environment.",
+ filename, linenum);
+ if (!*activep || uvalue != 0)
+ continue;
+ array_append(filename, linenum, "SetEnv",
+ &options->setenv, &options->num_setenv, arg);
+ }
+ break;
+
case sPermitTunnel:
intptr = &options->permit_tun;
arg = strdelim(&cp);
@@ -1799,36 +1886,57 @@ process_server_config_line(ServerOptions *options, char *line,
*activep = value;
break;
+ case sPermitListen:
case sPermitOpen:
+ if (opcode == sPermitListen) {
+ uintptr = &options->num_permitted_listens;
+ chararrayptr = &options->permitted_listens;
+ } else {
+ uintptr = &options->num_permitted_opens;
+ chararrayptr = &options->permitted_opens;
+ }
arg = strdelim(&cp);
if (!arg || *arg == '\0')
- fatal("%s line %d: missing PermitOpen specification",
- filename, linenum);
- value = options->num_permitted_opens; /* modified later */
+ fatal("%s line %d: missing %s specification",
+ filename, linenum, lookup_opcode_name(opcode));
+ uvalue = *uintptr; /* modified later */
if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
- if (*activep && value == 0) {
- options->num_permitted_opens = 1;
- options->permitted_opens = xcalloc(1,
- sizeof(*options->permitted_opens));
- options->permitted_opens[0] = xstrdup(arg);
+ if (*activep && uvalue == 0) {
+ *uintptr = 1;
+ *chararrayptr = xcalloc(1,
+ sizeof(**chararrayptr));
+ (*chararrayptr)[0] = xstrdup(arg);
}
break;
}
for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
- arg2 = xstrdup(arg);
- p = hpdelim(&arg);
- if (p == NULL)
- fatal("%s line %d: missing host in PermitOpen",
- filename, linenum);
- p = cleanhostname(p);
- if (arg == NULL || ((port = permitopen_port(arg)) < 0))
- fatal("%s line %d: bad port number in "
- "PermitOpen", filename, linenum);
- if (*activep && value == 0) {
+ if (opcode == sPermitListen &&
+ strchr(arg, ':') == NULL) {
+ /*
+ * Allow bare port number for PermitListen
+ * to indicate a wildcard listen host.
+ */
+ xasprintf(&arg2, "*:%s", arg);
+ } else {
+ arg2 = xstrdup(arg);
+ p = hpdelim(&arg);
+ if (p == NULL) {
+ fatal("%s line %d: missing host in %s",
+ filename, linenum,
+ lookup_opcode_name(opcode));
+ }
+ p = cleanhostname(p);
+ }
+ if (arg == NULL ||
+ ((port = permitopen_port(arg)) < 0)) {
+ fatal("%s line %d: bad port number in %s",
+ filename, linenum,
+ lookup_opcode_name(opcode));
+ }
+ if (*activep && uvalue == 0) {
array_append(filename, linenum,
- "PermitOpen",
- &options->permitted_opens,
- &options->num_permitted_opens, arg2);
+ lookup_opcode_name(opcode),
+ chararrayptr, uintptr, arg2);
}
free(arg2);
}
@@ -1951,7 +2059,7 @@ process_server_config_line(ServerOptions *options, char *line,
case sAuthenticationMethods:
if (options->num_auth_methods == 0) {
value = 0; /* seen "any" pseudo-method */
- value2 = 0; /* sucessfully parsed any method */
+ value2 = 0; /* successfully parsed any method */
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (strcmp(arg, "any") == 0) {
if (options->num_auth_methods > 0) {
@@ -2056,22 +2164,21 @@ process_server_config_line(ServerOptions *options, char *line,
/* Reads the server configuration file. */
void
-load_server_config(const char *filename, Buffer *conf)
+load_server_config(const char *filename, struct sshbuf *conf)
{
- char line[4096], *cp;
+ char *line = NULL, *cp;
+ size_t linesize = 0;
FILE *f;
- int lineno = 0;
+ int r, lineno = 0;
debug2("%s: filename %s", __func__, filename);
if ((f = fopen(filename, "r")) == NULL) {
perror(filename);
exit(1);
}
- buffer_clear(conf);
- while (fgets(line, sizeof(line), f)) {
+ sshbuf_reset(conf);
+ while (getline(&line, &linesize, f) != -1) {
lineno++;
- if (strlen(line) == sizeof(line) - 1)
- fatal("%s line %d too long", filename, lineno);
/*
* Trim out comments and strip whitespace
* NB - preserve newlines, they are needed to reproduce
@@ -2080,12 +2187,14 @@ load_server_config(const char *filename, Buffer *conf)
if ((cp = strchr(line, '#')) != NULL)
memcpy(cp, "\n", 2);
cp = line + strspn(line, " \t\r");
-
- buffer_append(conf, cp, strlen(cp));
+ if ((r = sshbuf_put(conf, cp, strlen(cp))) != 0)
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
}
- buffer_append(conf, "\0", 1);
+ free(line);
+ if ((r = sshbuf_put_u8(conf, 0)) != 0)
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
fclose(f);
- debug2("%s: done config len = %d", __func__, buffer_len(conf));
+ debug2("%s: done config len = %zu", __func__, sshbuf_len(conf));
}
void
@@ -2095,7 +2204,7 @@ parse_server_match_config(ServerOptions *options,
ServerOptions mo;
initialize_server_options(&mo);
- parse_server_config(&mo, "reprocess config", &cfg, connectinfo);
+ parse_server_config(&mo, "reprocess config", cfg, connectinfo);
copy_set_server_options(options, &mo, 0);
}
@@ -2135,7 +2244,7 @@ int parse_server_match_testspec(struct connection_info *ci, char *spec)
*
* If the preauth flag is set, we do not bother copying the string or
* array values that are not used pre-authentication, because any that we
- * do use must be explictly sent in mm_getpwnamallow().
+ * do use must be explicitly sent in mm_getpwnamallow().
*/
void
copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
@@ -2239,13 +2348,13 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
#undef M_CP_STRARRAYOPT
void
-parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
- struct connection_info *connectinfo)
+parse_server_config(ServerOptions *options, const char *filename,
+ struct sshbuf *conf, struct connection_info *connectinfo)
{
int active, linenum, bad_options = 0;
char *cp, *obuf, *cbuf;
- debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
+ debug2("%s: config %s len %zu", __func__, filename, sshbuf_len(conf));
if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
fatal("%s: sshbuf_dup_string failed", __func__);
@@ -2307,17 +2416,6 @@ fmt_intarg(ServerOpCodes code, int val)
}
}
-static const char *
-lookup_opcode_name(ServerOpCodes code)
-{
- u_int i;
-
- for (i = 0; keywords[i].name != NULL; i++)
- if (keywords[i].opcode == code)
- return(keywords[i].name);
- return "UNKNOWN";
-}
-
static void
dump_cfg_int(ServerOpCodes code, int val)
{
@@ -2471,7 +2569,6 @@ dump_config(ServerOptions *o)
dump_cfg_fmtint(sStrictModes, o->strict_modes);
dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
- dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
dump_cfg_fmtint(sCompression, o->compression);
dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
dump_cfg_fmtint(sUseDNS, o->use_dns);
@@ -2528,6 +2625,7 @@ dump_config(ServerOptions *o)
dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
+ dump_cfg_strarray(sSetEnv, o->num_setenv, o->setenv);
dump_cfg_strarray_oneline(sAuthenticationMethods,
o->num_auth_methods, o->auth_methods);
@@ -2562,4 +2660,20 @@ dump_config(ServerOptions *o)
printf(" %s", o->permitted_opens[i]);
}
printf("\n");
+ printf("permitlisten");
+ if (o->num_permitted_listens == 0)
+ printf(" any");
+ else {
+ for (i = 0; i < o->num_permitted_listens; i++)
+ printf(" %s", o->permitted_listens[i]);
+ }
+ printf("\n");
+
+ if (o->permit_user_env_whitelist == NULL) {
+ dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
+ } else {
+ printf("permituserenvironment %s\n",
+ o->permit_user_env_whitelist);
+ }
+
}