X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/5188ba17523a6e5e1ac4b55f910f79610070f9d8..5498741cc14208f105eb8341046536b21a0c31db:/servconf.c diff --git a/servconf.c b/servconf.c index 330e7914..1a754517 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.155 2006/07/17 01:31:09 stevesk Exp $ */ +/* $OpenBSD: servconf.c,v 1.172 2007/04/23 10:15:39 dtucker Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -15,22 +15,30 @@ #include #include -#if defined(HAVE_NETDB_H) -# include -#endif +#include +#include +#include +#include +#include +#include #include +#include +#include "xmalloc.h" #include "ssh.h" #include "log.h" +#include "buffer.h" #include "servconf.h" -#include "xmalloc.h" #include "compat.h" #include "pathnames.h" #include "misc.h" #include "cipher.h" +#include "key.h" #include "kex.h" #include "mac.h" #include "match.h" +#include "channels.h" +#include "groupaccess.h" static void add_listen_addr(ServerOptions *, char *, u_short); static void add_one_listen_addr(ServerOptions *, char *, u_short); @@ -112,6 +120,8 @@ initialize_server_options(ServerOptions *options) options->authorized_keys_file2 = NULL; options->num_accept_env = 0; options->permit_tun = -1; + options->num_permitted_opens = -1; + options->adm_forced_command = NULL; } void @@ -281,7 +291,7 @@ typedef enum { sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, - sMatch, + sMatch, sPermitOpen, sForceCommand, sUsePrivilegeSeparation, sDeprecated, sUnsupported } ServerOpCodes; @@ -315,14 +325,14 @@ static struct { { "syslogfacility", sLogFacility, SSHCFG_GLOBAL }, { "loglevel", sLogLevel, SSHCFG_GLOBAL }, { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL }, - { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_GLOBAL }, - { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_GLOBAL }, + { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL }, + { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL }, { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_GLOBAL }, - { "rsaauthentication", sRSAAuthentication, SSHCFG_GLOBAL }, - { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, + { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL }, + { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL }, { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */ #ifdef KRB5 - { "kerberosauthentication", sKerberosAuthentication, SSHCFG_GLOBAL }, + { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL }, { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL }, { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL }, #ifdef USE_AFS @@ -331,7 +341,7 @@ static struct { { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, #endif #else - { "kerberosauthentication", sUnsupported, SSHCFG_GLOBAL }, + { "kerberosauthentication", sUnsupported, SSHCFG_ALL }, { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL }, { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL }, { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, @@ -339,14 +349,14 @@ static struct { { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, #ifdef GSSAPI - { "gssapiauthentication", sGssAuthentication, SSHCFG_GLOBAL }, + { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, #else - { "gssapiauthentication", sUnsupported, SSHCFG_GLOBAL }, + { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, #endif - { "passwordauthentication", sPasswordAuthentication, SSHCFG_GLOBAL }, - { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_GLOBAL }, + { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, + { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */ { "checkmail", sDeprecated, SSHCFG_GLOBAL }, @@ -356,9 +366,9 @@ static struct { { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL }, { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL }, { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL }, - { "x11forwarding", sX11Forwarding, SSHCFG_GLOBAL }, - { "x11displayoffset", sX11DisplayOffset, SSHCFG_GLOBAL }, - { "x11uselocalhost", sX11UseLocalhost, SSHCFG_GLOBAL }, + { "x11forwarding", sX11Forwarding, SSHCFG_ALL }, + { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL }, + { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL }, { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL }, { "strictmodes", sStrictModes, SSHCFG_GLOBAL }, { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL }, @@ -379,7 +389,7 @@ static struct { { "subsystem", sSubsystem, SSHCFG_GLOBAL }, { "maxstartups", sMaxStartups, SSHCFG_GLOBAL }, { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL }, - { "banner", sBanner, SSHCFG_GLOBAL }, + { "banner", sBanner, SSHCFG_ALL }, { "usedns", sUseDNS, SSHCFG_GLOBAL }, { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL }, @@ -390,6 +400,9 @@ static struct { { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL }, { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL }, { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL }, + { "match", sMatch, SSHCFG_ALL }, + { "permitopen", sPermitOpen, SSHCFG_ALL }, + { "forcecommand", sForceCommand, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; @@ -485,6 +498,51 @@ add_one_listen_addr(ServerOptions *options, char *addr, u_short port) * PermittedChannelRequests session,forwarded-tcpip */ +static int +match_cfg_line_group(const char *grps, int line, const char *user) +{ + int result = 0; + u_int ngrps = 0; + char *arg, *p, *cp, *grplist[MAX_MATCH_GROUPS]; + struct passwd *pw; + + /* + * Even if we do not have a user yet, we still need to check for + * valid syntax. + */ + arg = cp = xstrdup(grps); + while ((p = strsep(&cp, ",")) != NULL && *p != '\0') { + if (ngrps >= MAX_MATCH_GROUPS) { + error("line %d: too many groups in Match Group", line); + result = -1; + goto out; + } + grplist[ngrps++] = p; + } + + if (user == NULL) + goto out; + + if ((pw = getpwnam(user)) == NULL) { + debug("Can't match group at line %d because user %.100s does " + "not exist", line, user); + } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) { + debug("Can't Match group because user %.100s not in any group " + "at line %d", user, line); + } else if (ga_match(grplist, ngrps) != 1) { + debug("user %.100s does not match group %.100s at line %d", + user, arg, line); + } else { + debug("user %.100s matched group %.100s at line %d", user, + arg, line); + result = 1; + } +out: + ga_free(); + xfree(arg); + return result; +} + static int match_cfg_line(char **condition, int line, const char *user, const char *host, const char *address) @@ -516,6 +574,13 @@ match_cfg_line(char **condition, int line, const char *user, const char *host, else debug("user %.100s matched 'User %.100s' at " "line %d", user, arg, line); + } else if (strcasecmp(attrib, "group") == 0) { + switch (match_cfg_line_group(arg, line, user)) { + case -1: + return -1; + case 0: + result = 0; + } } else if (strcasecmp(attrib, "host") == 0) { if (!host) { result = 0; @@ -527,7 +592,6 @@ match_cfg_line(char **condition, int line, const char *user, const char *host, debug("connection from %.100s matched 'Host " "%.100s' at line %d", host, arg, line); } else if (strcasecmp(attrib, "address") == 0) { - debug("address '%s' arg '%s'", address, arg); if (!address) { result = 0; continue; @@ -548,6 +612,8 @@ match_cfg_line(char **condition, int line, const char *user, const char *host, return result; } +#define WHITESPACE " \t\r\n" + int process_server_config_line(ServerOptions *options, char *line, const char *filename, int linenum, int *activep, const char *user, @@ -901,7 +967,7 @@ parse_flag: else fatal("%s line %d: Bad yes/no/clientspecified " "argument: %s", filename, linenum, arg); - if (*intptr == -1) + if (*activep && *intptr == -1) *intptr = value; break; @@ -952,7 +1018,7 @@ parse_flag: case sDenyUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_deny_users >= MAX_DENY_USERS) - fatal( "%s line %d: too many deny users.", + fatal("%s line %d: too many deny users.", filename, linenum); options->deny_users[options->num_deny_users++] = xstrdup(arg); @@ -1087,7 +1153,7 @@ parse_flag: */ case sAuthorizedKeysFile: case sAuthorizedKeysFile2: - charptr = (opcode == sAuthorizedKeysFile ) ? + charptr = (opcode == sAuthorizedKeysFile) ? &options->authorized_keys_file : &options->authorized_keys_file2; goto parse_filename; @@ -1148,6 +1214,45 @@ parse_flag: *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 sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); @@ -1211,19 +1316,55 @@ parse_server_match_config(ServerOptions *options, const char *user, initialize_server_options(&mo); parse_server_config(&mo, "reprocess config", &cfg, user, host, address); - copy_set_server_options(options, &mo); + copy_set_server_options(options, &mo, 0); } -/* Copy any (supported) values that are set */ +/* Helper macros */ +#define M_CP_INTOPT(n) do {\ + if (src->n != -1) \ + dst->n = src->n; \ +} while (0) +#define M_CP_STROPT(n) do {\ + if (src->n != NULL) { \ + if (dst->n != NULL) \ + xfree(dst->n); \ + dst->n = src->n; \ + } \ +} while(0) + +/* + * Copy any supported values that are set. + * + * If the preauth flag is set, we do not bother copying the the string or + * array values that are not used pre-authentication, because any that we + * do use must be explictly sent in mm_getpwnamallow(). + */ void -copy_set_server_options(ServerOptions *dst, ServerOptions *src) +copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) { - if (src->allow_tcp_forwarding != -1) - dst->allow_tcp_forwarding = src->allow_tcp_forwarding; - if (src->gateway_ports != -1) - dst->gateway_ports = src->gateway_ports; + M_CP_INTOPT(password_authentication); + M_CP_INTOPT(gss_authentication); + M_CP_INTOPT(rsa_authentication); + M_CP_INTOPT(pubkey_authentication); + M_CP_INTOPT(kerberos_authentication); + M_CP_INTOPT(hostbased_authentication); + M_CP_INTOPT(kbd_interactive_authentication); + + M_CP_INTOPT(allow_tcp_forwarding); + M_CP_INTOPT(gateway_ports); + M_CP_INTOPT(x11_display_offset); + M_CP_INTOPT(x11_forwarding); + M_CP_INTOPT(x11_use_localhost); + + M_CP_STROPT(banner); + if (preauth) + return; + M_CP_STROPT(adm_forced_command); } +#undef M_CP_INTOPT +#undef M_CP_STROPT + void parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, const char *user, const char *host, const char *address)