[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.152 and 1.153

version 1.152, 2006/07/08 21:47:12 version 1.153, 2006/07/12 11:34:58
Line 25 
Line 25 
 #include "cipher.h"  #include "cipher.h"
 #include "kex.h"  #include "kex.h"
 #include "mac.h"  #include "mac.h"
   #include "match.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 100 
Line 102 
         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;
   
         /* Needs to be accessable in many places */  
         use_privsep = -1;  
 }  }
   
 void  void
Line 254 
Line 253 
         sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,          sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
         sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,          sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
         sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,          sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
           sMatch,
         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_GLOBAL },
         { "x11displayoffset", sX11DisplayOffset },          { "x11displayoffset", sX11DisplayOffset, SSHCFG_GLOBAL },
         { "x11uselocalhost", sX11UseLocalhost },          { "x11uselocalhost", sX11UseLocalhost, SSHCFG_GLOBAL },
         { "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 },
           { NULL, sBadOption, 0 }
 };  };
   
 /*  /*
Line 354 
Line 360 
   
 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 405 
Line 413 
         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(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, "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;
   }
   
 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;          size_t len;
   
         cp = line;          cp = line;
Line 426 
Line 531 
                 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 458 
Line 581 
                         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 538 
Line 661 
                 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 589 
Line 712 
                 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 854 
Line 977 
                 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 936 
Line 1063 
                         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 963 
Line 1092 
                         *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 sDeprecated:          case sDeprecated:
                 logit("%s line %d: Deprecated option %s",                  logit("%s line %d: Deprecated option %s",
                     filename, linenum, arg);                      filename, linenum, arg);
Line 1019 
Line 1159 
 }  }
   
 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;
   }
   
   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.152  
changed lines
  Added in v.1.153