]> andersk Git - openssh.git/commitdiff
- markus@cvs.openbsd.org 2001/05/20 17:20:36
authormouring <mouring>
Tue, 5 Jun 2001 20:25:05 +0000 (20:25 +0000)
committermouring <mouring>
Tue, 5 Jun 2001 20:25:05 +0000 (20:25 +0000)
     [auth-rsa.c auth.c auth.h auth2.c servconf.c servconf.h sshd.8
      sshd_config]
     configurable authorized_keys{,2} location; originally from peter@;
     ok djm@

ChangeLog
auth-rsa.c
auth.c
auth.h
auth2.c
servconf.c
servconf.h
sshd.8
sshd_config

index b7cb2c9063cb2eb05566fa659b3464cc36f52fcd..8c03dae8c8246b4b3a70e120fa691e2d65b251f7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
    - stevesk@cvs.openbsd.org 2001/05/19 19:57:09
      [channels.c]                               
      typo in error message                      
+   - markus@cvs.openbsd.org 2001/05/20 17:20:36                                 
+     [auth-rsa.c auth.c auth.h auth2.c servconf.c servconf.h sshd.8
+      sshd_config]
+     configurable authorized_keys{,2} location; originally from peter@; 
+     ok djm@ 
 
 20010528
  - (tim) [conifgure.in] add setvbuf test needed for sftp-int.c
index 59bee18bd3f9fa76865bd029a2992f29ace74325..491ed81d60d4e88a5f5754d7b0631f32d786e329 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth-rsa.c,v 1.40 2001/04/06 21:00:07 markus Exp $");
+RCSID("$OpenBSD: auth-rsa.c,v 1.41 2001/05/20 17:20:35 markus Exp $");
 
 #include <openssl/rsa.h>
 #include <openssl/md5.h>
@@ -122,7 +122,7 @@ auth_rsa_challenge_dialog(RSA *pk)
 int
 auth_rsa(struct passwd *pw, BIGNUM *client_n)
 {
-       char line[8192], file[MAXPATHLEN];
+       char line[8192], *file;
        int authenticated;
        u_int bits;
        FILE *f;
@@ -138,13 +138,14 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
        temporarily_use_uid(pw);
 
        /* The authorized keys. */
-       snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
-                _PATH_SSH_USER_PERMITTED_KEYS);
+       file = authorized_keys_file(pw);
+       debug("trying public RSA key file %s", file);
 
        /* Fail quietly if file does not exist */
        if (stat(file, &st) < 0) {
                /* Restore the privileged uid. */
                restore_uid();
+               xfree(file);
                return 0;
        }
        /* Open the file containing the authorized keys. */
@@ -154,43 +155,17 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
                restore_uid();
                packet_send_debug("Could not open %.900s for reading.", file);
                packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
+               xfree(file);
                return 0;
        }
