Public key reading abstraction (to allow future work)
rob at inversepath.com
rob at inversepath.com
Fri Sep 7 21:25:50 EST 2007
Damien,
I've filed a bug for this on mindrot as requested,
https://bugzilla.mindrot.org/show_bug.cgi?id=1348.
Patch attached in case that helps reviewing.
Comments welcome,
Rob
--
Rob Holland <rob at inversepath.com>
http://www.inversepath.com - Chief R & D Engineer
Inverse Path Ltd, 63 Park Road, Peterborough, PE1 2TN, UK
Registered in England: 5555973
-------------- next part --------------
=== modified file 'auth-rsa.c'
--- auth-rsa.c 2007-07-30 09:54:36 +0000
+++ auth-rsa.c 2007-08-02 12:17:32 +0000
@@ -173,7 +173,6 @@
u_int bits;
FILE *f;
u_long linenum = 0;
- struct stat st;
Key *key;
/* Temporarily use the user's uid. */
@@ -183,26 +182,9 @@
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. */
- f = fopen(file, "r");
+ f = open_keyfile(file, pw, options.strict_modes);
if (!f) {
- /* Restore the privileged uid. */
- restore_uid();
- xfree(file);
- return (0);
- }
- if (options.strict_modes &&
- secure_filename(f, file, pw, line, sizeof(line)) != 0) {
- xfree(file);
- fclose(f);
- logit("Authentication refused: %s", line);
+ xfree(file);
restore_uid();
return (0);
}
=== modified file 'auth.c'
--- auth.c 2007-07-30 09:54:36 +0000
+++ auth.c 2007-08-02 12:03:02 +0000
@@ -397,79 +397,6 @@
return host_status;
}
-
-/*
- * Check a given file for security. This is defined as all components
- * of the path to the file must be owned by either the owner of
- * of the file or root and no directories must be group or 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, struct passwd *pw,
- char *err, size_t errlen)
-{
- uid_t uid = pw->pw_uid;
- char buf[MAXPATHLEN], homedir[MAXPATHLEN];
- char *cp;
- int comparehome = 0;
- struct stat st;
-
- if (realpath(file, buf) == NULL) {
- snprintf(err, errlen, "realpath %s failed: %s", file,
- strerror(errno));
- return -1;
- }
- if (realpath(pw->pw_dir, homedir) != NULL)
- comparehome = 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;
- }
-
- /* If are passed the homedir then we can stop */
- if (comparehome && strcmp(homedir, buf) == 0) {
- debug3("secure_filename: terminating check at '%s'",
- buf);
- break;
- }
- /*
- * 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;
-}
-
struct passwd *
getpwnamallow(const char *user)
{
=== modified file 'auth.h'
--- auth.h 2007-07-30 09:54:36 +0000
+++ auth.h 2007-08-02 12:02:24 +0000
@@ -166,8 +166,6 @@
char *authorized_keys_file(struct passwd *);
char *authorized_keys_file2(struct passwd *);
-int
-secure_filename(FILE *, const char *, struct passwd *, char *, size_t);
HostStatus
check_key_in_hostfiles(struct passwd *, Key *, const char *,
=== modified file 'auth2-pubkey.c'
--- auth2-pubkey.c 2007-07-30 09:54:36 +0000
+++ auth2-pubkey.c 2007-08-02 12:19:19 +0000
@@ -183,34 +183,21 @@
int found_key = 0;
FILE *f;
u_long linenum = 0;
- struct stat st;
Key *found;
char *fp;
/* Temporarily use the user's uid. */
temporarily_use_uid(pw);
+ /* The authorized keys. */
+ file = authorized_keys_file(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();
- return 0;
- }
- /* Open the file containing the authorized keys. */
- f = fopen(file, "r");
+ f = open_keyfile(file, pw, options.strict_modes);
if (!f) {
- /* Restore the privileged uid. */
- restore_uid();
- return 0;
- }
- if (options.strict_modes &&
- secure_filename(f, file, pw, line, sizeof(line)) != 0) {
- fclose(f);
- logit("Authentication refused: %s", line);
- restore_uid();
- return 0;
+ xfree(file);
+ restore_uid();
+ return (0);
}
found_key = 0;
=== modified file 'misc.c'
--- misc.c 2007-07-30 09:54:36 +0000
+++ misc.c 2007-08-02 12:47:54 +0000
@@ -46,6 +46,9 @@
# include <paths.h>
#include <pwd.h>
#endif
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h>
+#endif
#ifdef SSH_TUN_OPENBSD
#include <net/if.h>
#endif
@@ -608,6 +611,102 @@
}
/*
+ * Check a given file for security. This is defined as all components
+ * of the path to the file must be owned by either the owner of
+ * of the file or root and no directories must be group or 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
+ */
+static int
+secure_filename(FILE *f, const char *file, struct passwd *pw,
+ char *err, size_t errlen)
+{
+ uid_t uid = pw->pw_uid;
+ char buf[MAXPATHLEN], homedir[MAXPATHLEN];
+ char *cp;
+ int comparehome = 0;
+ struct stat st;
+
+ if (realpath(file, buf) == NULL) {
+ snprintf(err, errlen, "realpath %s failed: %s", file,
+ strerror(errno));
+ return -1;
+ }
+ if (realpath(pw->pw_dir, homedir) != NULL)
+ comparehome = 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;
+ }
+
+ /* If are passed the homedir then we can stop */
+ if (comparehome && strcmp(homedir, buf) == 0) {
+ debug3("secure_filename: terminating check at '%s'",
+ buf);
+ break;
+ }
+ /*
+ * 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;
+}
+
+FILE *
+open_keyfile(const char *filename, struct passwd *pw, int strict_modes)
+{
+ char err[1024];
+ struct stat st;
+ FILE *f;
+
+ if (stat(filename, &st) < 0)
+ return NULL;
+
+ f = fopen(filename, "r");
+ if (!f)
+ return NULL;
+
+ if (strict_modes &&
+ secure_filename(f, filename, pw, err, sizeof(err)) != 0) {
+ fclose(f);
+ logit("Authentication refused: %s", err);
+ return NULL;
+ }
+
+ return f;
+}
+
+/*
* Read an entire line from a public key file into a static buffer, discarding
* lines that exceed the buffer size. Returns 0 on success, -1 on failure.
*/
=== modified file 'misc.h'
--- misc.h 2007-07-30 09:54:36 +0000
+++ misc.h 2007-08-02 12:12:51 +0000
@@ -85,6 +85,7 @@
char *read_passphrase(const char *, int);
int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
+FILE *open_keyfile(const char *, struct passwd *, int);
int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
#endif /* _MISC_H */
More information about the openssh-unix-dev
mailing list