/* * pam_env.c * * Copyright (c) Andrew G. Morgan 1996,1997 * All rights reserved. * * This file was written from a "hint" provided by the people at SUN. * and the X/Open XSSO draft of March 1997. * * $Id$ */ #include "pam_private.h" #include "pam_inline.h" #include #include #include #ifdef sunos #define memmove(x,y,z) bcopy(y,x,z) #endif /* helper functions */ #ifdef PAM_DEBUG static void _pam_dump_env(pam_handle_t *pamh) { int i; D(("Listing environment of pamh=%p", pamh)); D(("pamh->env = %p", pamh->env)); D(("environment entries used = %d [of %d allocated]" , pamh->env->requested, pamh->env->entries)); for (i=0; ienv->requested; ++i) { _pam_output_debug( #if UINTPTR_MAX == UINT32_MAX ">%-3d [%10p]:[%s]" #else ">%-3d [%18p]:[%s]" #endif , i, pamh->env->list[i], pamh->env->list[i]); } _pam_output_debug("*NOTE* the last item should be (nil)"); } #else #define _pam_dump_env(x) #endif /* * Create the environment */ int _pam_make_env(pam_handle_t *pamh) { D(("called.")); IF_NO_PAMH(pamh, PAM_ABORT); /* * get structure memory */ pamh->env = malloc(sizeof(struct pam_environ)); if (pamh->env == NULL) { pam_syslog(pamh, LOG_CRIT, "_pam_make_env: out of memory"); return PAM_BUF_ERR; } /* * get list memory */ pamh->env->list = calloc( PAM_ENV_CHUNK, sizeof(char *) ); if (pamh->env->list == NULL) { pam_syslog(pamh, LOG_CRIT, "_pam_make_env: no memory for list"); _pam_drop(pamh->env); return PAM_BUF_ERR; } /* * fill entries in pamh->env */ pamh->env->entries = PAM_ENV_CHUNK; pamh->env->requested = 1; pamh->env->list[0] = NULL; _pam_dump_env(pamh); /* only active when debugging */ return PAM_SUCCESS; } /* * purge the environment */ void _pam_drop_env(pam_handle_t *pamh) { D(("called.")); IF_NO_PAMH(pamh, /* nothing to return */); if (pamh->env != NULL) { int i; /* we will only purge the pamh->env->requested number of elements */ for (i=pamh->env->requested-1; i-- > 0; ) { D(("dropping #%3d>%s<", i, pamh->env->list[i])); pam_overwrite_string(pamh->env->list[i]); /* clean */ _pam_drop(pamh->env->list[i]); /* forget */ } pamh->env->requested = 0; pamh->env->entries = 0; _pam_drop(pamh->env->list); /* forget */ _pam_drop(pamh->env); /* forget */ } else { D(("no environment present in pamh?")); } } /* * Return the item number of the given variable = first 'length' chars * of 'name_value'. Since this is a static function, it is safe to * assume its supplied arguments are well defined. */ static int _pam_search_env(const struct pam_environ *env , const char *name_value, size_t length) { int i; for (i=env->requested-1; i-- > 0; ) { if (strncmp(name_value,env->list[i],length) == 0 && env->list[i][length] == '=') { return i; /* Got it! */ } } return -1; /* no luck */ } /* * externally visible functions */ /* * pam_putenv(): Add/replace/delete a PAM-environment variable. * * Add/replace: * name_value = "NAME=VALUE" or "NAME=" (for empty value="\0") * * delete: * name_value = "NAME" */ int pam_putenv(pam_handle_t *pamh, const char *name_value) { size_t l2eq; int item, retval; D(("called.")); IF_NO_PAMH(pamh, PAM_ABORT); if (name_value == NULL) { pam_syslog(pamh, LOG_ERR, "pam_putenv: no variable indicated"); return PAM_PERM_DENIED; } /* * establish if we are setting or deleting; scan for '=' */ for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq); if (l2eq == 0) { pam_syslog(pamh, LOG_ERR, "pam_putenv: bad variable"); return PAM_BAD_ITEM; } /* * Look first for environment. */ if (pamh->env == NULL || pamh->env->list == NULL) { pam_syslog(pamh, LOG_ERR, "pam_putenv: no env%s found", pamh->env == NULL ? "":"-list"); return PAM_ABORT; } /* find the item to replace */ item = _pam_search_env(pamh->env, name_value, l2eq); if (name_value[l2eq]) { /* (re)setting */ if (item == -1) { /* new variable */ D(("adding item: %s", name_value)); /* enough space? */ if (pamh->env->entries <= pamh->env->requested) { register int i; register char **tmp; /* get some new space */ tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK , sizeof(char *) ); if (tmp == NULL) { /* nothing has changed - old env intact */ pam_syslog(pamh, LOG_CRIT, "pam_putenv: cannot grow environment"); return PAM_BUF_ERR; } /* copy old env-item pointers/forget old */ for (i=0; ienv->requested; ++i) { tmp[i] = pamh->env->list[i]; pamh->env->list[i] = NULL; } /* drop old list and replace with new */ _pam_drop(pamh->env->list); pamh->env->list = tmp; pamh->env->entries += PAM_ENV_CHUNK; D(("resized env list")); _pam_dump_env(pamh); /* only when debugging */ } item = pamh->env->requested-1; /* old last item (NULL) */ /* add a new NULL entry at end; increase counter */ pamh->env->list[pamh->env->requested++] = NULL; } else { /* replace old */ D(("replacing item: %s\n with: %s" , pamh->env->list[item], name_value)); pam_overwrite_string(pamh->env->list[item]); _pam_drop(pamh->env->list[item]); } /* * now we have a place to put the new env-item, insert at 'item' */ pamh->env->list[item] = _pam_strdup(name_value); if (pamh->env->list[item] != NULL) { _pam_dump_env(pamh); /* only when debugging */ return PAM_SUCCESS; } /* something went wrong; we should delete the item - fall through */ retval = PAM_BUF_ERR; /* an error occurred */ } else { retval = PAM_SUCCESS; /* we requested delete */ } /* getting to here implies we are deleting an item */ if (item < 0) { pam_syslog(pamh, LOG_ERR, "pam_putenv: delete non-existent entry; %s", name_value); return PAM_BAD_ITEM; } /* * remove item: purge memory; reset counter; resize [; display-env] */ D(("deleting: env#%3d:[%s]", item, pamh->env->list[item])); pam_overwrite_string(pamh->env->list[item]); _pam_drop(pamh->env->list[item]); --(pamh->env->requested); D(("memmove: item[%d]+%d -> item[%d]" , item+1, ( pamh->env->requested - item ), item)); (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1] , ( pamh->env->requested - item )*sizeof(char *) ); _pam_dump_env(pamh); /* only when debugging */ /* * deleted. */ return retval; } /* * Return the value of the requested environment variable */ const char *pam_getenv(pam_handle_t *pamh, const char *name) { int item; D(("called.")); IF_NO_PAMH(pamh, NULL); if (name == NULL) { pam_syslog(pamh, LOG_ERR, "pam_getenv: no variable indicated"); return NULL; } if (pamh->env == NULL || pamh->env->list == NULL) { pam_syslog(pamh, LOG_ERR, "pam_getenv: no env%s found", pamh->env == NULL ? "":"-list" ); return NULL; } /* find the requested item */ item = _pam_search_env(pamh->env, name, strlen(name)); if (item != -1) { D(("env-item: %s, found!", name)); return (pamh->env->list[item] + 1 + strlen(name)); } else { D(("env-item: %s, not found", name)); return NULL; } } static char **_copy_env(pam_handle_t *pamh) { char **dump; int i = pamh->env->requested; /* reckon size of environment */ char *const *env = pamh->env->list; D(("now get some memory for dump")); /* allocate some memory for this (plus the null tail-pointer) */ dump = calloc(i, sizeof(char *)); D(("dump = %p", dump)); if (dump == NULL) { return NULL; } /* now run through entries and copy the variables over */ dump[--i] = NULL; while (i-- > 0) { D(("env[%d]=`%s'", i,env[i])); dump[i] = _pam_strdup(env[i]); D(("->dump[%d]=`%s'", i,dump[i])); if (dump[i] == NULL) { /* out of memory */ while (dump[++i]) { pam_overwrite_string(dump[i]); _pam_drop(dump[i]); } _pam_drop(dump); return NULL; } } env = NULL; /* forget now */ /* return transcribed environment */ return dump; } char **pam_getenvlist(pam_handle_t *pamh) { int i; D(("called.")); IF_NO_PAMH(pamh, NULL); if (pamh->env == NULL || pamh->env->list == NULL) { pam_syslog(pamh, LOG_ERR, "pam_getenvlist: no env%s found", pamh->env == NULL ? "":"-list" ); return NULL; } /* some quick checks */ if (pamh->env->requested > pamh->env->entries) { pam_syslog(pamh, LOG_ERR, "pam_getenvlist: environment corruption"); _pam_dump_env(pamh); /* only active when debugging */ return NULL; } for (i=pamh->env->requested-1; i-- > 0; ) { if (pamh->env->list[i] == NULL) { pam_syslog(pamh, LOG_ERR, "pam_getenvlist: environment broken"); _pam_dump_env(pamh); /* only active when debugging */ return NULL; /* somehow we've broken the environment!? */ } } /* Seems fine; copy environment */ _pam_dump_env(pamh); /* only active when debugging */ return _copy_env(pamh); }