diff options
Diffstat (limited to 'pam_ldaphome')
-rw-r--r-- | pam_ldaphome/pam_ldaphome.c | 262 |
1 files changed, 169 insertions, 93 deletions
diff --git a/pam_ldaphome/pam_ldaphome.c b/pam_ldaphome/pam_ldaphome.c index dd3f9e3..0b492dd 100644 --- a/pam_ldaphome/pam_ldaphome.c +++ b/pam_ldaphome/pam_ldaphome.c @@ -177,7 +177,7 @@ get_intval(struct gray_env *env, const char *name, int base, unsigned long *pv) return 0; } -char * +static char * parse_ldap_uri(const char *uri) { int wc; @@ -722,25 +722,35 @@ check_groups(int gc, char **gv, const char *username, gid_t gid) int i; struct group *gp; char *pgname; + int rc = 1; gp = getgrgid(gid); - pgname = gp ? gray_strdup(gp->gr_name) : NULL; - for (i = 0; i < gc; i++) { + if (gp) { + pgname = strdup(gp->gr_name); + if (!pgname) { + errno_to_pam(errno); + return -1; + } + } else + gp = NULL; + for (i = 0; rc && i < gc; i++) { if (strcmp(gv[i], pgname) == 0) { - free(pgname); - return 0; + rc = 0; + break; } gp = getgrnam(gv[i]); if (gp) { char **p; - for (p = gp->gr_mem; *p; p++) + for (p = gp->gr_mem; *p; p++) { if (strcmp(username, *p) == 0) { - free(pgname); - return 0; + rc = 0; + break; } } } - return 1; + } + free(pgname); + return rc; } static int @@ -856,36 +866,24 @@ copy_file(pam_handle_t *pamh, const char *src, const char *dst, return rc; } -#define INITIAL_READLINK_SIZE 128 - -int -read_link_name(const char *name, char **pbuf, size_t *psize, size_t *plen) +static int +read_link_name(const char *name, char **pbuf) { int rc = 0; - char *buf = *pbuf; - size_t size = *psize; - ssize_t linklen; + char *buf = NULL; + size_t size = 0; + ssize_t linklen = 0; while (1) { - if (!buf) { - size = INITIAL_READLINK_SIZE; - buf = malloc(size); - } else { - char *p; - size_t newsize = size << 1; - if (newsize < size) { - rc = ENAMETOOLONG; + if (linklen == size) { + char *p = gray_2nrealloc(&buf, &size, 1); + if (!p) { + errno_to_pam(errno); + rc = 1; break; } - size = newsize; - p = realloc(buf, size); - if (!p) - free(buf); buf = p; - } - if (!buf) { - rc = 1; - break; + linklen = size; } linklen = readlink(name, buf, size); @@ -894,7 +892,7 @@ read_link_name(const char *name, char **pbuf, size_t *psize, size_t *plen) break; } - if ((size_t) linklen < size) { + if (linklen < size) { buf[linklen++] = '\0'; rc = 0; break; @@ -906,12 +904,8 @@ read_link_name(const char *name, char **pbuf, size_t *psize, size_t *plen) free(buf); buf = NULL; } - size = 0; } *pbuf = buf; - *psize = size; - if (plen) - *plen = linklen; return rc; } @@ -920,11 +914,10 @@ static int copy_link(pam_handle_t *pamh, const char *src, const char *dst, char *buffer, size_t bufsize, struct stat *st) { - char *lnkname = NULL; - size_t lnklen = 0; + char *lnkname; int rc; - if (read_link_name(src, &lnkname, &lnklen, NULL)) { + if (read_link_name(src, &lnkname)) { _pam_log(LOG_ERR, "error reading link %s: %s", src, strerror(errno)); return 1; @@ -999,7 +992,11 @@ create_interdir(const char *path, struct passwd *pw) if (!p) return 1; len = p - path; - dir = gray_malloc(len + 1); + dir = malloc(len + 1); + if (!dir) { + errno_to_pam(errno); + return -1; + } memcpy(dir, path, len); dir[len] = 0; rc = create_hierarchy(dir, strlen(pw->pw_dir)); @@ -1268,6 +1265,21 @@ struct pubkeyfile { size_t lnm; /* Max. capacity of lnv */ }; +/* Close the public key file */ +static void +pubkeyfile_close(struct pubkeyfile *pkb) +{ + close(pkb->fd); + free(pkb->file_name); + free(pkb->base); + free(pkb->lnv); + + pkb->fd = -1; + pkb->file_name = NULL; + pkb->base = NULL; + pkb->lnv = NULL; +} + /* Open public key file NAME. Return 0 on success. On error, issue a diagnostic message and return -1. */ static int @@ -1280,7 +1292,13 @@ pubkeyfile_open(struct pubkeyfile *pkb, char *name) name, strerror(errno)); return -1; } - pkb->file_name = gray_strdup(name); + pkb->file_name = strdup(name); + if (!pkb->file_name) { + int rc = errno_to_pam(errno); + close(pkb->fd); + pkb->fd = -1; + return rc; + } return 0; } @@ -1298,7 +1316,11 @@ pubkeyfile_read(struct pubkeyfile *pkb) return -1; } pkb->size = st.st_size; - pkb->base = gray_malloc(st.st_size + 1); + pkb->base = malloc(st.st_size + 1); + if (!pkb->base) { + errno_to_pam(errno); + return -1; + } if (full_read(pkb->fd, pkb->file_name, pkb->base, pkb->size)) { _pam_log(LOG_ERR, "fread %s: %s", pkb->file_name, strerror(errno)); @@ -1310,8 +1332,11 @@ pubkeyfile_read(struct pubkeyfile *pkb) if (*p == '\n') ++pkb->lnc; pkb->lnm = pkb->lnc + 1; - pkb->lnv = gray_calloc(pkb->lnm, sizeof(pkb->lnv[0])); - + pkb->lnv = calloc(pkb->lnm, sizeof(pkb->lnv[0])); + if (pkb->lnv) { + errno_to_pam(errno); + return -1; + } i = 0; for (p = pkb->base; *p; p++) { if (p == pkb->base || p[-1] == 0) @@ -1329,7 +1354,10 @@ pubkeyfile_init(struct pubkeyfile *pkb, char *name) { if (pubkeyfile_open(pkb, name)) return -1; - return pubkeyfile_read(pkb); + if (pubkeyfile_read(pkb) == 0) + return 0; + pubkeyfile_close(pkb); + return -1; } /* Write data from lnv into the public key file, overwriting its current @@ -1388,52 +1416,49 @@ pubkeyfile_remove_lines(struct pubkeyfile *pkb, int pos, int count) /* Allocate COUNT lines starting from position POS in PKB, preserving the existing data. */ -static void +static int pubkeyfile_alloc_lines(struct pubkeyfile *pkb, size_t pos, size_t count) { if (pos > pkb->lnc) { _pam_log(LOG_ERR, "%s:%d: INTERNAL ERROR: pos out of range", __FILE__, __LINE__); - abort(); + return PAM_SERVICE_ERR; } if (pkb->lnc + count + 1 > pkb->lnm) { - pkb->lnm += count; - pkb->lnv = gray_realloc(pkb->lnv, - pkb->lnm * sizeof(pkb->lnv[0])); + char **p; + size_t lnm = pkb->lnm + count; + p = realloc(pkb->lnv, lnm * sizeof(pkb->lnv[0])); + if (!p) + return errno_to_pam(errno); + pkb->lnv = p; + pkb->lnm = lnm; } memmove(pkb->lnv + pos + count, pkb->lnv + pos, (pkb->lnc - pos + 1) * sizeof(pkb->lnv[0])); pkb->lnc += count; + return PAM_SUCCESS; } /* Insert lines from LV in position POS in the file PKB, shifting down existing lines as necessary. */ -void +static int pubkeyfile_insert_lines(struct pubkeyfile *pkb, size_t pos, char **lv) { size_t i; size_t lc; + int rc; for (lc = 0; lv[lc]; lc++) ; - pubkeyfile_alloc_lines(pkb, pos, lc); - + rc = pubkeyfile_alloc_lines(pkb, pos, lc); + if (rc == 0) { for (i = 0; i < lc; i++) pkb->lnv[pos + i] = lv[i]; } - -/* Close the public key file */ -void -pubkeyfile_close(struct pubkeyfile *pkb) -{ - close(pkb->fd); - free(pkb->file_name); - free(pkb->base); - free(pkb->lnv); + return rc; } - static int store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env) { @@ -1451,7 +1476,9 @@ store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env) len = homelen + pathlen; if (pw->pw_dir[homelen - 1] != '/') len++; - file_name = gray_malloc(len + 1); + file_name = malloc(len + 1); + if (!file_name) + return errno_to_pam(errno); memcpy(file_name, pw->pw_dir, homelen); if (pw->pw_dir[homelen - 1] != '/') file_name[homelen++] = '/'; @@ -1520,9 +1547,11 @@ store_pubkeys(char **keys, struct passwd *pw, struct gray_env *env) if (update) { pubkeyfile_remove_lines(&pkf, 0, i); - pubkeyfile_insert_lines(&pkf, 0, keys); + retval = pubkeyfile_insert_lines(&pkf, 0, keys); + if (retval == PAM_SUCCESS) { pubkeyfile_write(&pkf); retval = PAM_TRY_AGAIN; + } } else retval = PAM_SUCCESS; pubkeyfile_close(&pkf); @@ -1560,20 +1589,27 @@ import_public_key(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env) else { char *filter; gray_slist_t slist; - char **keys; slist = gray_slist_create(); + if (!slist) + retval = errno_to_pam(errno); + else { gray_expand_string(pamh, filter_pat, slist); gray_slist_append_char(slist, 0); filter = gray_slist_finish(slist); - - keys = get_pubkeys(ld, base, filter, attr); - gray_slist_free(&slist); + if (filter) { + char **keys = get_pubkeys(ld, base, filter, + attr); if (keys) { retval = store_pubkeys(keys, pw, env); argcvz_free(keys); } else retval = PAM_SUCCESS; + } else { + retval = errno_to_pam(gray_slist_err(slist)); + } + gray_slist_free(&slist); + } } ldap_unbind(ld); return retval; @@ -1694,6 +1730,12 @@ locate_unset(char **env, const char *name) return 0; } +/* Concatenate NAMELEN bytes from NAME, "=", A, and B. Allocate the + result using malloc. + + On ENOMEM, log a diagnostic message and exit with code 127. This function + should be used from child process only. +*/ static char * env_concat(char *name, size_t namelen, char *a, char *b) { @@ -1701,25 +1743,35 @@ env_concat(char *name, size_t namelen, char *a, char *b) size_t len; if (a && b) { - res = gray_malloc(namelen + 1 + strlen(a) + strlen(b) + 1); + res = malloc(namelen + 1 + strlen(a) + strlen(b) + 1); + if (res) { strcpy(res + namelen + 1, a); strcat(res, b); + } } else if (a) { len = strlen(a); if (ispunct(a[len-1])) len--; - res = gray_malloc(namelen + 1 + len + 1); + res = malloc(namelen + 1 + len + 1); + if (res) { memcpy(res + namelen + 1, a, len); res[namelen + 1 + len] = 0; + } } else /* if (a == NULL) */ { if (ispunct(b[0])) b++; len = strlen(b); - res = gray_malloc(namelen + 1 + len + 1); + res = malloc(namelen + 1 + len + 1); + if (res) strcpy(res + namelen + 1, b); } + if (res) { memcpy(res, name, namelen); res[namelen] = '='; + } else { + errno_to_pam(errno); + _exit(127); + } return res; } @@ -1740,6 +1792,14 @@ parsenv(char *str) char **wv = NULL; size_t wi = 0, wc = 0; +# define ASSERT_NOTNULL(p) do { \ + if (!(p)) { \ + errno_to_pam(errno); \ + _exit(127); \ + } \ + } while (0) + + if (!str) return NULL; @@ -1791,17 +1851,15 @@ parsenv(char *str) char *q; if (wi == wc) { - if (wc == 0) - wc = 4; - else - wc *= 2; - wv = gray_realloc(wv, wc * sizeof(wv[0])); + wv = gray_2nrealloc(wv, &wc, sizeof(wv[0])); + ASSERT_NOTNULL(wv); } switch (prev_state) { case st_squote: len -= 2; - wv[wi] = gray_malloc(len + 1); + wv[wi] = malloc(len + 1); + ASSERT_NOTNULL(wv[wi]); for (q = wv[wi]; *kw; ) { if (*kw == '\'') ++kw; @@ -1812,7 +1870,8 @@ parsenv(char *str) break; case st_dquote: len -= 2; - wv[wi] = gray_malloc(len + 1); + wv[wi] = malloc(len + 1); + ASSERT_NOTNULL(wv[wi]); q = wv[wi]; while ((*q++ = *kw++) != '=') ; @@ -1827,7 +1886,8 @@ parsenv(char *str) *q = 0; break; default: - wv[wi] = gray_malloc(len + 1); + wv[wi] = malloc(len + 1); + ASSERT_NOTNULL(wv[wi]); memcpy(wv[wi], kw, len); wv[wi][len] = 0; } @@ -1838,19 +1898,26 @@ parsenv(char *str) if (state != st_init) { if (wc == wi) { - ++wc; - wv = gray_realloc(wv, (wc + 1) * sizeof(wv[0])); + wv = gray_2nrealloc(wv, &wc, sizeof(wv[0])); + ASSERT_NOTNULL(wv); } - wv[wi++] = gray_strdup(kw); + wv[wi] = strdup(kw); + ASSERT_NOTNULL(wv[wi]); + ++wi; } - if (wc == wi) - wv = gray_realloc(wv, (wc + 1) * sizeof(wv[0])); + if (wc == wi) { + wv = gray_2nrealloc(wv, &wc, sizeof(wv[0])); + ASSERT_NOTNULL(wv); + } wv[wi] = NULL; return wv; } +/* Setup environment for exec* family call. On ENOMEM, exit with code 127. + This function should be called from a child process. +*/ static char ** env_setup(char *envstr) { @@ -1879,8 +1946,11 @@ env_setup(char *envstr) count++; /* Allocate the new environment. */ - new_env = gray_calloc(count + 1, sizeof new_env[0]); - + new_env = calloc(count + 1, sizeof new_env[0]); + if (!new_env) { + errno_to_pam(errno); + _exit(127); + } /* Populate the environment. */ n = 0; @@ -1938,9 +2008,16 @@ runas(struct passwd *pw) continue; for (p = gr->gr_mem; *p; p++) { if (strcmp (*p, pw->pw_name) == 0) { - if (sgc == sgm) - sgv = gray_2nrealloc(sgv, &sgm, + if (sgc == sgm) { + gid_t *p; + p = gray_2nrealloc(sgv, &sgm, sizeof(sgv[0])); + if (!p) { + errno_to_pam(errno); + return 1; //FIXME: proper error code + } + sgv = p; + } sgv[sgc++] = gr->gr_gid; } } @@ -2143,12 +2220,11 @@ ldaphome_main(pam_handle_t *pamh, int flags, int argc, const char **argv, _pam_parse(pamh, argc, argv); DEBUG(90,("enter %s", func)); - gray_pam_init(PAM_AUTHINFO_UNAVAIL); if (gray_env_read(config_file_name, &env) == 0) { char *val; struct passwd *pw; - if (val = gray_env_get(env, "ldap-config")) { + if ((val = gray_env_get(env, "ldap-config"))) { if (strcmp(val, "none") == 0) ldap_config_name = NULL; else @@ -2162,7 +2238,7 @@ ldaphome_main(pam_handle_t *pamh, int flags, int argc, const char **argv, gray_env_merge(&env, &tmp); } - if (val = gray_env_get(env, "authorized_keys")) + if ((val = gray_env_get(env, "authorized_keys"))) authorized_keys_file = val; if (check_user_groups(pamh, env, &pw, &retval) == 0) { |