[BACK]Return to servconf.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/servconf.c between version 1.146 and 1.146.2.1

version 1.146, 2005/12/08 18:34:11 version 1.146.2.1, 2006/09/30 04:06:51
Line 1 
Line 1 
   /* $OpenBSD$ */
 /*  /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland   * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved   *                    All rights reserved
Line 9 
Line 10 
  * called by a name other than "ssh" or "Secure Shell".   * called by a name other than "ssh" or "Secure Shell".
  */   */
   
 #include "includes.h"  #include <sys/types.h>
 RCSID("$OpenBSD$");  #include <sys/socket.h>
   
   #include <netdb.h>
   #include <pwd.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <signal.h>
   #include <unistd.h>
   #include <stdarg.h>
   
   #include "xmalloc.h"
 #include "ssh.h"  #include "ssh.h"
 #include "log.h"  #include "log.h"
   #include "buffer.h"
 #include "servconf.h"  #include "servconf.h"
 #include "xmalloc.h"  
 #include "compat.h"  #include "compat.h"
 #include "pathnames.h"  #include "pathnames.h"
 #include "misc.h"  #include "misc.h"
 #include "cipher.h"  #include "cipher.h"
   #include "key.h"
 #include "kex.h"  #include "kex.h"
 #include "mac.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_listen_addr(ServerOptions *, char *, u_short);
 static void add_one_listen_addr(ServerOptions *, char *, u_short);  static void add_one_listen_addr(ServerOptions *, char *, u_short);
   
 /* Use of privilege separation or not */  /* Use of privilege separation or not */
 extern int use_privsep;  extern int use_privsep;
   extern Buffer cfg;
   
 /* Initializes the server options to their default values. */  /* Initializes the server options to their default values. */
   
Line 97 
Line 113 
         options->authorized_keys_file2 = NULL;          options->authorized_keys_file2 = NULL;
         options->num_accept_env = 0;          options->num_accept_env = 0;
         options->permit_tun = -1;          options->permit_tun = -1;
           options->num_permitted_opens = -1;
         /* Needs to be accessable in many places */          options->adm_forced_command = NULL;
         use_privsep = -1;  
 }  }
   
 void  void