-       if (options.strict_modes) {
-               int fail = 0;
-               char buf[1024];
-               /* Check open file in order to avoid open/stat races */
-               if (fstat(fileno(f), &st) < 0 ||
-                   (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
-                   (st.st_mode & 022) != 0) {
-                       snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
-                                "bad ownership or modes for '%s'.", pw->pw_name, file);
-                       fail = 1;
-               } else {
-                       /* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
-                       int i;
-                       static const char *check[] = {
-                               "", _PATH_SSH_USER_DIR, NULL
-                       };
-                       for (i = 0; check[i]; i++) {
-                               snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
-                               if (stat(line, &st) < 0 ||
-                                   (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
-                                   (st.st_mode & 022) != 0) {
-                                       snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: "
-                                                "bad ownership or modes for '%s'.", pw->pw_name, line);
-                                       fail = 1;
-                                       break;
-                               }
-                       }
-               }
-               if (fail) {
-                       fclose(f);
-                       log("%s", buf);
-                       packet_send_debug("%s", buf);
-                       restore_uid();
-                       return 0;
-               }
+       if (options.strict_modes &&
+           secure_filename(f, file, pw->pw_uid, line, sizeof(line)) != 0) {
+               xfree(file);
+               fclose(f);
+               log("Authentication refused: %s", line);
+               packet_send_debug("Authentication refused: %s", line);
+               restore_uid();
+               return 0;
        }
        /* Flag indicating whether authentication has succeeded. */
        authenticated = 0;
@@ -285,6 +260,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
        restore_uid();
 
        /* Close the file. */
+       xfree(file);
        fclose(f);
 
        RSA_free(pk);
diff --git a/auth.c b/auth.c
index 1f976eee2083dd7ff4730b0dd82a1ff6db4a5567..07e5b8f05329aaaefc5aa350e17066f784cf746e 100644 (file)
--- a/auth.c
+++ b/auth.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $");
+RCSID("$OpenBSD: auth.c,v 1.22 2001/05/20 17:20:35 markus Exp $");
 
 #ifdef HAVE_LOGIN_H
 #include <login.h>
@@ -32,6 +32,8 @@ RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $");
 #include <shadow.h>
 #endif /* defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) */
 
+#include <libgen.h>
+
 #include "xmalloc.h"
 #include "match.h"
 #include "groupaccess.h"
@@ -40,6 +42,8 @@ RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $");
 #include "auth.h"
 #include "auth-options.h"
 #include "canohost.h"
+#include "buffer.h"
+#include "bufaux.h"
 
 /* import */
 extern ServerOptions options;
@@ -222,3 +226,132 @@ auth_root_allowed(char *method)
        log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
        return 0;
 }
+
+
+/*
+ * Given a template and a passwd structure, build a filename
+ * by substituting % tokenised options. Currently, %% becomes '%',
+ * %h becomes the home directory and %u the username.
+ *
+ * This returns a buffer allocated by xmalloc.
+ */
+char *
+expand_filename(const char *filename, struct passwd *pw)
+{
+       Buffer buffer;
+       char *file;
+       const char *cp;
+
+       /*
+        * Build the filename string in the buffer by making the appropriate
+        * substitutions to the given file name.
+        */
+       buffer_init(&buffer);
+       for (cp = filename; *cp; cp++) {
+               if (cp[0] == '%' && cp[1] == '%') {
+                       buffer_append(&buffer, "%", 1);
+                       cp++;
+                       continue;
+               }
+               if (cp[0] == '%' && cp[1] == 'h') {
+                       buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir));
+                       cp++;
+                       continue;
+               }
+               if (cp[0] == '%' && cp[1] == 'u') {
+                       buffer_append(&buffer, pw->pw_name,
+                            strlen(pw->pw_name));
+                       cp++;
+                       continue;
+               }
+               buffer_append(&buffer, cp, 1);
+       }
+       buffer_append(&buffer, "\0", 1);
+
+       /*
+        * Ensure that filename starts anchored. If not, be backward
+        * compatible and prepend the '%h/'
+        */
+       file = xmalloc(MAXPATHLEN);
+       cp = buffer_ptr(&buffer);
+       if (*cp != '/')
+               snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp);
+       else
+               strlcpy(file, cp, MAXPATHLEN);
+
+       buffer_free(&buffer);
+       return file;
+}
+
+char *
+authorized_keys_file(struct passwd *pw)
+{
+       return expand_filename(options.authorized_keys_file, pw);
+}
+
+char *
+authorized_keys_file2(struct passwd *pw)
+{
+       return expand_filename(options.authorized_keys_file2, pw);
+}
+
+/*
+ * Check a given file for security. This is defined as all components
+ * of the path to the file must either be owned by either the owner of
+ * of the file or root and no directories must be world writable.
+ *
+ * XXX Should any specific check be done for sym links ?
+ *
+ * Takes an open file descriptor, the file name, a uid and and
+ * error buffer plus max size as arguments.
+ *
+ * Returns 0 on success and -1 on failure
+ */
+int
+secure_filename(FILE *f, const char *file, uid_t uid, char *err, size_t errlen)
+{
+       char buf[MAXPATHLEN];
+       char *cp;
+       struct stat st;
+
+       if (realpath(file, buf) == NULL) {
+               snprintf(err, errlen, "realpath %s failed: %s", file,
+                   strerror(errno));
+               return -1;
+       }
+
+       /* check the open file to avoid races */
+       if (fstat(fileno(f), &st) < 0 ||
+           (st.st_uid != 0 && st.st_uid != uid) ||
+           (st.st_mode & 022) != 0) {
+               snprintf(err, errlen, "bad ownership or modes for file %s",
+                   buf);
+               return -1;
+       }
+
+       /* for each component of the canonical path, walking upwards */
+       for (;;) {
+               if ((cp = dirname(buf)) == NULL) {
+                       snprintf(err, errlen, "dirname() failed");
+                       return -1;
+               }
+               strlcpy(buf, cp, sizeof(buf));
+
+               debug3("secure_filename: checking '%s'", buf);
+               if (stat(buf, &st) < 0 ||
+                   (st.st_uid != 0 && st.st_uid != uid) ||
+                   (st.st_mode & 022) != 0) {
+                       snprintf(err, errlen, 
+                           "bad ownership or modes for directory %s", buf);
+                       return -1;
+               }
+
+               /*
+                * dirname should always complete with a "/" path,
+                * but we can be paranoid and check for "." too
+                */
+               if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
+                       break;
+       }
+       return 0;
+}
diff --git a/auth.h b/auth.h
index 20c3ebb78e2a9776f4dd05112a1b6cebd01ffbe0..2d1f1e9b90f38677ac066b9f291fd5bd228dc643 100644 (file)
--- a/auth.h
+++ b/auth.h
@@ -21,7 +21,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $OpenBSD: auth.h,v 1.16 2001/05/18 14:13:28 markus Exp $
+ * $OpenBSD: auth.h,v 1.17 2001/05/20 17:20:35 markus Exp $
  */
 #ifndef AUTH_H
 #define AUTH_H
