4 * Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 1996,1997
7 * This file was written from a "hint" provided by the people at SUN.
8 * and the X/Open XSSO draft of March 1997.
10 * $Id: pam_env.c,v 1.2 1997/02/15 15:56:48 morgan Exp morgan $
11 * $FreeBSD: src/contrib/libpam/libpam/pam_env.c,v 1.1.1.1.6.2 2001/06/11 15:28:12 markm Exp $
12 * $DragonFly: src/contrib/libpam/libpam/Attic/pam_env.c,v 1.2 2003/06/17 04:24:03 dillon Exp $
15 * Revision 1.2 1997/02/15 15:56:48 morgan
16 * liberate pamh->env structure too!
18 * Revision 1.1 1996/12/01 03:14:13 morgan
25 #define memmove(x,y,z) bcopy(y,x,z)
28 #include "pam_private.h"
30 /* helper functions */
33 static void _pam_dump_env(pam_handle_t *pamh)
37 D(("Listing environment of pamh=%p", pamh));
38 D(("pamh->env = %p", pamh->env));
39 D(("environment entries used = %d [of %d allocated]"
40 , pamh->env->requested, pamh->env->entries));
42 for (i=0; i<pamh->env->requested; ++i) {
43 _pam_output_debug(">%-3d [%9p]:[%s]"
44 , i, pamh->env->list[i], pamh->env->list[i]);
46 _pam_output_debug("*NOTE* the last item should be (nil)");
49 #define _pam_dump_env(x)
53 * Create the environment
56 int _pam_make_env(pam_handle_t *pamh)
59 IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT);
62 * get structure memory
65 pamh->env = (struct pam_environ *) malloc(sizeof(struct pam_environ));
66 if (pamh->env == NULL) {
67 pam_system_log(pamh, NULL, LOG_CRIT, "_pam_make_env: out of memory");
75 pamh->env->list = (char **)calloc( PAM_ENV_CHUNK, sizeof(char *) );
76 if (pamh->env->list == NULL) {
77 pam_system_log(pamh, NULL, LOG_CRIT,
78 "_pam_make_env: no memory for list");
84 * fill entries in pamh->env
87 pamh->env->entries = PAM_ENV_CHUNK;
88 pamh->env->requested = 1;
89 pamh->env->list[0] = NULL;
91 _pam_dump_env(pamh); /* only active when debugging */
97 * purge the environment
100 void _pam_drop_env(pam_handle_t *pamh)
103 IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */);
105 if (pamh->env != NULL) {
107 /* we will only purge the pamh->env->requested number of elements */
109 for (i=pamh->env->requested-1; i-- > 0; ) {
110 D(("dropping #%3d>%s<", i, pamh->env->list[i]));
111 _pam_overwrite(pamh->env->list[i]); /* clean */
112 _pam_drop(pamh->env->list[i]); /* forget */
114 pamh->env->requested = 0;
115 pamh->env->entries = 0;
116 _pam_drop(pamh->env->list); /* forget */
117 _pam_drop(pamh->env); /* forget */
119 D(("no environment present in pamh?"));
124 * Return the item number of the given variable = first 'length' chars
125 * of 'name_value'. Since this is a static function, it is safe to
126 * assume its supplied arguments are well defined.
129 static int _pam_search_env(const struct pam_environ *env
130 , const char *name_value, int length)
134 for (i=env->requested-1; i-- > 0; ) {
135 if (strncmp(name_value,env->list[i],length) == 0
136 && env->list[i][length] == '=') {
138 return i; /* Got it! */
143 return -1; /* no luck */
147 * externally visible functions
151 * pam_putenv(): Add/replace/delete a PAM-environment variable.
154 * name_value = "NAME=VALUE" or "NAME=" (for empty value="\0")
157 * name_value = "NAME"
160 int pam_putenv(pam_handle_t *pamh, const char *name_value)
162 int l2eq, item, retval;
165 IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT);
167 if (name_value == NULL) {
168 pam_system_log(pamh, NULL, LOG_ERR,
169 "pam_putenv: no variable indicated");
170 return PAM_PERM_DENIED;
174 * establish if we are setting or deleting; scan for '='
177 for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq);
179 pam_system_log(pamh, NULL, LOG_ERR, "pam_putenv: bad variable");
184 * Look first for environment.
187 if (pamh->env == NULL || pamh->env->list == NULL) {
188 pam_system_log(pamh, NULL, LOG_ERR, "pam_putenv: no env%s found"
189 , pamh->env == NULL ? "":"-list");
193 /* find the item to replace */
195 item = _pam_search_env(pamh->env, name_value, l2eq);
197 if (name_value[l2eq]) { /* (re)setting */
199 if (item == -1) { /* new variable */
200 D(("adding item: %s", name_value));
202 if (pamh->env->entries <= pamh->env->requested) {
206 /* get some new space */
207 tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK
210 /* nothing has changed - old env intact */
211 pam_system_log(pamh, NULL, LOG_CRIT,
212 "pam_putenv: cannot grow environment");
216 /* copy old env-item pointers/forget old */
217 for (i=0; i<pamh->env->requested; ++i) {
218 tmp[i] = pamh->env->list[i];
219 pamh->env->list[i] = NULL;
222 /* drop old list and replace with new */
223 _pam_drop(pamh->env->list);
224 pamh->env->list = tmp;
225 pamh->env->entries += PAM_ENV_CHUNK;
227 D(("resized env list"));
228 _pam_dump_env(pamh); /* only when debugging */
231 item = pamh->env->requested-1; /* old last item (NULL) */
233 /* add a new NULL entry at end; increase counter */
234 pamh->env->list[pamh->env->requested++] = NULL;
236 } else { /* replace old */
237 D(("replacing item: %s\n with: %s"
238 , pamh->env->list[item], name_value));
239 _pam_overwrite(pamh->env->list[item]);
240 _pam_drop(pamh->env->list[item]);
244 * now we have a place to put the new env-item, insert at 'item'
247 pamh->env->list[item] = _pam_strdup(name_value);
248 if (pamh->env->list[item] != NULL) {
249 _pam_dump_env(pamh); /* only when debugging */
253 /* something went wrong; we should delete the item - fall through */
255 retval = PAM_BUF_ERR; /* an error occurred */
257 retval = PAM_SUCCESS; /* we requested delete */
260 /* getting to here implies we are deleting an item */
263 pam_system_log(pamh, NULL, LOG_ERR,
264 "pam_putenv: delete non-existent entry; %s",
270 * remove item: purge memory; reset counter; resize [; display-env]
273 D(("deleting: env#%3d:[%s]", item, pamh->env->list[item]));
274 _pam_overwrite(pamh->env->list[item]);
275 _pam_drop(pamh->env->list[item]);
276 --(pamh->env->requested);
277 D(("mmove: item[%d]+%d -> item[%d]"
278 , item+1, ( pamh->env->requested - item ), item));
279 (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1]
280 , ( pamh->env->requested - item )*sizeof(char *) );
282 _pam_dump_env(pamh); /* only when debugging */
292 * Return the value of the requested environment variable
295 const char *pam_getenv(pam_handle_t *pamh, const char *name)
300 IF_NO_PAMH("pam_getenv", pamh, NULL);
303 pam_system_log(pamh, NULL, LOG_ERR,
304 "pam_getenv: no variable indicated");
308 if (pamh->env == NULL || pamh->env->list == NULL) {
309 pam_system_log(pamh, NULL, LOG_ERR, "pam_getenv: no env%s found",
310 pamh->env == NULL ? "":"-list" );
314 /* find the requested item */
316 item = _pam_search_env(pamh->env, name, strlen(name));
319 D(("env-item: %s, found!", name));
320 return (pamh->env->list[item] + 1 + strlen(name));
324 D(("env-item: %s, not found", name));
330 static char **_copy_env(pam_handle_t *pamh)
333 int i = pamh->env->requested; /* reckon size of environment */
334 char *const *env = pamh->env->list;
336 D(("now get some memory for dump"));
338 /* allocate some memory for this (plus the null tail-pointer) */
339 dump = (char **) calloc(i, sizeof(char *));
340 D(("dump = %p", dump));
345 /* now run through entries and copy the variables over */
348 D(("env[%d]=`%s'", i,env[i]));
349 dump[i] = _pam_strdup(env[i]);
350 D(("->dump[%d]=`%s'", i,dump[i]));
351 if (dump[i] == NULL) {
355 _pam_overwrite(dump[i]);
362 env = NULL; /* forget now */
364 /* return transcribed environment */
368 char **pam_getenvlist(pam_handle_t *pamh)
373 IF_NO_PAMH("pam_getenvlist", pamh, NULL);
375 if (pamh->env == NULL || pamh->env->list == NULL) {
376 pam_system_log(pamh, NULL, LOG_ERR,
377 "pam_getenvlist: no env%s found",
378 pamh->env == NULL ? "":"-list" );
382 /* some quick checks */
384 if (pamh->env->requested > pamh->env->entries) {
385 pam_system_log(pamh, NULL, LOG_ERR,
386 "pam_getenvlist: environment corruption");
387 _pam_dump_env(pamh); /* only active when debugging */
391 for (i=pamh->env->requested-1; i-- > 0; ) {
392 if (pamh->env->list[i] == NULL) {
393 pam_system_log(pamh, NULL, LOG_ERR,
394 "pam_getenvlist: environment broken");
395 _pam_dump_env(pamh); /* only active when debugging */
396 return NULL; /* somehow we've broken the environment!? */
400 /* Seems fine; copy environment */
402 _pam_dump_env(pamh); /* only active when debugging */
404 return _copy_env(pamh);