summaryrefslogtreecommitdiffabout
path: root/pam_ldaphome/pam_ldaphome.c
Side-by-side diff
Diffstat (limited to 'pam_ldaphome/pam_ldaphome.c') (more/less context) (show whitespace changes)
-rw-r--r--pam_ldaphome/pam_ldaphome.c262
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) {

Return to:

Send suggestions and report system problems to the System administrator.