@@ -159,6 +159,16 @@ int        verify_response(Authctxt *authctxt, const char *response);
 
 struct passwd * auth_get_user(void);
 
+
+/* expand a filename - return buffer is allocated by xmalloc */
+char   *expand_filename(const char *template, struct passwd *pw);
+char   *authorized_keys_file(struct passwd *pw);
+char   *authorized_keys_file2(struct passwd *pw);
+
+/* check a file and the path to it */
+int
+secure_filename(FILE *f, const char *file, uid_t u, char *err, size_t errlen);
+
 #define AUTH_FAIL_MAX 6
 #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
 #define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
diff --git a/auth2.c b/auth2.c
index e800c0587490538ad45e106c26f8c81d1a046a5a..9988f7aef1a43d058e1096136ff6c7f7d84117a9 100644 (file)
--- a/auth2.c
+++ b/auth2.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.57 2001/05/18 14:13:28 markus Exp $");
+RCSID("$OpenBSD: auth2.c,v 1.58 2001/05/20 17:20:35 markus Exp $");
 
 #include <openssl/evp.h>
 
@@ -666,7 +666,7 @@ authmethod_lookup(const char *name)
 int
 user_key_allowed(struct passwd *pw, Key *key)
 {
-       char line[8192], file[MAXPATHLEN];
+       char line[8192], *file;
        int found_key = 0;
        FILE *f;
        u_long linenum = 0;
@@ -680,13 +680,14 @@ user_key_allowed(struct passwd *pw, Key *key)
        temporarily_use_uid(pw);
 
        /* The authorized keys. */
-       snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
-           _PATH_SSH_USER_PERMITTED_KEYS2);
+       file = authorized_keys_file2(pw);
+       debug("trying public key file %s", file);
 
        /* Fail quietly if file does not exist */
        if (stat(file, &st) < 0) {
                /* Restore the privileged uid. */
                restore_uid();
+               xfree(file);
                return 0;
        }
        /* Open the file containing the authorized keys. */
@@ -694,48 +695,18 @@ user_key_allowed(struct passwd *pw, Key *key)
        if (!f) {
                /* Restore the privileged uid. */
                restore_uid();
+               xfree(file);
                return 0;
        }
