This patch adds support for simple parsing of ~/.ssh/config to get keyfile paths from it. It passes all found paths to pam_ssh as-is, so they will be parsed same way as PAM-provided ones. You'd probably like to apply '*-non-dotssh-paths.diff' too, as it allows pam_ssh to handle absolute and homedir paths. Else OpenSSH paths will be probably incompatible with pam_ssh. (c) 2009 Michał Górny (http://mgorny.alt.pl/) diff -dupr pam_ssh-1.92.orig/pam_ssh.c pam_ssh-1.92/pam_ssh.c --- pam_ssh-1.92.orig/pam_ssh.c 2009-07-04 12:54:50.862477621 +0200 +++ pam_ssh-1.92/pam_ssh.c 2009-07-04 13:19:44.088475873 +0200 @@ -534,25 +546,76 @@ pam_sm_authenticate(pam_handle_t *pamh, int retval; /* from calls */ const char *user; /* username */ + char *defkeyfiles; /* fallback keyfile list (from config or hardcoded) */ + log_init(MODULE_NAME, SYSLOG_LEVEL_ERROR, SYSLOG_FACILITY_AUTHPRIV, 0); + if ((retval = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) + return retval; + if (!(user && (pwent = getpwnam(user)) && pwent->pw_dir && + *pwent->pw_dir)) + return PAM_AUTH_ERR; + + if (!(defkeyfiles = strdup(DEF_KEYFILES))) { + pam_ssh_log(LOG_CRIT, "out of memory"); + return PAM_SERVICE_ERR; + } + + { /* Try to get keyfile path from ~/.ssh/config using very simple parser */ + char *cpath; + FILE *f; + + if (asprintf(&cpath, "%s/%s/config", pwent->pw_dir, SSH_CLIENT_DIR) != -1) { + if ((f = fopen(cpath, "r"))) { + char buf[512]; + char *s, *t, *u; + + while ((s = fgets(buf, sizeof(buf), f))) { + s += strspn(s, " \t"); + t = s + strcspn(s, " \t="); + if (*t != '=') { + u = t + strspn(t, " \t"); + *t = 0; + t = u; + } + if (*t != '=') + continue; + *(t++) = 0; + + if (strcasecmp(s, "IdentityFile")) + continue; + + t += strspn(t, " \t"); + u = t + strcspn(t, " \t\n"); + *u = 0; + + if (asprintf(&u, "%s,%s", t, defkeyfiles) != -1) { + free(defkeyfiles); + defkeyfiles = u; + } + } + } + } + } + allow_blank_passphrase = 0; keyfiles = kfspec = NULL; #if HAVE_OPENPAM if ((kfspec = openpam_get_option(pamh, PAM_OPT_KEYFILES_NAME))) { if (!(kfspec = opt_arg(kfspec))) { + free(defkeyfiles); openpam_log(PAM_LOG_ERROR, "invalid keyfile list"); return PAM_SERVICE_ERR; } } else - kfspec = DEF_KEYFILES; + kfspec = defkeyfiles; if ((kfspec = openpam_get_option(pamh, PAM_OPT_BLANK_PASSPHRASE))) allow_blank_passphrase = 1; #elif HAVE_PAM_STRUCT_OPTIONS || !HAVE_PAM_STD_OPTION memset(&options, 0, sizeof options); pam_std_option(&options, other_options, argc, argv); if (!pam_test_option(&options, PAM_OPT_KEYFILES, &kfspec)) - kfspec = DEF_KEYFILES; + kfspec = defkeyfiles; allow_blank_passphrase = pam_test_option(&options, PAM_OPT_BLANK_PASSPHRASE, NULL); #else @@ -568,6 +631,7 @@ pam_sm_authenticate(pam_handle_t *pamh, if (!(kfspec = opt_arg(*argv))) { pam_ssh_log(LOG_ERR, "invalid keyfile list"); + free(defkeyfiles); return PAM_SERVICE_ERR; } break; @@ -579,18 +643,12 @@ pam_sm_authenticate(pam_handle_t *pamh, pam_std_option(&options, *argv); } if (!kfspec) - kfspec = DEF_KEYFILES; + kfspec = defkeyfiles; #endif - - if ((retval = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) - return retval; - if (!(user && (pwent = getpwnam(user)) && pwent->pw_dir && - *pwent->pw_dir)) - return PAM_AUTH_ERR; - retval = openpam_borrow_cred(pamh, pwent); if (retval != PAM_SUCCESS && retval != PAM_PERM_DENIED) { pam_ssh_log(LOG_ERR, "can't drop privileges: %m"); + free(defkeyfiles); return retval; } @@ -605,10 +663,12 @@ pam_sm_authenticate(pam_handle_t *pamh, #endif if (retval != PAM_SUCCESS) { openpam_restore_cred(pamh); + free(defkeyfiles); return retval; } if (!pass) { openpam_restore_cred(pamh); + free(defkeyfiles); return PAM_AUTH_ERR; } @@ -621,12 +681,14 @@ pam_sm_authenticate(pam_handle_t *pamh, if (asprintf(&dotdir, "%s/%s", pwent->pw_dir, SSH_CLIENT_DIR) == -1) { pam_ssh_log(LOG_CRIT, "out of memory"); openpam_restore_cred(pamh); + free(defkeyfiles); return PAM_SERVICE_ERR; } authenticated = 0; if (!(keyfiles = strdup(kfspec))) { pam_ssh_log(LOG_CRIT, "out of memory"); openpam_restore_cred(pamh); + free(defkeyfiles); return PAM_SERVICE_ERR; } for (file = strtok(keyfiles, SEP_KEYFILES); file; @@ -636,6 +698,7 @@ pam_sm_authenticate(pam_handle_t *pamh, authenticated = 1; free(dotdir); free(keyfiles); + free(defkeyfiles); if (!authenticated) { openpam_restore_cred(pamh); return PAM_AUTH_ERR;