mirror of
https://github.com/linux-pam/linux-pam.git
synced 2024-11-24 02:03:39 +08:00
da3bc2fc01
It is not required to cast the results of calloc, malloc, realloc, etc. Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
401 lines
9.4 KiB
C
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);
|
|
}
|