linux-pam/libpam/pam_env.c
Tobias Stoeckmann da3bc2fc01 treewide: do not cast calloc/malloc/realloc
It is not required to cast the results of calloc, malloc,
realloc, etc.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2023-11-12 19:43:03 +00:00

401 lines
9.4 KiB
C

/*
* pam_env.c
*
* Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 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 <string.h>
#include <stdint.h>
#include <stdlib.h>
#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; i<pamh->env->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; i<pamh->env->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);
}