-       if (options.strict_modes) {
-               int fail = 0;
-               char buf[1024];
-               /* Check open file in order to avoid open/stat races */
-               if (fstat(fileno(f), &st) < 0 ||
-                   (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
-                   (st.st_mode & 022) != 0) {
-                       snprintf(buf, sizeof buf,
-                           "%s authentication refused for %.100s: "
-                           "bad ownership or modes for '%s'.",
-                           key_type(key), pw->pw_name, file);
-                       fail = 1;
-               } else {
-                       /* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
-                       int i;
-                       static const char *check[] = {
-                               "", _PATH_SSH_USER_DIR, NULL
-                       };
-                       for (i = 0; check[i]; i++) {
-                               snprintf(line, sizeof line, "%.500s/%.100s",
-                                   pw->pw_dir, check[i]);
-                               if (stat(line, &st) < 0 ||
-                                   (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
-                                   (st.st_mode & 022) != 0) {
-                                       snprintf(buf, sizeof buf,
-                                           "%s authentication refused for %.100s: "
-                                           "bad ownership or modes for '%s'.",
-                                           key_type(key), pw->pw_name, line);
-                                       fail = 1;
-                                       break;
-                               }
-                       }
-               }
-               if (fail) {
-                       fclose(f);
-                       log("%s", buf);
-                       restore_uid();
-                       return 0;
-               }
+       if (options.strict_modes &&
+           secure_filename(f, file, pw->pw_uid, line, sizeof(line)) != 0) {
+               xfree(file);
+               fclose(f);
+               log("Authentication refused: %s", line);
+               restore_uid();
+               return 0;
        }
+
        found_key = 0;
        found = key_new(key->type);
 
@@ -778,6 +749,7 @@ user_key_allowed(struct passwd *pw, Key *key)
        }
        restore_uid();
        fclose(f);
+       xfree(file);
        key_free(found);
        if (!found_key)
                debug2("key not found");
index 2d10963c4e180818f2b37ccac415c6ece067bac6..e357d77a4b9b3ba92ea6d63ce98bd7564688ccf9 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.81 2001/05/19 19:43:57 stevesk Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.82 2001/05/20 17:20:35 markus Exp $");
 
 #ifdef KRB4
 #include <krb.h>
@@ -101,6 +101,8 @@ initialize_server_options(ServerOptions *options)
        options->reverse_mapping_check = -1;
        options->client_alive_interval = -1;
        options->client_alive_count_max = -1;
+       options->authorized_keys_file = NULL;
+       options->authorized_keys_file2 = NULL;
        options->pam_authentication_via_kbd_int = -1;
 }
 
@@ -208,6 +210,10 @@ fill_default_server_options(ServerOptions *options)
                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 = _PATH_SSH_USER_PERMITTED_KEYS;  
+       if (options->authorized_keys_file2 == NULL)
+               options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
        if (options->pam_authentication_via_kbd_int == -1)
                options->pam_authentication_via_kbd_int = 0;
 }
@@ -235,7 +241,8 @@ typedef enum {
        sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
        sBanner, sReverseMappingCheck, sHostbasedAuthentication,
        sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 
-       sClientAliveCountMax, sPAMAuthenticationViaKbdInt
+       sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+       sPAMAuthenticationViaKbdInt
 } ServerOpCodes;
 
 /* Textual representation of the tokens. */
@@ -301,6 +308,8 @@ static struct {
        { "reversemappingcheck", sReverseMappingCheck },
        { "clientaliveinterval", sClientAliveInterval },
        { "clientalivecountmax", sClientAliveCountMax },
+       { "authorizedkeysfile", sAuthorizedKeysFile },
+       { "authorizedkeysfile2", sAuthorizedKeysFile2 },
        { "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt },
        { NULL, 0 }
 };
@@ -802,6 +811,18 @@ parse_flag:
                case sBanner:
                        charptr = &options->banner;
                        goto parse_filename;
+               /*
+                * These options can contain %X options expanded at
+                * connect time, so that you can specify paths like:
+                *
+                * AuthorizedKeysFile   /etc/ssh_keys/%u
+                */
+               case sAuthorizedKeysFile:
+               case sAuthorizedKeysFile2:
+                       charptr = (opcode == sAuthorizedKeysFile ) ?
+                           &options->authorized_keys_file :
+                           &options->authorized_keys_file2;
+                       goto parse_filename;
 
                case sClientAliveInterval:
                        intptr = &options->client_alive_interval;
index a319a5c69ae37121d311e25973d6eec977d1f252..2bf19fb3b790c495289a2b346226254f4533bf1e 100644 (file)
@@ -11,7 +11,7 @@
  * called by a name other than "ssh" or "Secure Shell".
  */
 
-/* RCSID("$OpenBSD: servconf.h,v 1.42 2001/05/18 14:13:29 markus Exp $"); */
+/* RCSID("$OpenBSD: servconf.h,v 1.43 2001/05/20 17:20:35 markus Exp $"); */
 
 #ifndef SERVCONF_H
 #define SERVCONF_H
@@ -124,6 +124,8 @@ typedef struct {
                                         * for this many intervals, above
                                         * diconnect the session 
                                         */
+       char   *authorized_keys_file;   /* File containing public RSA keys */ 
+       char   *authorized_keys_file2;  /* File containing public SSH2 keys */
        int     pam_authentication_via_kbd_int;
 }       ServerOptions;
 /*
diff --git a/sshd.8 b/sshd.8
index 02960b70bdd8edb40f2abe5e216bb6d9b72c1e93..a66dac54e0986ece4809314ff58c2a569afebe7f 100644 (file)
--- a/sshd.8
+++ b/sshd.8
@@ -34,7 +34,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd.8,v 1.124 2001/05/19 19:43:57 stevesk Exp $
+.\" $OpenBSD: sshd.8,v 1.125 2001/05/20 17:20:35 markus Exp $
 .Dd September 25, 1999
 .Dt SSHD 8
 .Os
@@ -331,6 +331,34 @@ wildcards in the patterns.
 Only user names are valid; a numerical user ID isn't recognized.
 By default login is allowed regardless of the user name.
 .Pp
+.It Cm AuthorizedKeysFile
+Specifies the file that contains the public RSA keys that can be used
+for RSA authentication in protocol version 1.
+.Cm AuthorizedKeysFile
+may contain tokens of the form %T which are substituted during connection
+set-up. The following tokens are defined; %% is replaces by a literal '%',
+%h is replaced by the home directory of the user being authenticated and
+%u is replaced by the username of that user.
+After expansion,
+.Cm AuthorizedKeysFile
+is taken to be an absolute path or one realtive to the user's home
+directory.
+The default is
+.Dq .ssh/authorized_keys
+.It Cm AuthorizedKeysFile2
+Specifies the file that contains the public keys that can be used
+for public key authentication in protocol version 2.
+.Cm AuthorizedKeysFile2
+may contain tokens of the form %T which are substituted during connection
+set-up. The following tokens are defined; %% is replaces by a literal '%',
+%h is replaced by the home directory of the user being authenticated and
+%u is replaced by the username of that user.
+After expansion,
+.Cm AuthorizedKeysFile2
+is taken to be an absolute path or one realtive to the user's home
+directory.
+The default is
+.Dq .ssh/authorized_keys2
 .It Cm Banner
 In some jurisdictions, sending a warning message before authentication
 may be relevant for getting legal protection.
@@ -883,15 +911,18 @@ authentication protocol and cookie in standard input.
 Runs user's shell or command.
 .El
 .Sh AUTHORIZED_KEYS FILE FORMAT
-The
 .Pa $HOME/.ssh/authorized_keys
-file lists the RSA keys that are
+is the default file that lists the RSA keys that are
 permitted for RSA authentication in protocol version 1.
-Similarly, the
+.Cm AuthorizedKeysFile
+may be used to specify an alternative file.
+Similarly,
 .Pa $HOME/.ssh/authorized_keys2
-file lists the DSA and RSA keys that are
+is the default file that lists the DSA and RSA keys that are
 permitted for public key authentication (PubkeyAuthentication)
 in protocol version 2.
+.Cm AuthorizedKeysFile2
+may be used to specify an alternative file.
 .Pp
 Each line of the file contains one
 key (empty lines and lines starting with a
index 8c411e476f2f7e17613855d06ef8fd97bd49a8cb..90df340a6f80f5add80402a6cb3ebe3fb99a75a1 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: sshd_config,v 1.38 2001/04/15 21:41:29 deraadt Exp $
+#      $OpenBSD: sshd_config,v 1.39 2001/05/20 17:20:36 markus Exp $
 
 # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
 
@@ -41,6 +41,9 @@ RhostsRSAAuthentication no
 HostbasedAuthentication no
 #
 RSAAuthentication yes
+PubkeyAuthentication yes
+#AuthorizedKeysFile    %h/.ssh/authorized_keys
+#AuthorizedKeysFile2   %h/.ssh/authorized_keys2
 
 # To disable tunneled clear text passwords, change to no here!
 PasswordAuthentication yes
This page took 0.073439 seconds and 5 git commands to generate.