diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-05-15 18:22:08 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-05-15 18:22:08 +0300 |
commit | 8a9a1ee295f7b824bd07c43a985b1d6705fcd0a8 (patch) | |
tree | adbb332f0bdd00a927e4925698ede206134d85b4 | |
parent | 381fbf336578e31bb56bf0394fef486a9fb93f79 (diff) | |
download | pam-modules-8a9a1ee295f7b824bd07c43a985b1d6705fcd0a8.tar.gz pam-modules-8a9a1ee295f7b824bd07c43a985b1d6705fcd0a8.tar.bz2 |
Allow for multiple authorized keys.
* pam_ldaphome/pam_ldaphome.c (argcvz_free,trimnl): New functions.
(get_ldap_attr): Trim trailing newlines from the return value.
(ldap_search): Rename to get_pubkeys. Return null-terminated array
of sorted lexicographically keys.
(store_pubkey): Rename to store_pubkeys, take char ** as its
first argument. Store all keys unless the file already contains
exactly that set of keys.
(import_public_key): Call store_pubkeys. Use argcvz_free to
free the keys.
-rw-r--r-- | pam_ldaphome/pam_ldaphome.c | 141 |
1 files changed, 92 insertions, 49 deletions
diff --git a/pam_ldaphome/pam_ldaphome.c b/pam_ldaphome/pam_ldaphome.c index c61796a..26bb6d7 100644 --- a/pam_ldaphome/pam_ldaphome.c +++ b/pam_ldaphome/pam_ldaphome.c @@ -70,9 +70,18 @@ argcv_free(int wc, char **wv) { int i; - for (i = 0; i < wc; i++) { + for (i = 0; i < wc; i++) + free(wv[i]); + free(wv); +} + +static void +argcvz_free(char **wv) +{ + int i; + + for (i = 0; wv[i]; i++) free(wv[i]); - } free(wv); } @@ -422,6 +431,15 @@ ldap_unbind(LDAP *ld) } } +static void +trimnl(char *s) +{ + size_t len = strlen(s); + while (len > 0 && s[len-1] == '\n') + --len; + s[len] = 0; +} + static char * get_ldap_attr(LDAP *ld, LDAPMessage *msg, const char *attr) { @@ -447,20 +465,28 @@ get_ldap_attr(LDAP *ld, LDAPMessage *msg, const char *attr) val = strdup(values[0]->bv_val); if (!val) _pam_log(LOG_ERR, "%s", strerror(errno)); - else + else { + trimnl(val); DEBUG(1, ("pubkey: %s", val)); + } ldap_value_free_len(values); return val; } -static char * -ldap_search(LDAP *ld, const char *base, const char *filter, const char *attr) +static int +keycmp(const void *a, const void *b) +{ + return strcmp(a, b); +} + +static char ** +get_pubkeys(LDAP *ld, const char *base, const char *filter, const char *attr) { int rc; LDAPMessage *res, *msg; ber_int_t msgid; char *attrs[2]; - char *ret; + char **ret; attrs[0] = (char*) attr; attrs[1] = NULL; @@ -480,16 +506,29 @@ ldap_search(LDAP *ld, const char *base, const char *filter, const char *attr) } rc = ldap_count_entries(ld, res); - if (rc == 0) { - _pam_log(LOG_ERR, "not enough entires"); - return NULL; + + ret = calloc(rc + 1, sizeof(ret[0])); + if (!ret) + _pam_log(LOG_ERR, "%s", strerror(errno)); + else { + int i = 0; + + for (msg = ldap_first_entry(ld, res); msg; + msg = ldap_next_entry(ld, msg)) { + char *s = get_ldap_attr(ld, msg, attr); + if (s) + ret[i++] = s; + } + + if (i != rc) { + argcv_free(i, ret); + ret = NULL; + } + ret[i] = NULL; + + qsort(ret, i, sizeof(ret[0]), keycmp); } - if (rc > 1) - _pam_log(LOG_NOTICE, "LDAP: too many entries for filter %s", - filter); - - msg = ldap_first_entry(ld, res); - ret = get_ldap_attr(ld, msg, attr); + ldap_msgfree(res); return ret; @@ -968,7 +1007,7 @@ recursive_copy(pam_handle_t *pamh, DIR *dir, if (chown(dstbuf->name, pw->pw_uid, pw->pw_gid) || (st && chmod(dstbuf->name, st->st_mode & 07777))) { _pam_log(LOG_ERR, - "cannot set privileges of %s:" + "cannot set privileges for %s:" "%s", dstbuf->name, strerror(errno)); @@ -1043,15 +1082,14 @@ populate_homedir(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env) } static int -store_pubkey(const char *key, struct passwd *pw) +store_pubkeys(char **keys, struct passwd *pw) { FILE *fp; - const char *kp; int c; - int found = 0; char *file_name; size_t homelen, pathlen, len; - int retval; + int retval, i; + int update = 0; homelen = strlen(pw->pw_dir); pathlen = strlen(authorized_keys_file); @@ -1064,9 +1102,11 @@ store_pubkey(const char *key, struct passwd *pw) file_name[homelen++] = '/'; strcpy(file_name + homelen, authorized_keys_file); - fp = fopen(file_name, "a+"); - if (!fp && create_interdir(file_name, pw) == 0) - fp = fopen(file_name, "a+"); + fp = fopen(file_name, "r+"); + if (!fp && create_interdir(file_name, pw) == 0) { + fp = fopen(file_name, "w"); + update = 1; + } if (!fp) { _pam_log(LOG_EMERG, "cannot open file %s: %s", file_name, strerror(errno)); @@ -1075,33 +1115,36 @@ store_pubkey(const char *key, struct passwd *pw) } free(file_name); fchown(fileno(fp), pw->pw_uid, pw->pw_gid); - - kp = key; - while (!feof(fp)) { - while (*kp && (c = getc(fp)) != EOF && c == *kp) - kp++; - if (*kp == 0) { - DEBUG(2, ("key found")); - found = 1; - break; - } - kp = key; - if (c != '\n') { - if (c != EOF) { - while ((c = getc(fp)) != EOF && c != '\n') - ; + + if (!update) { + i = 0; + do { + const char *kp = keys[i++]; + if (!kp) { + DEBUG(2, ("some keys deleted")); + update = 1; + break; } - if (c == EOF) { - if (ftell(fp)) - fputc('\n', fp); + while (*kp && (c = getc(fp)) != EOF && c == *kp) + kp++; + if (*kp) { + DEBUG(2, ("key %d mismatch", i)); + update = 1; break; } + } while (c == '\n'); + + if (update) { + rewind(fp); + ftruncate(fileno(fp), 0); } } - - if (!found) { - fwrite(key, strlen(key), 1, fp); - fputc('\n', fp); + + if (update) { + for (i = 0; keys[i]; i++) { + fwrite(keys[i], strlen(keys[i]), 1, fp); + fputc('\n', fp); + } retval = PAM_TRY_AGAIN; } else retval = PAM_SUCCESS; @@ -1135,17 +1178,17 @@ import_public_key(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env) else { char *filter; gray_slist_t slist; - char *pubkey; + char **keys; slist = gray_slist_create(); gray_expand_string(pamh, filter_pat, slist); gray_slist_append_char(slist, 0); filter = gray_slist_finish(slist); - pubkey = ldap_search(ld, base, filter, attr); + keys = get_pubkeys(ld, base, filter, attr); gray_slist_free(&slist); - retval = store_pubkey(pubkey, pw); - free(pubkey); + retval = store_pubkeys(keys, pw); + argcvz_free(keys); } ldap_unbind(ld); return retval; |