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 $
13 * Revision 1.2 1997/02/15 15:56:48 morgan
14 * liberate pamh->env structure too!
16 * Revision 1.1 1996/12/01 03:14:13 morgan
23 #define memmove(x,y,z) bcopy(y,x,z)
26 #include "pam_private.h"
28 /* helper functions */
31 static void _pam_dump_env(pam_handle_t *pamh)
35 D(("Listing environment of pamh=%p", pamh));
36 D(("pamh->env = %p", pamh->env));
37 D(("environment entries used = %d [of %d allocated]"
38 , pamh->env->requested, pamh->env->entries));
40 for (i=0; i<pamh->env->requested; ++i) {
41 _pam_output_debug(">%-3d [%9p]:[%s]"
42 , i, pamh->env->list[i], pamh->env->list[i]);
44 _pam_output_debug("*NOTE* the last item should be (nil)");
47 #define _pam_dump_env(x)
51 * Create the environment
54 int _pam_make_env(pam_handle_t *pamh)
57 IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT);
60 * get structure memory
63 pamh->env = (struct pam_environ *) malloc(sizeof(struct pam_environ));
64 if (pamh->env == NULL) {
65 pam_system_log(pamh, NULL, LOG_CRIT, "_pam_make_env: out of memory");
73 pamh->env->list = (char **)calloc( PAM_ENV_CHUNK, sizeof(char *) );
74 if (pamh->env->list == NULL) {
75 pam_system_log(pamh, NULL, LOG_CRIT,
76 "_pam_make_env: no memory for list");
82 * fill entries in pamh->env
85 pamh->env->entries = PAM_ENV_CHUNK;
86 pamh->env->requested = 1;
87 pamh->env->list[0] = NULL;
89 _pam_dump_env(pamh); /* only active when debugging */
95 * purge the environment
98 void _pam_drop_env(pam_handle_t *pamh)
101 IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */);
103 if (pamh->env != NULL) {
105 /* we will only purge the pamh->env->requested number of elements */
107 for (i=pamh->env->requested-1; i-- > 0; ) {
108 D(("dropping #%3d>%s<", i, pamh->env->list[i]));
109 _pam_overwrite(pamh->env->list[i]); /* clean */
110 _pam_drop(pamh->env->list[i]); /* forget */
112 pamh->env->requested = 0;
113 pamh->env->entries = 0;
114 _pam_drop(pamh->env->list); /* forget */
115 _pam_drop(pamh->env); /* forget */
117 D(("no environment present in pamh?"));
122 * Return the item number of the given variable = first 'length' chars
123 * of 'name_value'. Since this is a static function, it is safe to
124 * assume its supplied arguments are well defined.
127 static int _pam_search_env(const struct pam_environ *env
128 , const char *name_value, int length)
132 for (i=env->requested-1; i-- > 0; ) {
133 if (strncmp(name_value,env->list[i],length) == 0
134 && env->list[i][length] == '=') {
136 return i; /* Got it! */
141 return -1; /* no luck */
145 * externally visible functions
149 * pam_putenv(): Add/replace/delete a PAM-environment variable.
152 * name_value = "NAME=VALUE" or "NAME=" (for empty value="\0")
155 * name_value = "NAME"
158 int pam_putenv(pam_handle_t *pamh, const char *name_value)
160 int l2eq, item, retval;
163 IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT);
165 if (name_value == NULL) {
166 pam_system_log(pamh, NULL, LOG_ERR,
167 "pam_putenv: no variable indicated");
168 return PAM_PERM_DENIED;
172 * establish if we are setting or deleting; scan for '='
175 for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq);
177 pam_system_log(pamh, NULL, LOG_ERR, "pam_putenv: bad variable");
182 * Look first for environment.
185 if (pamh->env == NULL || pamh->env->list == NULL) {
186 pam_system_log(pamh, NULL, LOG_ERR, "pam_putenv: no env%s found"
187 , pamh->env == NULL ? "":"-list");
191 /* find the item to replace */
193 item = _pam_search_env(pamh->env, name_value, l2eq);
195 if (name_value[l2eq]) { /* (re)setting */
197 if (item == -1) { /* new variable */
198 D(("adding item: %s", name_value));
200 if (pamh->env->entries <= pamh->env->requested) {
204 /* get some new space */
205 tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK
208 /* nothing has changed - old env intact */
209 pam_system_log(pamh, NULL, LOG_CRIT,
210 "pam_putenv: cannot grow environment");
214 /* copy old env-item pointers/forget old */
215 for (i=0; i<pamh->env->requested; ++i) {
216 tmp[i] = pamh->env->list[i];
217 pamh->env->list[i] = NULL;
220 /* drop old list and replace with new */
221 _pam_drop(pamh->env->list);
222 pamh->env->list = tmp;
223 pamh->env->entries += PAM_ENV_CHUNK;
225 D(("resized env list"));
226 _pam_dump_env(pamh); /* only when debugging */
229 item = pamh->env->requested-1; /* old last item (NULL) */
231 /* add a new NULL entry at end; increase counter */
232 pamh->env->list[pamh->env->requested++] = NULL;
234 } else { /* replace old */
235 D(("replacing item: %s\n with: %s"
236 , pamh->env->list[item], name_value));
237 _pam_overwrite(pamh->env->list[item]);
238 _pam_drop(pamh->env->list[item]);
242 * now we have a place to put the new env-item, insert at 'item'
245 pamh->env->list[item] = _pam_strdup(name_value);
246 if (pamh->env->list[item] != NULL) {
247 _pam_dump_env(pamh); /* only when debugging */
251 /* something went wrong; we should delete the item - fall through */
253 retval = PAM_BUF_ERR; /* an error occurred */
255 retval = PAM_SUCCESS; /* we requested delete */
258 /* getting to here implies we are deleting an item */
261 pam_system_log(pamh, NULL, LOG_ERR,
262 "pam_putenv: delete non-existent entry; %s",
268 * remove item: purge memory; reset counter; resize [; display-env]
271 D(("deleting: env#%3d:[%s]", item, pamh->env->list[item]));
272 _pam_overwrite(pamh->env->list[item]);
273 _pam_drop(pamh->env->list[item]);
274 --(pamh->env->requested);
275 D(("mmove: item[%d]+%d -> item[%d]"
276 , item+1, ( pamh->env->requested - item ), item));
277 (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1]
278 , ( pamh->env->requested - item )*sizeof(char *) );
280 _pam_dump_env(pamh); /* only when debugging */
290 * Return the value of the requested environment variable
293 const char *pam_getenv(pam_handle_t *pamh, const char *name)
298 IF_NO_PAMH("pam_getenv", pamh, NULL);
301 pam_system_log(pamh, NULL, LOG_ERR,
302 "pam_getenv: no variable indicated");
306 if (pamh->env == NULL || pamh->env->list == NULL) {
307 pam_system_log(pamh, NULL, LOG_ERR, "pam_getenv: no env%s found",
308 pamh->env == NULL ? "":"-list" );
312 /* find the requested item */
314 item = _pam_search_env(pamh->env, name, strlen(name));
317 D(("env-item: %s, found!", name));
318 return (pamh->env->list[item] + 1 + strlen(name));
322 D(("env-item: %s, not found", name));
328 static char **_copy_env(pam_handle_t *pamh)
331 int i = pamh->env->requested; /* reckon size of environment */
332 char *const *env = pamh->env->list;
334 D(("now get some memory for dump"));
336 /* allocate some memory for this (plus the null tail-pointer) */
337 dump = (char **) calloc(i, sizeof(char *));
338 D(("dump = %p", dump));
343 /* now run through entries and copy the variables over */
346 D(("env[%d]=`%s'", i,env[i]));
347 dump[i] = _pam_strdup(env[i]);
348 D(("->dump[%d]=`%s'", i,dump[i]));
349 if (dump[i] == NULL) {
353 _pam_overwrite(dump[i]);
360 env = NULL; /* forget now */
362 /* return transcribed environment */
366 char **pam_getenvlist(pam_handle_t *pamh)
371 IF_NO_PAMH("pam_getenvlist", pamh, NULL);
373 if (pamh->env == NULL || pamh->env->list == NULL) {
374 pam_system_log(pamh, NULL, LOG_ERR,
375 "pam_getenvlist: no env%s found",
376 pamh->env == NULL ? "":"-list" );
380 /* some quick checks */
382 if (pamh->env->requested > pamh->env->entries) {
383 pam_system_log(pamh, NULL, LOG_ERR,
384 "pam_getenvlist: environment corruption");
385 _pam_dump_env(pamh); /* only active when debugging */
389 for (i=pamh->env->requested-1; i-- > 0; ) {
390 if (pamh->env->list[i] == NULL) {
391 pam_system_log(pamh, NULL, LOG_ERR,
392 "pam_getenvlist: environment broken");
393 _pam_dump_env(pamh); /* only active when debugging */
394 return NULL; /* somehow we've broken the environment!? */
398 /* Seems fine; copy environment */
400 _pam_dump_env(pamh); /* only active when debugging */
402 return _copy_env(pamh);