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.
16 #define memmove(x,y,z) bcopy(y,x,z)
19 #include "pam_private.h"
21 /* helper functions */
24 static void _pam_dump_env(pam_handle_t *pamh)
28 D(("Listing environment of pamh=%p", pamh));
29 D(("pamh->env = %p", pamh->env));
30 D(("environment entries used = %d [of %d allocated]"
31 , pamh->env->requested, pamh->env->entries));
33 for (i=0; i<pamh->env->requested; ++i) {
34 _pam_output_debug(">%-3d [%9p]:[%s]"
35 , i, pamh->env->list[i], pamh->env->list[i]);
37 _pam_output_debug("*NOTE* the last item should be (nil)");
40 #define _pam_dump_env(x)
44 * Create the environment
47 int _pam_make_env(pam_handle_t *pamh)
51 IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT);
54 * get structure memory
57 pamh->env = (struct pam_environ *) malloc(sizeof(struct pam_environ));
58 if (pamh->env == NULL) {
59 _pam_system_log(LOG_CRIT, "_pam_make_env: out of memory");
67 pamh->env->list = (char **)calloc( PAM_ENV_CHUNK, sizeof(char *) );
68 if (pamh->env->list == NULL) {
69 _pam_system_log(LOG_CRIT, "_pam_make_env: no memory for list");
75 * fill entries in pamh->env
78 pamh->env->entries = PAM_ENV_CHUNK;
79 pamh->env->requested = 1;
80 pamh->env->list[0] = NULL;
82 _pam_dump_env(pamh); /* only active when debugging */
88 * purge the environment
91 void _pam_drop_env(pam_handle_t *pamh)
94 IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */);
96 if (pamh->env != NULL) {
98 /* we will only purge the pamh->env->requested number of elements */
100 for (i=pamh->env->requested-1; i-- > 0; ) {
101 D(("dropping #%3d>%s<", i, pamh->env->list[i]));
102 _pam_overwrite(pamh->env->list[i]); /* clean */
103 _pam_drop(pamh->env->list[i]); /* forget */
105 pamh->env->requested = 0;
106 pamh->env->entries = 0;
107 _pam_drop(pamh->env->list); /* forget */
108 _pam_drop(pamh->env); /* forget */
110 D(("no environment present in pamh?"));
115 * Return the item number of the given variable = first 'length' chars
116 * of 'name_value'. Since this is a static function, it is safe to
117 * assume its supplied arguments are well defined.
120 static int _pam_search_env(const struct pam_environ *env
121 , const char *name_value, int length)
125 for (i=env->requested-1; i-- > 0; ) {
126 if (strncmp(name_value,env->list[i],length) == 0
127 && env->list[i][length] == '=') {
129 return i; /* Got it! */
134 return -1; /* no luck */
138 * externally visible functions
142 * pam_putenv(): Add/replace/delete a PAM-environment variable.
145 * name_value = "NAME=VALUE" or "NAME=" (for empty value="\0")
148 * name_value = "NAME"
151 int pam_putenv(pam_handle_t *pamh, const char *name_value)
153 int l2eq, item, retval;
156 IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT);
158 if (name_value == NULL) {
159 _pam_system_log(LOG_ERR, "pam_putenv: no variable indicated");
160 return PAM_PERM_DENIED;
164 * establish if we are setting or deleting; scan for '='
167 for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq);
169 _pam_system_log(LOG_ERR, "pam_putenv: bad variable");
174 * Look first for environment.
177 if (pamh->env == NULL || pamh->env->list == NULL) {
178 _pam_system_log(LOG_ERR, "pam_putenv: no env%s found",
179 pamh->env == NULL ? "":"-list");
183 /* find the item to replace */
185 item = _pam_search_env(pamh->env, name_value, l2eq);
187 if (name_value[l2eq]) { /* (re)setting */
189 if (item == -1) { /* new variable */
190 D(("adding item: %s", name_value));
192 if (pamh->env->entries <= pamh->env->requested) {
196 /* get some new space */
197 tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK
200 /* nothing has changed - old env intact */
201 _pam_system_log(LOG_CRIT,
202 "pam_putenv: cannot grow environment");
206 /* copy old env-item pointers/forget old */
207 for (i=0; i<pamh->env->requested; ++i) {
208 tmp[i] = pamh->env->list[i];
209 pamh->env->list[i] = NULL;
212 /* drop old list and replace with new */
213 _pam_drop(pamh->env->list);
214 pamh->env->list = tmp;
215 pamh->env->entries += PAM_ENV_CHUNK;
217 D(("resized env list"));
218 _pam_dump_env(pamh); /* only when debugging */
221 item = pamh->env->requested-1; /* old last item (NULL) */
223 /* add a new NULL entry at end; increase counter */
224 pamh->env->list[pamh->env->requested++] = NULL;
226 } else { /* replace old */
227 D(("replacing item: %s\n with: %s"
228 , pamh->env->list[item], name_value));
229 _pam_overwrite(pamh->env->list[item]);
230 _pam_drop(pamh->env->list[item]);
234 * now we have a place to put the new env-item, insert at 'item'
237 pamh->env->list[item] = _pam_strdup(name_value);
238 if (pamh->env->list[item] != NULL) {
239 _pam_dump_env(pamh); /* only when debugging */
243 /* something went wrong; we should delete the item - fall through */
245 retval = PAM_BUF_ERR; /* an error occurred */
247 retval = PAM_SUCCESS; /* we requested delete */
250 /* getting to here implies we are deleting an item */
253 _pam_system_log(LOG_ERR, "pam_putenv: delete non-existent entry; %s",
259 * remove item: purge memory; reset counter; resize [; display-env]
262 D(("deleting: env#%3d:[%s]", item, pamh->env->list[item]));
263 _pam_overwrite(pamh->env->list[item]);
264 _pam_drop(pamh->env->list[item]);
265 --(pamh->env->requested);
266 D(("mmove: item[%d]+%d -> item[%d]"
267 , item+1, ( pamh->env->requested - item ), item));
268 (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1]
269 , ( pamh->env->requested - item )*sizeof(char *) );
271 _pam_dump_env(pamh); /* only when debugging */
281 * Return the value of the requested environment variable
284 const char *pam_getenv(pam_handle_t *pamh, const char *name)
289 IF_NO_PAMH("pam_getenv", pamh, NULL);
292 _pam_system_log(LOG_ERR, "pam_getenv: no variable indicated");
296 if (pamh->env == NULL || pamh->env->list == NULL) {
297 _pam_system_log(LOG_ERR, "pam_getenv: no env%s found",
298 pamh->env == NULL ? "":"-list" );
302 /* find the requested item */
304 item = _pam_search_env(pamh->env, name, strlen(name));
307 D(("env-item: %s, found!", name));
308 return (pamh->env->list[item] + 1 + strlen(name));
312 D(("env-item: %s, not found", name));
318 static char **_copy_env(pam_handle_t *pamh)
321 int i = pamh->env->requested; /* reckon size of environment */
322 char *const *env = pamh->env->list;
324 D(("now get some memory for dump"));
326 /* allocate some memory for this (plus the null tail-pointer) */
327 dump = (char **) calloc(i, sizeof(char *));
328 D(("dump = %p", dump));
333 /* now run through entries and copy the variables over */
336 D(("env[%d]=`%s'", i,env[i]));
337 dump[i] = _pam_strdup(env[i]);
338 D(("->dump[%d]=`%s'", i,dump[i]));
339 if (dump[i] == NULL) {
343 _pam_overwrite(dump[i]);
350 env = NULL; /* forget now */
352 /* return transcribed environment */
356 char **pam_getenvlist(pam_handle_t *pamh)
361 IF_NO_PAMH("pam_getenvlist", pamh, NULL);
363 if (pamh->env == NULL || pamh->env->list == NULL) {
364 _pam_system_log(LOG_ERR, "pam_getenvlist: no env%s found",
365 pamh->env == NULL ? "":"-list" );
369 /* some quick checks */
371 if (pamh->env->requested > pamh->env->entries) {
372 _pam_system_log(LOG_ERR, "pam_getenvlist: environment corruption");
373 _pam_dump_env(pamh); /* only active when debugging */
377 for (i=pamh->env->requested-1; i-- > 0; ) {
378 if (pamh->env->list[i] == NULL) {
379 _pam_system_log(LOG_ERR, "pam_getenvlist: environment broken");
380 _pam_dump_env(pamh); /* only active when debugging */
381 return NULL; /* somehow we've broken the environment!? */
385 /* Seems fine; copy environment */
387 _pam_dump_env(pamh); /* only active when debugging */
389 return _copy_env(pamh);