Here is the user-dependent IdentityFile patch for openssh3.5 (BSD version), which allows private key files to be placed system wide (for all users) in a secure (non-NFS) mounted location. This addresses an important security hole on systems where home directories are NFS mounted, particularly if there are users who use blank passphrases (or when lpd is tunneled through ssh on systems running lpd as user lp) instead of ssh-agent. IdentityFile now accepts the same %u, %h, %% options that AuthorizedKeysFile accepts. For example, one can specify a user-dependent IdentityFile in ssh_config: IdentityFile /ssh/%u/id_rsa This version of the IdentityFile patch modifies ssh-keygen to use the directory part of the first local host IdentityFile entry as the default key location (which may then be overridden). Note: Useful commands for moving existing key files system wide to the new secure directory (e.g. /ssh) are available at http://www.math.ualberta.ca/imaging/snfs/openssh.html diff -ru ssh/auth.c sshJ/auth.c --- ssh/auth.c Fri Sep 20 12:41:29 2002 +++ sshJ/auth.c Sat Jan 18 16:20:41 2003 @@ -35,7 +35,6 @@ #include "auth.h" #include "auth-options.h" #include "canohost.h" -#include "buffer.h" #include "bufaux.h" #include "uidswap.h" #include "tildexpand.h" @@ -214,62 +213,6 @@ 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) { diff -ru ssh/auth.h sshJ/auth.h --- ssh/auth.h Thu Sep 26 05:38:43 2002 +++ sshJ/auth.h Sat Jan 18 16:20:41 2003 @@ -159,7 +159,6 @@ struct passwd * auth_get_user(void); -char *expand_filename(const char *, struct passwd *); char *authorized_keys_file(struct passwd *); char *authorized_keys_file2(struct passwd *); diff -ru ssh/ssh-keygen/Makefile sshJ/ssh-keygen/Makefile --- ssh/ssh-keygen/Makefile Wed Jun 27 13:29:16 2001 +++ sshJ/ssh-keygen/Makefile Thu Oct 31 09:46:47 2002 @@ -10,7 +10,7 @@ BINDIR= /usr/bin MAN= ssh-keygen.1 -SRCS= ssh-keygen.c +SRCS= ssh-keygen.c readconf.c .include <bsd.prog.mk> diff -ru ssh/ssh-keygen.c sshJ/ssh-keygen.c --- ssh/ssh-keygen.c Sun Jun 23 03:39:55 2002 +++ sshJ/ssh-keygen.c Sat Jan 18 16:20:41 2003 @@ -27,6 +27,9 @@ #include "pathnames.h" #include "log.h" #include "readpass.h" +#include "ssh.h" +#include "readconf.h" +#include "tildexpand.h" #ifdef SMARTCARD #include "scard.h" @@ -78,6 +81,13 @@ char hostname[MAXHOSTNAMELEN]; +/* + * General data structure for command line options and options configurable + * in configuration files. See readconf.h. + */ +Options options; +uid_t original_real_uid; + static void ask_filename(struct passwd *pw, const char *prompt) { @@ -103,7 +113,28 @@ break; } - snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); + + if(options.num_identity_files > 0) { + char *file=NULL; + char *p=strrchr(name,'/'); + if(p) file = p+1; + + name = tilde_expand_filename(options.identity_files[0], + original_real_uid); + name = expand_filename(name,pw); + p=strrchr(name,'/'); + if(p) *p=0; + + if(file && *file) { + snprintf(identity_file, sizeof(identity_file), "%s/%s", name,file); + } + else { + snprintf(identity_file, sizeof(identity_file), "%s", name); + } + } else { + snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, + name); + } fprintf(stderr, "%s (%s): ", prompt, identity_file); fflush(stderr); if (fgets(buf, sizeof(buf), stdin) == NULL) @@ -750,6 +781,7 @@ struct stat st; int opt, type, fd, download = 0; FILE *f; + char buf[256]; extern int optind; extern char *optarg; @@ -767,6 +799,13 @@ exit(1); } + snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, + _PATH_SSH_USER_CONFFILE); + (void)read_config_file(buf, hostname, &options); + + /* Read systemwide configuration file after user config. */ + (void)read_config_file(_PATH_HOST_CONFIG_FILE, hostname, &options); + while ((opt = getopt(ac, av, "deiqpclBRxXyb:f:t:U:D:P:N:C:")) != -1) { switch (opt) { case 'b': diff -ru ssh/ssh.c sshJ/ssh.c --- ssh/ssh.c Wed Sep 18 19:58:18 2002 +++ sshJ/ssh.c Sat Jan 18 16:20:41 2003 @@ -1165,9 +1165,13 @@ xfree(keys); } #endif /* SMARTCARD */ + struct passwd *pw; + pw=getpwuid(original_real_uid); + if (!pw) fatal("Unknown user id: %d", original_real_uid); for (; i < options.num_identity_files; i++) { filename = tilde_expand_filename(options.identity_files[i], original_real_uid); + filename = expand_filename(filename,pw); public = key_load_public(filename, NULL); debug("identity file %s type %d", filename, public ? public->type : -1); diff -ru ssh/tildexpand.c sshJ/tildexpand.c --- ssh/tildexpand.c Sat Jun 22 21:25:50 2002 +++ sshJ/tildexpand.c Sat Jan 18 16:20:41 2003 @@ -16,6 +16,7 @@ #include "xmalloc.h" #include "log.h" #include "tildexpand.h" +#include "buffer.h" /* * Expands tildes in the file name. Returns data allocated by xmalloc. @@ -47,7 +48,7 @@ if (userlen == 0) pw = getpwuid(my_uid); /* Own home directory. */ else { - /* Tilde refers to someone elses home directory. */ + /* Tilde refers to someone else's home directory. */ if (userlen > sizeof(user) - 1) fatal("User name after tilde too long."); memcpy(user, filename, userlen); @@ -71,3 +72,58 @@ strcmp(pw->pw_dir, "/") ? "/" : "", cp + 1); return expanded; } + +/* + * 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; +} diff -ru ssh/tildexpand.h sshJ/tildexpand.h --- ssh/tildexpand.h Tue Jun 26 11:27:25 2001 +++ sshJ/tildexpand.h Sat Jan 18 16:20:41 2003 @@ -13,3 +13,4 @@ */ char *tilde_expand_filename(const char *, uid_t); +char *expand_filename(const char *, struct passwd *);