From 3644f9124aaf35f2ad7b17cd05df19226d4e4d1c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 17 Dec 2012 20:58:25 +0100 Subject: [PATCH] pam_ssh_agent_auth: Allow multiple authorized keys files We need this because of https://github.com/NixOS/nixos/pull/52. --- .../linux/pam_ssh_agent_auth/default.nix | 6 + .../multiple-key-files.patch | 338 ++++++++++++++++++ 2 files changed, 344 insertions(+) create mode 100644 pkgs/os-specific/linux/pam_ssh_agent_auth/multiple-key-files.patch diff --git a/pkgs/os-specific/linux/pam_ssh_agent_auth/default.nix b/pkgs/os-specific/linux/pam_ssh_agent_auth/default.nix index 0edbb42bb237e..eae62c9e1973b 100644 --- a/pkgs/os-specific/linux/pam_ssh_agent_auth/default.nix +++ b/pkgs/os-specific/linux/pam_ssh_agent_auth/default.nix @@ -8,6 +8,12 @@ stdenv.mkDerivation rec { sha256 = "1a8cv223f30mvkxnyh9hk6kya0ynkwwkc5nhlz3rcqhxfw0fcva9"; }; + patches = + [ # Allow multiple colon-separated authorized keys files to be + # specified in the file= option. + ./multiple-key-files.patch + ]; + buildInputs = [ pam openssl perl ]; enableParallelBuilding = true; diff --git a/pkgs/os-specific/linux/pam_ssh_agent_auth/multiple-key-files.patch b/pkgs/os-specific/linux/pam_ssh_agent_auth/multiple-key-files.patch new file mode 100644 index 0000000000000..dc97b7d54f7c7 --- /dev/null +++ b/pkgs/os-specific/linux/pam_ssh_agent_auth/multiple-key-files.patch @@ -0,0 +1,338 @@ +diff -ru -x '*~' pam_ssh_agent_auth-0.9.4-orig/iterate_ssh_agent_keys.c pam_ssh_agent_auth-0.9.4/iterate_ssh_agent_keys.c +--- pam_ssh_agent_auth-0.9.4-orig/iterate_ssh_agent_keys.c 2012-06-28 01:47:49.000000000 +0000 ++++ pam_ssh_agent_auth-0.9.4/iterate_ssh_agent_keys.c 2012-12-17 19:29:16.014226336 +0000 +@@ -69,14 +69,14 @@ + return cookie; + } + +-int ++const char * + pamsshagentauth_find_authorized_keys(uid_t uid) + { + Identity *id; + Key *key; + AuthenticationConnection *ac; + char *comment; +- uint8_t retval = 0; ++ const char *key_file = 0; + + OpenSSL_add_all_digests(); + session_id2 = pamsshagentauth_session_id2_gen(); +@@ -90,13 +90,11 @@ + id->key = key; + id->filename = comment; + id->ac = ac; +- if(userauth_pubkey_from_id(id)) { +- retval = 1; +- } ++ key_file = userauth_pubkey_from_id(id); + pamsshagentauth_xfree(id->filename); + pamsshagentauth_key_free(id->key); + pamsshagentauth_xfree(id); +- if(retval == 1) ++ if(key_file) + break; + } + } +@@ -107,5 +105,5 @@ + } + pamsshagentauth_xfree(session_id2); + EVP_cleanup(); +- return retval; ++ return key_file; + } +diff -ru -x '*~' pam_ssh_agent_auth-0.9.4-orig/iterate_ssh_agent_keys.h pam_ssh_agent_auth-0.9.4/iterate_ssh_agent_keys.h +--- pam_ssh_agent_auth-0.9.4-orig/iterate_ssh_agent_keys.h 2012-06-28 01:47:49.000000000 +0000 ++++ pam_ssh_agent_auth-0.9.4/iterate_ssh_agent_keys.h 2012-12-17 19:28:57.454334806 +0000 +@@ -31,6 +31,6 @@ + #ifndef _ITERATE_SSH_AGENT_KEYS_H + #define _ITERATE_SSH_AGENT_KEYS_H + +-int pamsshagentauth_find_authorized_keys(uid_t); ++const char * pamsshagentauth_find_authorized_keys(uid_t); + + #endif +diff -ru -x '*~' pam_ssh_agent_auth-0.9.4-orig/pam_ssh_agent_auth.c pam_ssh_agent_auth-0.9.4/pam_ssh_agent_auth.c +--- pam_ssh_agent_auth-0.9.4-orig/pam_ssh_agent_auth.c 2012-06-28 01:47:49.000000000 +0000 ++++ pam_ssh_agent_auth-0.9.4/pam_ssh_agent_auth.c 2012-12-17 19:30:24.013830673 +0000 +@@ -60,7 +60,6 @@ + + #define strncasecmp_literal(A,B) strncasecmp( A, B, sizeof(B) - 1) + +-char *authorized_keys_file = NULL; + uint8_t allow_user_owned_authorized_keys_file = 0; + + #if ! HAVE___PROGNAME || HAVE_BUNDLE +@@ -161,15 +160,13 @@ + goto cleanexit; + } + +- if(authorized_keys_file_input && user) { +- /* +- * user is the name of the target-user, and so must be used for validating the authorized_keys file +- */ +- parse_authorized_key_file(user, authorized_keys_file_input); +- } else { +- pamsshagentauth_verbose("Using default file=/etc/security/authorized_keys"); +- authorized_keys_file = pamsshagentauth_xstrdup("/etc/security/authorized_keys"); +- } ++ if (!authorized_keys_file_input || !user) ++ authorized_keys_file_input = "/etc/security/authorized_keys"; ++ ++ /* ++ * user is the name of the target-user, and so must be used for validating the authorized_keys file ++ */ ++ parse_authorized_key_files(user, authorized_keys_file_input); + + /* + * PAM_USER and PAM_RUSER do not necessarily have to get set by the calling application, and we may be unable to divine the latter. +@@ -177,16 +174,17 @@ + */ + + if(user && strlen(ruser) > 0) { +- pamsshagentauth_verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); ++ pamsshagentauth_verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file_input); + + /* + * this pw_uid is used to validate the SSH_AUTH_SOCK, and so must be the uid of the ruser invoking the program, not the target-user + */ +- if(pamsshagentauth_find_authorized_keys(getpwnam(ruser)->pw_uid)) { +- pamsshagentauth_logit("Authenticated: `%s' as `%s' using %s", ruser, user, authorized_keys_file); ++ const char *key_file; ++ if((key_file = pamsshagentauth_find_authorized_keys(getpwnam(ruser)->pw_uid))) { ++ pamsshagentauth_logit("Authenticated: `%s' as `%s' using %s", ruser, user, key_file); + retval = PAM_SUCCESS; + } else { +- pamsshagentauth_logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); ++ pamsshagentauth_logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file_input); + } + } else { + pamsshagentauth_logit("No %s specified, cannot continue with this form of authentication", (user) ? "ruser" : "user" ); +@@ -198,7 +196,7 @@ + free(__progname); + #endif + +- free(authorized_keys_file); ++ free_authorized_key_files(); + + return retval; + } +diff -ru -x '*~' pam_ssh_agent_auth-0.9.4-orig/pam_ssh_agent_auth.pod pam_ssh_agent_auth-0.9.4/pam_ssh_agent_auth.pod +--- pam_ssh_agent_auth-0.9.4-orig/pam_ssh_agent_auth.pod 2012-06-28 01:47:49.000000000 +0000 ++++ pam_ssh_agent_auth-0.9.4/pam_ssh_agent_auth.pod 2012-12-17 19:52:35.968965448 +0000 +@@ -26,7 +26,7 @@ + + =item file= + +-Specify the path to the authorized_keys file(s) you would like to use for authentication. Subject to tilde and % EXPANSIONS (below) ++Specify the path(s) to the authorized_keys file(s) you would like to use for authentication. Subject to tilde and % EXPANSIONS (below). Paths are separated using colons. + + =item allow_user_owned_authorized_keys_file + +diff -ru -x '*~' pam_ssh_agent_auth-0.9.4-orig/pam_user_authorized_keys.c pam_ssh_agent_auth-0.9.4/pam_user_authorized_keys.c +--- pam_ssh_agent_auth-0.9.4-orig/pam_user_authorized_keys.c 2012-06-28 01:47:49.000000000 +0000 ++++ pam_ssh_agent_auth-0.9.4/pam_user_authorized_keys.c 2012-12-17 19:32:20.830157313 +0000 +@@ -79,66 +79,96 @@ + + #include "identity.h" + #include "pam_user_key_allowed2.h" ++#include "pam_user_authorized_keys.h" + +-extern char *authorized_keys_file; ++#define MAX_AUTHORIZED_KEY_FILES 16 ++ ++char *authorized_keys_files[MAX_AUTHORIZED_KEY_FILES]; ++unsigned int nr_authorized_keys_files = 0; + extern uint8_t allow_user_owned_authorized_keys_file; + uid_t authorized_keys_file_allowed_owner_uid; + + void +-parse_authorized_key_file(const char *user, const char *authorized_keys_file_input) ++parse_authorized_key_files(const char *user, const char *authorized_keys_file_input) + { +- char fqdn[HOST_NAME_MAX] = ""; ++ const char *pos = authorized_keys_file_input; + char hostname[HOST_NAME_MAX] = ""; +- char auth_keys_file_buf[4096] = ""; +- char *slash_ptr = NULL; +- char owner_uname[128] = ""; +- size_t owner_uname_len = 0; +- +- /* +- * temporary copy, so that both tilde expansion and percent expansion both get to apply to the path +- */ +- strncat(auth_keys_file_buf, authorized_keys_file_input, sizeof(auth_keys_file_buf) - 1); ++ char fqdn[HOST_NAME_MAX] = ""; ++ ++#if HAVE_GETHOSTNAME ++ *hostname = '\0'; ++ gethostname(fqdn, HOST_NAME_MAX); ++ strncat(hostname, fqdn, strcspn(fqdn,".")); ++#endif + +- if(allow_user_owned_authorized_keys_file) +- authorized_keys_file_allowed_owner_uid = getpwnam(user)->pw_uid; ++ while (pos) { ++ const char *colon = strchr(pos, ':'); ++ char auth_keys_file_buf[4096] = ""; ++ char *slash_ptr = NULL; ++ char owner_uname[128] = ""; ++ size_t owner_uname_len = 0; ++ ++ strncat(auth_keys_file_buf, pos, sizeof(auth_keys_file_buf) - 1); ++ if (colon) { ++ auth_keys_file_buf[colon - pos] = 0; ++ pos = colon + 1; ++ } else { ++ pos = 0; ++ } + +- if(*auth_keys_file_buf == '~') { +- if(*(auth_keys_file_buf+1) == '/') { ++ if(allow_user_owned_authorized_keys_file) + authorized_keys_file_allowed_owner_uid = getpwnam(user)->pw_uid; ++ ++ if(*auth_keys_file_buf == '~') { ++ if(*(auth_keys_file_buf+1) == '/') { ++ authorized_keys_file_allowed_owner_uid = getpwnam(user)->pw_uid; ++ } ++ else { ++ slash_ptr = strchr(auth_keys_file_buf,'/'); ++ if(!slash_ptr) ++ pamsshagentauth_fatal("cannot expand tilde in path without a `/'"); ++ ++ owner_uname_len = slash_ptr - auth_keys_file_buf - 1; ++ if(owner_uname_len > (sizeof(owner_uname) - 1) ) ++ pamsshagentauth_fatal("Username too long"); ++ ++ strncat(owner_uname, auth_keys_file_buf + 1, owner_uname_len); ++ if(!authorized_keys_file_allowed_owner_uid) ++ authorized_keys_file_allowed_owner_uid = getpwnam(owner_uname)->pw_uid; ++ } ++ char *tmp = pamsshagentauth_tilde_expand_filename(auth_keys_file_buf, authorized_keys_file_allowed_owner_uid); ++ strncpy(auth_keys_file_buf, tmp, sizeof(auth_keys_file_buf) - 1 ); ++ pamsshagentauth_xfree(tmp); + } +- else { +- slash_ptr = strchr(auth_keys_file_buf,'/'); +- if(!slash_ptr) +- pamsshagentauth_fatal("cannot expand tilde in path without a `/'"); +- +- owner_uname_len = slash_ptr - auth_keys_file_buf - 1; +- if(owner_uname_len > (sizeof(owner_uname) - 1) ) +- pamsshagentauth_fatal("Username too long"); +- +- strncat(owner_uname, auth_keys_file_buf + 1, owner_uname_len); +- if(!authorized_keys_file_allowed_owner_uid) +- authorized_keys_file_allowed_owner_uid = getpwnam(owner_uname)->pw_uid; ++ ++ if(strstr(auth_keys_file_buf, "%h")) { ++ authorized_keys_file_allowed_owner_uid = getpwnam(user)->pw_uid; + } +- authorized_keys_file = pamsshagentauth_tilde_expand_filename(auth_keys_file_buf, authorized_keys_file_allowed_owner_uid); +- strncpy(auth_keys_file_buf, authorized_keys_file, sizeof(auth_keys_file_buf) - 1 ); +- pamsshagentauth_xfree(authorized_keys_file) /* when we percent_expand later, we'd step on this, so free it immediately */; +- } + +- if(strstr(auth_keys_file_buf, "%h")) { +- authorized_keys_file_allowed_owner_uid = getpwnam(user)->pw_uid; ++ if (nr_authorized_keys_files >= MAX_AUTHORIZED_KEY_FILES) ++ pamsshagentauth_fatal("Too many authorized key files"); ++ authorized_keys_files[nr_authorized_keys_files++] = ++ pamsshagentauth_percent_expand(auth_keys_file_buf, "h", getpwnam(user)->pw_dir, "H", hostname, "f", fqdn, "u", user, NULL); + } ++} + +-#if HAVE_GETHOSTNAME +- *hostname = '\0'; +- gethostname(fqdn, HOST_NAME_MAX); +- strncat(hostname, fqdn, strcspn(fqdn,".")); +-#endif +- authorized_keys_file = pamsshagentauth_percent_expand(auth_keys_file_buf, "h", getpwnam(user)->pw_dir, "H", hostname, "f", fqdn, "u", user, NULL); ++void ++free_authorized_key_files() ++{ ++ unsigned int n; ++ for (n = 0; n < nr_authorized_keys_files; n++) ++ free(authorized_keys_files[n]); ++ nr_authorized_keys_files = 0; + } + +-int ++const char * + pam_user_key_allowed(Key * key) + { +- return pam_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), key, authorized_keys_file) +- || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_file); ++ unsigned int n; ++ for (n = 0; n < nr_authorized_keys_files; n++) { ++ if (pam_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), key, authorized_keys_files[n]) ++ || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_files[n])) ++ return authorized_keys_files[n]; ++ } ++ return 0; + } +diff -ru -x '*~' pam_ssh_agent_auth-0.9.4-orig/pam_user_authorized_keys.h pam_ssh_agent_auth-0.9.4/pam_user_authorized_keys.h +--- pam_ssh_agent_auth-0.9.4-orig/pam_user_authorized_keys.h 2010-01-13 02:17:01.000000000 +0000 ++++ pam_ssh_agent_auth-0.9.4/pam_user_authorized_keys.h 2012-12-17 19:24:34.477894517 +0000 +@@ -28,11 +28,12 @@ + */ + + +-#ifndef _PAM_USER_KEY_ALLOWED_H +-#define _PAM_USER_KEY_ALLOWED_H ++#ifndef _PAM_USER_AUTHORIZED_KEYS_H ++#define _PAM_USER_AUTHORIZED_KEYS_H + + #include "identity.h" +-int pam_user_key_allowed(Key *); +-void parse_authorized_key_file(const char *, const char *); ++const char * pam_user_key_allowed(Key *); ++void parse_authorized_key_files(const char *, const char *); ++void free_authorized_key_files(); + + #endif +diff -ru -x '*~' pam_ssh_agent_auth-0.9.4-orig/userauth_pubkey_from_id.c pam_ssh_agent_auth-0.9.4/userauth_pubkey_from_id.c +--- pam_ssh_agent_auth-0.9.4-orig/userauth_pubkey_from_id.c 2012-06-28 01:47:49.000000000 +0000 ++++ pam_ssh_agent_auth-0.9.4/userauth_pubkey_from_id.c 2012-12-17 19:27:30.813843933 +0000 +@@ -51,7 +51,7 @@ + extern u_char *session_id2; + extern uint8_t session_id_len; + +-int ++const char * + userauth_pubkey_from_id(Identity * id) + { + Buffer b = { 0 }; +@@ -59,11 +59,12 @@ + u_char *pkblob = NULL, *sig = NULL; + u_int blen = 0, slen = 0; + int authenticated = 0; ++ const char *key_file; + + pkalg = (char *) key_ssh_name(id->key); + + /* first test if this key is even allowed */ +- if(! pam_user_key_allowed(id->key)) ++ if(!(key_file = pam_user_key_allowed(id->key))) + goto user_auth_clean_exit; + + if(pamsshagentauth_key_to_blob(id->key, &pkblob, &blen) == 0) +@@ -96,5 +97,5 @@ + if(pkblob != NULL) + pamsshagentauth_xfree(pkblob); + CRYPTO_cleanup_all_ex_data(); +- return authenticated; ++ return authenticated ? key_file : 0; + } +diff -ru -x '*~' pam_ssh_agent_auth-0.9.4-orig/userauth_pubkey_from_id.h pam_ssh_agent_auth-0.9.4/userauth_pubkey_from_id.h +--- pam_ssh_agent_auth-0.9.4-orig/userauth_pubkey_from_id.h 2010-01-13 02:17:01.000000000 +0000 ++++ pam_ssh_agent_auth-0.9.4/userauth_pubkey_from_id.h 2012-12-17 19:25:54.893412987 +0000 +@@ -32,6 +32,6 @@ + #define _USERAUTH_PUBKEY_FROM_ID_H + + #include +-int userauth_pubkey_from_id(Identity *); ++const char * userauth_pubkey_from_id(Identity *); + + #endif