aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2012-05-15 18:22:08 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2012-05-15 18:22:08 +0300
commit8a9a1ee295f7b824bd07c43a985b1d6705fcd0a8 (patch)
treeadbb332f0bdd00a927e4925698ede206134d85b4
parent381fbf336578e31bb56bf0394fef486a9fb93f79 (diff)
downloadpam-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.c141
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;

Return to:

Send suggestions and report system problems to the System administrator.