Line 251 
Line 266 
         sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,          sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
         sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,          sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
         sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,          sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
           sMatch, sPermitOpen, sForceCommand,
         sUsePrivilegeSeparation,          sUsePrivilegeSeparation,
         sDeprecated, sUnsupported          sDeprecated, sUnsupported
 } ServerOpCodes;  } ServerOpCodes;
   
   #define SSHCFG_GLOBAL   0x01    /* allowed in main section of sshd_config */
   #define SSHCFG_MATCH    0x02    /* allowed inside a Match section */
   #define SSHCFG_ALL      (SSHCFG_GLOBAL|SSHCFG_MATCH)
   
 /* Textual representation of the tokens. */  /* Textual representation of the tokens. */
 static struct {  static struct {
         const char *name;          const char *name;
         ServerOpCodes opcode;          ServerOpCodes opcode;
           u_int flags;
 } keywords[] = {  } keywords[] = {
         { "port", sPort },          { "port", sPort, SSHCFG_GLOBAL },
         { "hostkey", sHostKeyFile },          { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
         { "hostdsakey", sHostKeyFile },                                 /* alias */          { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },          /* alias */
         { "pidfile", sPidFile },          { "pidfile", sPidFile, SSHCFG_GLOBAL },
         { "serverkeybits", sServerKeyBits },          { "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
         { "logingracetime", sLoginGraceTime },          { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
         { "keyregenerationinterval", sKeyRegenerationTime },          { "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
         { "permitrootlogin", sPermitRootLogin },          { "permitrootlogin", sPermitRootLogin, SSHCFG_GLOBAL },
         { "syslogfacility", sLogFacility },          { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
         { "loglevel", sLogLevel },          { "loglevel", sLogLevel, SSHCFG_GLOBAL },
         { "rhostsauthentication", sDeprecated },          { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
         { "rhostsrsaauthentication", sRhostsRSAAuthentication },          { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_GLOBAL },
         { "hostbasedauthentication", sHostbasedAuthentication },          { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_GLOBAL },
         { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly },          { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_GLOBAL },
         { "rsaauthentication", sRSAAuthentication },          { "rsaauthentication", sRSAAuthentication, SSHCFG_GLOBAL },
         { "pubkeyauthentication", sPubkeyAuthentication },          { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL },
         { "dsaauthentication", sPubkeyAuthentication },                 /* alias */          { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
 #ifdef KRB5  #ifdef KRB5
         { "kerberosauthentication", sKerberosAuthentication },          { "kerberosauthentication", sKerberosAuthentication, SSHCFG_GLOBAL },
         { "kerberosorlocalpasswd", sKerberosOrLocalPasswd },          { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
         { "kerberosticketcleanup", sKerberosTicketCleanup },          { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
         { "kerberosgetafstoken", sKerberosGetAFSToken },          { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
 #else  #else
         { "kerberosauthentication", sUnsupported },          { "kerberosauthentication", sUnsupported, SSHCFG_GLOBAL },
         { "kerberosorlocalpasswd", sUnsupported },          { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
         { "kerberosticketcleanup", sUnsupported },          { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
         { "kerberosgetafstoken", sUnsupported },          { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
 #endif  #endif
         { "kerberostgtpassing", sUnsupported },          { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
         { "afstokenpassing", sUnsupported },          { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
 #ifdef GSSAPI  #ifdef GSSAPI
         { "gssapiauthentication", sGssAuthentication },          { "gssapiauthentication", sGssAuthentication, SSHCFG_GLOBAL },
         { "gssapicleanupcredentials", sGssCleanupCreds },          { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
 #else  #else
         { "gssapiauthentication", sUnsupported },          { "gssapiauthentication", sUnsupported, SSHCFG_GLOBAL },
         { "gssapicleanupcredentials", sUnsupported },          { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
 #endif  #endif
         { "passwordauthentication", sPasswordAuthentication },          { "passwordauthentication", sPasswordAuthentication, SSHCFG_GLOBAL },
         { "kbdinteractiveauthentication", sKbdInteractiveAuthentication },          { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_GLOBAL },
         { "challengeresponseauthentication", sChallengeResponseAuthentication },          { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
         { "skeyauthentication", sChallengeResponseAuthentication }, /* alias */          { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
         { "checkmail", sDeprecated },          { "checkmail", sDeprecated, SSHCFG_GLOBAL },
         { "listenaddress", sListenAddress },          { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
         { "addressfamily", sAddressFamily },          { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
         { "printmotd", sPrintMotd },          { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
         { "printlastlog", sPrintLastLog },          { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
         { "ignorerhosts", sIgnoreRhosts },          { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
         { "ignoreuserknownhosts", sIgnoreUserKnownHosts },          { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
         { "x11forwarding", sX11Forwarding },          { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
         { "x11displayoffset", sX11DisplayOffset },          { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
         { "x11uselocalhost", sX11UseLocalhost },          { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
         { "xauthlocation", sXAuthLocation },          { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
         { "strictmodes", sStrictModes },          { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
         { "permitemptypasswords", sEmptyPasswd },          { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL },
         { "permituserenvironment", sPermitUserEnvironment },          { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
         { "uselogin", sUseLogin },          { "uselogin", sUseLogin, SSHCFG_GLOBAL },
         { "compression", sCompression },          { "compression", sCompression, SSHCFG_GLOBAL },
         { "tcpkeepalive", sTCPKeepAlive },          { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
         { "keepalive", sTCPKeepAlive },                         /* obsolete alias */          { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },  /* obsolete alias */
         { "allowtcpforwarding", sAllowTcpForwarding },          { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
         { "allowusers", sAllowUsers },          { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
         { "denyusers", sDenyUsers },          { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
         { "allowgroups", sAllowGroups },          { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
         { "denygroups", sDenyGroups },          { "denygroups", sDenyGroups, SSHCFG_GLOBAL },
         { "ciphers", sCiphers },          { "ciphers", sCiphers, SSHCFG_GLOBAL },
         { "macs", sMacs },          { "macs", sMacs, SSHCFG_GLOBAL },
         { "protocol", sProtocol },          { "protocol", sProtocol, SSHCFG_GLOBAL },
         { "gatewayports", sGatewayPorts },          { "gatewayports", sGatewayPorts, SSHCFG_ALL },
         { "subsystem", sSubsystem },          { "subsystem", sSubsystem, SSHCFG_GLOBAL },
         { "maxstartups", sMaxStartups },          { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
         { "maxauthtries", sMaxAuthTries },          { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL },
         { "banner", sBanner },          { "banner", sBanner, SSHCFG_GLOBAL },
         { "usedns", sUseDNS },          { "usedns", sUseDNS, SSHCFG_GLOBAL },
         { "verifyreversemapping", sDeprecated },          { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
         { "reversemappingcheck", sDeprecated },          { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
         { "clientaliveinterval", sClientAliveInterval },          { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
         { "clientalivecountmax", sClientAliveCountMax },          { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
         { "authorizedkeysfile", sAuthorizedKeysFile },          { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
         { "authorizedkeysfile2", sAuthorizedKeysFile2 },          { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
         { "useprivilegeseparation", sUsePrivilegeSeparation},          { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL},
         { "acceptenv", sAcceptEnv },          { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
         { "permittunnel", sPermitTunnel },          { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
         { NULL, sBadOption }          { "match", sMatch, SSHCFG_ALL },
           { "permitopen", sPermitOpen, SSHCFG_ALL },
           { "forcecommand", sForceCommand, SSHCFG_ALL },
           { NULL, sBadOption, 0 }
 };  };
   
 /*  /*
Line 351 
Line 375 
   
 static ServerOpCodes  static ServerOpCodes
 parse_token(const char *cp, const char *filename,  parse_token(const char *cp, const char *filename,
             int linenum)              int linenum, u_int *flags)
 {  {
         u_int i;          u_int i;
   
         for (i = 0; keywords[i].name; i++)          for (i = 0; keywords[i].name; i++)
                 if (strcasecmp(cp, keywords[i].name) == 0)                  if (strcasecmp(cp, keywords[i].name) == 0) {
                           *flags = keywords[i].flags;
                         return keywords[i].opcode;                          return keywords[i].opcode;
                   }
   
         error("%s: line %d: Bad configuration option: %s",          error("%s: line %d: Bad configuration option: %s",
             filename, linenum, cp);              filename, linenum, cp);
Line 402 
Line 428 
         options->listen_addrs = aitop;          options->listen_addrs = aitop;
 }  }
   
   /*
    * The strategy for the Match blocks is that the config file is parsed twice.
    *
    * The first time is at startup.  activep is initialized to 1 and the
    * directives in the global context are processed and acted on.  Hitting a
    * Match directive unsets activep and the directives inside the block are
    * checked for syntax only.
    *
    * The second time is after a connection has been established but before
    * authentication.  activep is initialized to 2 and global config directives
    * are ignored since they have already been processed.  If the criteria in a
    * Match block is met, activep is set and the subsequent directives
    * processed and actioned until EOF or another Match block unsets it.  Any
    * options set are copied into the main server config.
    *
    * Potential additions/improvements:
    *  - Add Match support for pre-kex directives, eg Protocol, Ciphers.
    *
    *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
    *      Match Address 192.168.0.*
    *              Tag trusted
    *      Match Group wheel
    *              Tag trusted
    *      Match Tag trusted
    *              AllowTcpForwarding yes
    *              GatewayPorts clientspecified
    *              [...]
    *
    *  - Add a PermittedChannelRequests directive
    *      Match Group shell
    *              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)
   {
           int result = 1;
           char *arg, *attrib, *cp = *condition;
           size_t len;
   
           if (user == NULL)
                   debug3("checking syntax for 'Match %s'", cp);
           else
                   debug3("checking match for '%s' user %s host %s addr %s", cp,
                       user ? user : "(null)", host ? host : "(null)",
                       address ? address : "(null)");
   
           while ((attrib = strdelim(&cp)) && *attrib != '\0') {
                   if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
                           error("Missing Match criteria for %s", attrib);
                           return -1;
                   }
                   len = strlen(arg);
                   if (strcasecmp(attrib, "user") == 0) {
                           if (!user) {
                                   result = 0;
                                   continue;
                           }
                           if (match_pattern_list(user, arg, len, 0) != 1)
                                   result = 0;
                           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;
                                   continue;
                           }
                           if (match_hostname(host, arg, len) != 1)
                                   result = 0;
                           else
                                   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;
                           }
                           if (match_hostname(address, arg, len) != 1)
                                   result = 0;
                           else
                                   debug("connection from %.100s matched 'Address "
                                       "%.100s' at line %d", address, arg, line);
                   } else {
                           error("Unsupported Match attribute %s", attrib);
                           return -1;
                   }
           }
           if (user != NULL)
                   debug3("match %sfound", result ? "" : "not ");
           *condition = cp;
           return result;
   }
   
   #define WHITESPACE " \t\r\n"
   
 int  int
 process_server_config_line(ServerOptions *options, char *line,  process_server_config_line(ServerOptions *options, char *line,
     const char *filename, int linenum)      const char *filename, int linenum, int *activep, const char *user,
       const char *host, const char *address)
 {  {
         char *cp, **charptr, *arg, *p;          char *cp, **charptr, *arg, *p;
         int *intptr, value, n;          int cmdline = 0, *intptr, value, n;
         ServerOpCodes opcode;          ServerOpCodes opcode;
         u_short port;          u_short port;
         u_int i;          u_int i, flags = 0;
           size_t len;
   
         cp = line;          cp = line;
         arg = strdelim(&cp);          if ((arg = strdelim(&cp)) == NULL)
                   return 0;
         /* Ignore leading whitespace */          /* Ignore leading whitespace */
         if (*arg == '\0')          if (*arg == '\0')
                 arg = strdelim(&cp);                  arg = strdelim(&cp);
Line 421 
Line 600 
                 return 0;                  return 0;
         intptr = NULL;          intptr = NULL;
         charptr = NULL;          charptr = NULL;
         opcode = parse_token(arg, filename, linenum);          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) {          switch (opcode) {
         case sBadOption:          case sBadOption:
                 return -1;                  return -1;
Line 453 
Line 650 
                         fatal("%s line %d: missing integer value.",                          fatal("%s line %d: missing integer value.",
                             filename, linenum);                              filename, linenum);
                 value = atoi(arg);                  value = atoi(arg);
                 if (*intptr == -1)                  if (*activep && *intptr == -1)
                         *intptr = value;                          *intptr = value;
                 break;                  break;
   
Line 533 
Line 730 
                 if (!arg || *arg == '\0')                  if (!arg || *arg == '\0')
                         fatal("%s line %d: missing file name.",                          fatal("%s line %d: missing file name.",
                             filename, linenum);                              filename, linenum);
                 if (*charptr == NULL) {                  if (*activep && *charptr == NULL) {
                         *charptr = tilde_expand_filename(arg, getuid());                          *charptr = tilde_expand_filename(arg, getuid());
                         /* increase optional counter */                          /* increase optional counter */
                         if (intptr != NULL)                          if (intptr != NULL)
Line 584 
Line 781 
                 else                  else
                         fatal("%s line %d: Bad yes/no argument: %s",                          fatal("%s line %d: Bad yes/no argument: %s",
                                 filename, linenum, arg);                                  filename, linenum, arg);
                 if (*intptr == -1)                  if (*activep && *intptr == -1)
                         *intptr = value;                          *intptr = value;
                 break;                  break;
   
Line 779 
Line 976 
         case sDenyUsers:          case sDenyUsers:
                 while ((arg = strdelim(&cp)) && *arg != '\0') {                  while ((arg = strdelim(&cp)) && *arg != '\0') {
                         if (options->num_deny_users >= MAX_DENY_USERS)                          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);                                      filename, linenum);
                         options->deny_users[options->num_deny_users++] =                          options->deny_users[options->num_deny_users++] =
                             xstrdup(arg);                              xstrdup(arg);
Line 849 
Line 1046 
                 if (!arg || *arg == '\0')                  if (!arg || *arg == '\0')
                         fatal("%s line %d: Missing subsystem name.",                          fatal("%s line %d: Missing subsystem name.",
                             filename, linenum);                              filename, linenum);
                   if (!*activep) {
                           arg = strdelim(&cp);
                           break;
                   }
                 for (i = 0; i < options->num_subsystems; i++)                  for (i = 0; i < options->num_subsystems; i++)
                         if (strcmp(arg, options->subsystem_name[i]) == 0)                          if (strcmp(arg, options->subsystem_name[i]) == 0)
                                 fatal("%s line %d: Subsystem '%s' already defined.",                                  fatal("%s line %d: Subsystem '%s' already defined.",
Line 859 
Line 1060 
                         fatal("%s line %d: Missing subsystem command.",                          fatal("%s line %d: Missing subsystem command.",
                             filename, linenum);                              filename, linenum);
                 options->subsystem_command[options->num_subsystems] = xstrdup(arg);                  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++;                  options->num_subsystems++;
                 break;                  break;
   
Line 899 
Line 1111 
          */           */
         case sAuthorizedKeysFile:          case sAuthorizedKeysFile:
         case sAuthorizedKeysFile2:          case sAuthorizedKeysFile2:
                 charptr = (opcode == sAuthorizedKeysFile ) ?                  charptr = (opcode == sAuthorizedKeysFile) ?
                     &options->authorized_keys_file :                      &options->authorized_keys_file :
                     &options->authorized_keys_file2;                      &options->authorized_keys_file2;
                 goto parse_filename;                  goto parse_filename;
Line 920 
Line 1132 
                         if (options->num_accept_env >= MAX_ACCEPT_ENV)                          if (options->num_accept_env >= MAX_ACCEPT_ENV)
                                 fatal("%s line %d: too many allow env.",                                  fatal("%s line %d: too many allow env.",
                                     filename, linenum);                                      filename, linenum);
                           if (!*activep)
                                   break;
                         options->accept_env[options->num_accept_env++] =                          options->accept_env[options->num_accept_env++] =
                             xstrdup(arg);                              xstrdup(arg);
                 }                  }
Line 947 
Line 1161 
                         *intptr = value;                          *intptr = value;
                 break;                  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);
                   if (strcmp(arg, "any") == 0) {
                           if (*activep) {
                                   channel_clear_adm_permitted_opens();
                                   options->num_permitted_opens = 0;
                           }
                           break;
                   }
                   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 && options->num_permitted_opens == -1) {
                                   channel_clear_adm_permitted_opens();
                                   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:          case sDeprecated:
                 logit("%s line %d: Deprecated option %s",                  logit("%s line %d: Deprecated option %s",
                     filename, linenum, arg);                      filename, linenum, arg);
Line 1003 
Line 1266 
 }  }
   
 void  void
 parse_server_config(ServerOptions *options, const char *filename, Buffer *conf)  parse_server_match_config(ServerOptions *options, const char *user,
       const char *host, const char *address)
 {  {
         int linenum, bad_options = 0;          ServerOptions mo;
   
           initialize_server_options(&mo);
           parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
           copy_set_server_options(options, &mo);
   }
   
   /* Copy any (supported) values that are set */
   void
   copy_set_server_options(ServerOptions *dst, ServerOptions *src)
   {
           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;
           if (src->adm_forced_command != NULL) {
                   if (dst->adm_forced_command != NULL)
                           xfree(dst->adm_forced_command);
                   dst->adm_forced_command = src->adm_forced_command;
           }
           if (src->x11_display_offset != -1)
                   dst->x11_display_offset = src->x11_display_offset;
           if (src->x11_forwarding != -1)
                   dst->x11_forwarding = src->x11_forwarding;
           if (src->x11_use_localhost != -1)
                   dst->x11_use_localhost = src->x11_use_localhost;
   }
   
   void
   parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
       const char *user, const char *host, const char *address)
   {
           int active, linenum, bad_options = 0;
         char *cp, *obuf, *cbuf;          char *cp, *obuf, *cbuf;
   
         debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));          debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
   
         obuf = cbuf = xstrdup(buffer_ptr(conf));          obuf = cbuf = xstrdup(buffer_ptr(conf));
           active = user ? 0 : 1;
         linenum = 1;          linenum = 1;
         while ((cp = strsep(&cbuf, "\n")) != NULL) {          while ((cp = strsep(&cbuf, "\n")) != NULL) {
                 if (process_server_config_line(options, cp, filename,                  if (process_server_config_line(options, cp, filename,
                     linenum++) != 0)                      linenum++, &active, user, host, address) != 0)
                         bad_options++;                          bad_options++;
         }          }
         xfree(obuf);          xfree(obuf);

Legend:
Removed from v.1.146  
changed lines
  Added in v.1.146.2.1