openssh-unix-dev May 2011 archive
Main Archive Page > Month Archives  > openssh-unix-dev archives
openssh-unix-dev: Re: backdoor by authorized_keys2 leftovers

Re: backdoor by authorized_keys2 leftovers

From: Damien Miller <djm_at_nospam>
Date: Fri May 20 2011 - 08:47:53 GMT
To: Darren Tucker <dtucker@zip.com.au>

Here's the latest version of the diff. It fixes a couple more bugs,
particularly around config passing between privsep monitor and child.

Index: auth-rsa.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth-rsa.c,v
retrieving revision 1.79
diff -u -p -r1.79 auth-rsa.c
--- auth-rsa.c 3 Dec 2010 23:55:27 -0000 1.79
+++ auth-rsa.c 20 May 2011 08:44:32 -0000
@@ -157,44 +157,27 @@ auth_rsa_challenge_dialog(Key *key)
         return (success);
 }
 
-/*
- * check if there's user key matching client_n,
- * return key if login is allowed, NULL otherwise
- */
-
-int
-auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
+static int
+rsa_key_allowed_in_file(struct passwd *pw, char *file,
+ const BIGNUM *client_n, Key **rkey)
 {
- char line[SSH_MAX_PUBKEY_BYTES], *file;
+ char line[SSH_MAX_PUBKEY_BYTES];
         int allowed = 0;
         u_int bits;
         FILE *f;
         u_long linenum = 0;
         Key *key;
 
- /* Temporarily use the user's uid. */
- temporarily_use_uid(pw);
-
- /* The authorized keys. */
- file = authorized_keys_file(pw);
         debug("trying public RSA key file %s", file);
- f = auth_openkeyfile(file, pw, options.strict_modes);
- if (!f) {
- xfree(file);
- restore_uid();
- return (0);
- }
-
- /* Flag indicating whether the key is allowed. */
- allowed = 0;
-
- key = key_new(KEY_RSA1);
+ if ((f = auth_openkeyfile(file, pw, options.strict_modes)) == NULL)
+ return 0;
 
         /*
          * Go though the accepted keys, looking for the current key. If
          * found, perform a challenge-response dialog to verify that the
          * user really has the corresponding private key.
          */
+ key = key_new(KEY_RSA1);
         while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
                 char *cp;
                 char *key_options;
@@ -232,7 +215,10 @@ auth_rsa_key_allowed(struct passwd *pw,
                 }
                 /* cp now points to the comment part. */
 
- /* Check if the we have found the desired key (identified by its modulus). */
+ /*
+ * Check if the we have found the desired key (identified
+ * by its modulus).
+ */
                 if (BN_cmp(key->rsa->n, client_n) != 0)
                         continue;
 
@@ -261,11 +247,7 @@ auth_rsa_key_allowed(struct passwd *pw,
                 break;
         }
 
- /* Restore the privileged uid. */
- restore_uid();
-
         /* Close the file. */
- xfree(file);
         fclose(f);
 
         /* return key if allowed */
@@ -273,7 +255,33 @@ auth_rsa_key_allowed(struct passwd *pw,
                 *rkey = key;
         else
                 key_free(key);
- return (allowed);
+
+ return allowed;
+}
+
+/*
+ * check if there's user key matching client_n,
+ * return key if login is allowed, NULL otherwise
+ */
+
+int
+auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
+{
+ char *file;
+ u_int i, allowed = 0;
+
+ temporarily_use_uid(pw);
+
+ for (i = 0; !allowed && i < options.num_authkeys_files; i++) {
+ file = expand_authorized_keys(
+ options.authorized_keys_files[i], pw);
+ allowed = rsa_key_allowed_in_file(pw, file, client_n, rkey);
+ xfree(file);
+ }
+
+ restore_uid();
+
+ return allowed;
 }
 
 /*
Index: auth.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth.c,v
retrieving revision 1.92
diff -u -p -r1.92 auth.c
--- auth.c 11 May 2011 04:47:06 -0000 1.92
+++ auth.c 20 May 2011 08:44:32 -0000
@@ -241,7 +241,7 @@ auth_root_allowed(char *method)
  *
  * This returns a buffer allocated by xmalloc.
  */
-static char *
+char *
 expand_authorized_keys(const char *filename, struct passwd *pw)
 {
         char *file, ret[MAXPATHLEN];
@@ -265,12 +265,6 @@ expand_authorized_keys(const char *filen
 }
 
 char *
-authorized_keys_file(struct passwd *pw)
-{
- return expand_authorized_keys(options.authorized_keys_file, pw);
-}
-
-char *
 authorized_principals_file(struct passwd *pw)
 {
         if (options.authorized_principals_file == NULL)
Index: auth.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth.h,v
retrieving revision 1.68
diff -u -p -r1.68 auth.h
--- auth.h 11 May 2011 04:47:06 -0000 1.68
+++ auth.h 20 May 2011 08:44:32 -0000
@@ -145,7 +145,7 @@ struct passwd * getpwnamallow(const char
 char *get_challenge(Authctxt *);
 int verify_response(Authctxt *, const char *);
 
-char *authorized_keys_file(struct passwd *);
+char *expand_authorized_keys(const char *, struct passwd *pw);
 char *authorized_principals_file(struct passwd *);
 
 FILE *auth_openkeyfile(const char *, struct passwd *, int);
Index: auth2-pubkey.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth2-pubkey.c,v
retrieving revision 1.28
diff -u -p -r1.28 auth2-pubkey.c
--- auth2-pubkey.c 11 May 2011 04:47:06 -0000 1.28
+++ auth2-pubkey.c 20 May 2011 08:44:32 -0000
@@ -435,7 +435,7 @@ user_cert_trusted_ca(struct passwd *pw,
 int
 user_key_allowed(struct passwd *pw, Key *key)
 {
- int success;
+ u_int success, i;
         char *file;
 
         if (auth_key_is_revoked(key))
@@ -447,9 +447,12 @@ user_key_allowed(struct passwd *pw, Key
         if (success)
                 return success;
 
- file = authorized_keys_file(pw);
- success = user_key_allowed2(pw, key, file);
- xfree(file);
+ for (i = 0; !success && i < options.num_authkeys_files; i++) {
+ file = expand_authorized_keys(
+ options.authorized_keys_files[i], pw);
+ success = user_key_allowed2(pw, key, file);
+ xfree(file);
+ }
 
         return success;
 }
Index: monitor.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/monitor.c,v
retrieving revision 1.112
diff -u -p -r1.112 monitor.c
--- monitor.c 20 May 2011 03:25:45 -0000 1.112
+++ monitor.c 20 May 2011 08:44:33 -0000
@@ -547,6 +547,7 @@ mm_answer_pwnamallow(int sock, Buffer *m
         char *username;
         struct passwd *pwent;
         int allowed = 0;
+ u_int i;
 
         debug3("%s", __func__);
 
@@ -589,6 +590,10 @@ mm_answer_pwnamallow(int sock, Buffer *m
                 if (options.x != NULL) \
                         buffer_put_cstring(m, options.x); \
         } while (0)
+#define M_CP_STRARRAYOPT(x, nx) do { \
+ for (i = 0; i < options.nx; i++) \
+ buffer_put_cstring(m, options.x[i]); \
+ } while (0)
         /* See comment in servconf.h */
         COPY_MATCH_STRING_OPTS();
 #undef M_CP_STROPT
@@ -604,7 +609,6 @@ mm_answer_pwnamallow(int sock, Buffer *m
                 monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
                 monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
         }
-
 
         return (0);
 }
Index: monitor_wrap.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/monitor_wrap.c,v
retrieving revision 1.71
diff -u -p -r1.71 monitor_wrap.c
--- monitor_wrap.c 20 May 2011 03:25:45 -0000 1.71
+++ monitor_wrap.c 20 May 2011 08:44:33 -0000
@@ -202,7 +202,7 @@ mm_getpwnamallow(const char *username)
 {
         Buffer m;
         struct passwd *pw;
- u_int len;
+ u_int len, i;
         ServerOptions *newopts;
 
         debug3("%s entering", __func__);
@@ -238,6 +238,10 @@ out:
 #define M_CP_STROPT(x) do { \
                 if (newopts->x != NULL) \
                         newopts->x = buffer_get_string(&m, NULL); \
+ } while (0)
+#define M_CP_STRARRAYOPT(x, nx) do { \
+ for (i = 0; i < newopts->nx; i++) \
+ newopts->x[i] = buffer_get_string(&m, NULL); \
         } while (0)
         /* See comment in servconf.h */
         COPY_MATCH_STRING_OPTS();
Index: pathnames.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/pathnames.h,v
retrieving revision 1.21
diff -u -p -r1.21 pathnames.h
--- pathnames.h 11 May 2011 04:47:06 -0000 1.21
+++ pathnames.h 20 May 2011 08:44:33 -0000
@@ -88,6 +88,9 @@
  */
 #define _PATH_SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
 
+/* backward compat for protocol v2 */
+#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
+
 /*
  * Per-user and system-wide ssh "rc" files. These files are executed with
  * /bin/sh before starting the shell or command if they exist. They will be
Index: servconf.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/servconf.c,v
retrieving revision 1.218
diff -u -p -r1.218 servconf.c
--- servconf.c 20 May 2011 03:25:45 -0000 1.218
+++ servconf.c 20 May 2011 08:44:33 -0000
@@ -119,7 +119,7 @@ initialize_server_options(ServerOptions
         options->use_dns = -1;
         options->client_alive_interval = -1;
         options->client_alive_count_max = -1;
- options->authorized_keys_file = NULL;
+ options->num_authkeys_files = 0;
         options->num_accept_env = 0;
         options->permit_tun = -1;
         options->num_permitted_opens = -1;
@@ -249,8 +249,12 @@ fill_default_server_options(ServerOption
                 options->client_alive_interval = 0;
         if (options->client_alive_count_max == -1)
                 options->client_alive_count_max = 3;
- if (options->authorized_keys_file == NULL)
- options->authorized_keys_file = xstrdup(_PATH_SSH_USER_PERMITTED_KEYS);
+ if (options->num_authkeys_files == 0) {
+ options->authorized_keys_files[options->num_authkeys_files++] =
+ xstrdup(_PATH_SSH_USER_PERMITTED_KEYS);
+ options->authorized_keys_files[options->num_authkeys_files++] =
+ xstrdup(_PATH_SSH_USER_PERMITTED_KEYS2);
+ }
         if (options->permit_tun == -1)
                 options->permit_tun = SSH_TUNMODE_NO;
         if (options->zero_knowledge_password_authentication == -1)
@@ -286,7 +290,7 @@ typedef enum {
         sMaxStartups, sMaxAuthTries, sMaxSessions,
         sBanner, sUseDNS, sHostbasedAuthentication,
         sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
- sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+ sClientAliveCountMax, sAuthorizedKeysFile,
         sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
         sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
         sUsePrivilegeSeparation, sAllowAgentForwarding,
@@ -391,7 +395,7 @@ static struct {
         { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
         { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
         { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
- { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_ALL },
+ { "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
         { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL},
         { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
         { "permittunnel", sPermitTunnel, SSHCFG_ALL },
@@ -1197,11 +1201,22 @@ process_server_config_line(ServerOptions
          * AuthorizedKeysFile /etc/ssh_keys/%u
          */
         case sAuthorizedKeysFile:
- charptr = &options->authorized_keys_file;
- goto parse_tilde_filename;
+ if (*activep && options->num_authkeys_files == 0) {
+ while ((arg = strdelim(&cp)) && *arg != '\0') {
+ if (options->num_authkeys_files >=
+ MAX_AUTHKEYS_FILES)
+ fatal("%s line %d: "
+ "too many authorized keys files.",
+ filename, linenum);
+ options->authorized_keys_files[
+ options->num_authkeys_files++] =
+ tilde_expand_filename(arg, getuid());
+ }
+ }
+ return 0;
+
         case sAuthorizedPrincipalsFile:
                 charptr = &options->authorized_principals_file;
- parse_tilde_filename:
                 arg = strdelim(&cp);
                 if (!arg || *arg == '\0')
                         fatal("%s line %d: missing file name.",
@@ -1420,6 +1435,12 @@ parse_server_match_config(ServerOptions
                 dst->n = src->n; \
         } \
 } while(0)
+#define M_CP_STRARRAYOPT(n, num_n) do {\
+ if (src->num_n != 0) { \
+ for (dst->num_n = 0; dst->num_n < src->num_n; dst->num_n++) \
+ dst->n[dst->num_n] = xstrdup(src->n[dst->num_n]); \
+ } \
+} while(0)
 
 /*
  * Copy any supported values that are set.
@@ -1464,12 +1485,14 @@ copy_set_server_options(ServerOptions *d
          */
         if (preauth)
                 return;
+
         M_CP_STROPT(adm_forced_command);
         M_CP_STROPT(chroot_directory);
 }
 
 #undef M_CP_INTOPT
 #undef M_CP_STROPT
+#undef M_CP_STRARRAYOPT
 
 void
 parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
@@ -1583,7 +1606,18 @@ dump_cfg_strarray(ServerOpCodes code, u_
         u_int i;
 
         for (i = 0; i < count; i++)
- printf("%s %s\n", lookup_opcode_name(code), vals[i]);
+ printf("%s %s\n", lookup_opcode_name(code), vals[i]);
+}
+
+static void
+dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
+{
+ u_int i;
+
+ printf("%s", lookup_opcode_name(code));
+ for (i = 0; i < count; i++)
+ printf(" %s", vals[i]);
+ printf("\n");
 }
 
 void
@@ -1676,7 +1710,6 @@ dump_config(ServerOptions *o)
         dump_cfg_string(sCiphers, o->ciphers);
         dump_cfg_string(sMacs, o->macs);
         dump_cfg_string(sBanner, o->banner);
- dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file);
         dump_cfg_string(sForceCommand, o->adm_forced_command);
         dump_cfg_string(sChrootDirectory, o->chroot_directory);
         dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
@@ -1689,6 +1722,8 @@ dump_config(ServerOptions *o)
         dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
 
         /* string array arguments */
+ dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
+ o->authorized_keys_files);
         dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
              o->host_key_files);
         dump_cfg_strarray(sHostKeyFile, o->num_host_cert_files,
Index: servconf.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/servconf.h,v
retrieving revision 1.97
diff -u -p -r1.97 servconf.h
--- servconf.h 20 May 2011 03:25:45 -0000 1.97
+++ servconf.h 20 May 2011 08:44:33 -0000
@@ -27,6 +27,7 @@
 #define MAX_HOSTCERTS 256 /* Max # host certificates. */
 #define MAX_ACCEPT_ENV 256 /* Max # of env vars. */
 #define MAX_MATCH_GROUPS 256 /* Max # of groups for Match. */
+#define MAX_AUTHKEYS_FILES 256 /* Max # of authorized_keys files. */
 
 /* permit_root_login */
 #define PERMIT_NOT_SET -1
@@ -145,7 +146,8 @@ typedef struct {
                                          * disconnect the session
                                          */
 
- char *authorized_keys_file; /* File containing public keys */
+ u_int num_authkeys_files; /* Files containing public keys */
+ char *authorized_keys_files[MAX_AUTHKEYS_FILES];
 
         char *adm_forced_command;
 
@@ -169,8 +171,8 @@ typedef struct {
                 M_CP_STROPT(banner); \
                 M_CP_STROPT(trusted_user_ca_keys); \
                 M_CP_STROPT(revoked_keys_file); \
- M_CP_STROPT(authorized_keys_file); \
                 M_CP_STROPT(authorized_principals_file); \
+ M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \
         } while (0)
 
 void initialize_server_options(ServerOptions *);
 /* Do fork() after authentication. Used by "ssh -f" */
Index: sshd.8
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sshd.8,v
retrieving revision 1.260
diff -u -p -r1.260 sshd.8
--- sshd.8 28 Oct 2010 18:33:28 -0000 1.260
+++ sshd.8 20 May 2011 08:44:33 -0000
@@ -435,10 +435,12 @@ is run, and if that
 does not exist either, xauth is used to add the cookie.
 .Sh AUTHORIZED_KEYS FILE FORMAT
 .Cm AuthorizedKeysFile
-specifies the file containing public keys for
+specifies the file or files containing public keys for
 public key authentication;
-if none is specified, the default is
-.Pa ~/.ssh/authorized_keys .
+if none is specified, the default is both
+.Pa ~/.ssh/authorized_keys
+and
+.Pa ~/.ssh/authorized_keys2 .
 Each line of the file contains one
 key (empty lines and lines starting with a
 .Ql #
Index: sshd_config
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sshd_config,v
retrieving revision 1.83
diff -u -p -r1.83 sshd_config
--- sshd_config 6 May 2011 01:03:35 -0000 1.83
+++ sshd_config 20 May 2011 08:44:33 -0000
@@ -42,7 +42,7 @@
 
 #RSAAuthentication yes
 #PubkeyAuthentication yes
-#AuthorizedKeysFile .ssh/authorized_keys
+AuthorizedKeysFile .ssh/authorized_keys
 
 # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
 #RhostsRSAAuthentication no
Index: sshd_config.5
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sshd_config.5,v
retrieving revision 1.131
diff -u -p -r1.131 sshd_config.5
--- sshd_config.5 8 Dec 2010 04:02:47 -0000 1.131
+++ sshd_config.5 20 May 2011 08:44:33 -0000
@@ -168,8 +168,11 @@ After expansion,
 .Cm AuthorizedKeysFile
 is taken to be an absolute path or one relative to the user's home
 directory.
-The default is
-.Dq .ssh/authorized_keys .
+The default is both
+.Dq .ssh/authorized_keys
+and
+.Dq .ssh/authorized_keys2 .
+Multiple files may be listed separated by whitespace.
 .It Cm AuthorizedPrincipalsFile
 Specifies a file that lists principal names that are accepted for
 certificate authentication.
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev