]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libpam/libpam/pam_env.c
This commit was generated by cvs2svn to compensate for changes in r56067,
[FreeBSD/FreeBSD.git] / contrib / libpam / libpam / pam_env.c
1 /*
2  * pam_env.c
3  *
4  * Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 1996,1997
5  * All rights reserved.
6  *
7  * This file was written from a "hint" provided by the people at SUN.
8  * and the X/Open XSSO draft of March 1997.
9  *
10  * $Id: pam_env.c,v 1.2 1997/02/15 15:56:48 morgan Exp morgan $
11  *
12  * $Log: pam_env.c,v $
13  * Revision 1.2  1997/02/15 15:56:48  morgan
14  * liberate pamh->env structure too!
15  *
16  * Revision 1.1  1996/12/01 03:14:13  morgan
17  * Initial revision
18  */
19
20 #include <string.h>
21 #include <stdlib.h>
22 #ifdef sunos
23 #define memmove(x,y,z) bcopy(y,x,z)
24 #endif
25
26 #include "pam_private.h"
27
28 /* helper functions */
29
30 #ifdef DEBUG
31 static void _pam_dump_env(pam_handle_t *pamh)
32 {
33     int i;
34
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));
39
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]);
43     }
44     _pam_output_debug("*NOTE* the last item should be (nil)");
45 }
46 #else
47 #define _pam_dump_env(x)
48 #endif
49
50 /*
51  * Create the environment
52  */
53
54 int _pam_make_env(pam_handle_t *pamh)
55 {
56     D(("called."));
57     IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT);
58
59     /*
60      * get structure memory
61      */
62
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");
66         return PAM_BUF_ERR;
67     }
68
69     /*
70      * get list memory
71      */
72
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");
77         _pam_drop(pamh->env);
78         return PAM_BUF_ERR;
79     }
80
81     /*
82      * fill entries in pamh->env
83      */
84     
85     pamh->env->entries = PAM_ENV_CHUNK;
86     pamh->env->requested = 1;
87     pamh->env->list[0] = NULL;
88
89     _pam_dump_env(pamh);                    /* only active when debugging */
90
91     return PAM_SUCCESS;
92 }
93
94 /*
95  * purge the environment
96  */
97
98 void _pam_drop_env(pam_handle_t *pamh)
99 {
100     D(("called."));
101     IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */);
102
103     if (pamh->env != NULL) {
104         int i;
105         /* we will only purge the pamh->env->requested number of elements */
106
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 */
111         }
112         pamh->env->requested = 0;
113         pamh->env->entries = 0;
114         _pam_drop(pamh->env->list);                     /* forget */
115         _pam_drop(pamh->env);                           /* forget */
116     } else {
117         D(("no environment present in pamh?"));
118     }
119 }
120
121 /*
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.
125  */
126
127 static int _pam_search_env(const struct pam_environ *env
128                            , const char *name_value, int length)
129 {
130     int i;
131
132     for (i=env->requested-1; i-- > 0; ) {
133         if (strncmp(name_value,env->list[i],length) == 0
134             && env->list[i][length] == '=') {
135
136             return i;                                   /* Got it! */
137
138         }
139     }
140
141     return -1;                                          /* no luck */
142 }
143
144 /*
145  * externally visible functions
146  */
147
148 /*
149  *  pam_putenv(): Add/replace/delete a PAM-environment variable.
150  *
151  *  Add/replace:
152  *      name_value = "NAME=VALUE" or "NAME=" (for empty value="\0")
153  *
154  *  delete:
155  *      name_value = "NAME"
156  */
157
158 int pam_putenv(pam_handle_t *pamh, const char *name_value)
159 {
160     int l2eq, item, retval;
161
162     D(("called."));
163     IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT);
164
165     if (name_value == NULL) {
166         pam_system_log(pamh, NULL, LOG_ERR,
167                        "pam_putenv: no variable indicated");
168         return PAM_PERM_DENIED;
169     }
170
171     /*
172      * establish if we are setting or deleting; scan for '='
173      */
174
175     for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq);
176     if (l2eq <= 0) {
177         pam_system_log(pamh, NULL, LOG_ERR, "pam_putenv: bad variable");
178         return PAM_BAD_ITEM;
179     }
180
181     /*
182      *  Look first for environment.
183      */
184
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");
188         return PAM_ABORT;
189     }
190
191     /* find the item to replace */
192
193     item = _pam_search_env(pamh->env, name_value, l2eq);
194
195     if (name_value[l2eq]) {                     /* (re)setting */
196
197         if (item == -1) {                      /* new variable */
198             D(("adding item: %s", name_value));
199             /* enough space? */
200             if (pamh->env->entries <= pamh->env->requested) {
201                 register int i;
202                 register char **tmp;
203
204                 /* get some new space */
205                 tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK
206                                      , sizeof(char *) );
207                 if (tmp == NULL) {
208                     /* nothing has changed - old env intact */
209                     pam_system_log(pamh, NULL, LOG_CRIT,
210                                    "pam_putenv: cannot grow environment");
211                     return PAM_BUF_ERR;
212                 }
213
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;
218                 }
219
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;
224
225                 D(("resized env list"));
226                 _pam_dump_env(pamh);              /* only when debugging */
227             }
228
229             item = pamh->env->requested-1;        /* old last item (NULL) */
230
231             /* add a new NULL entry at end; increase counter */
232             pamh->env->list[pamh->env->requested++] = NULL;
233             
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]);
239         }
240
241         /*
242          * now we have a place to put the new env-item, insert at 'item'
243          */
244
245         pamh->env->list[item] = _pam_strdup(name_value);
246         if (pamh->env->list[item] != NULL) {
247             _pam_dump_env(pamh);                   /* only when debugging */
248             return PAM_SUCCESS;
249         }
250
251         /* something went wrong; we should delete the item - fall through */
252
253         retval = PAM_BUF_ERR;                        /* an error occurred */
254     } else {
255         retval = PAM_SUCCESS;                      /* we requested delete */
256     }
257
258     /* getting to here implies we are deleting an item */
259
260     if (item < 0) {
261         pam_system_log(pamh, NULL, LOG_ERR,
262                        "pam_putenv: delete non-existent entry; %s",
263                        name_value);
264         return PAM_BAD_ITEM;
265     }
266
267     /*
268      * remove item: purge memory; reset counter; resize [; display-env]
269      */
270
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 *) );
279
280     _pam_dump_env(pamh);                   /* only when debugging */
281
282     /*
283      * deleted.
284      */
285
286     return retval;
287 }
288
289 /*
290  *  Return the value of the requested environment variable
291  */
292
293 const char *pam_getenv(pam_handle_t *pamh, const char *name)
294 {
295     int item;
296
297     D(("called."));
298     IF_NO_PAMH("pam_getenv", pamh, NULL);
299
300     if (name == NULL) {
301         pam_system_log(pamh, NULL, LOG_ERR,
302                        "pam_getenv: no variable indicated");
303         return NULL;
304     }
305
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" );
309         return NULL;
310     }
311
312     /* find the requested item */
313
314     item = _pam_search_env(pamh->env, name, strlen(name));
315     if (item != -1) {
316
317         D(("env-item: %s, found!", name));
318         return (pamh->env->list[item] + 1 + strlen(name));
319
320     } else {
321
322         D(("env-item: %s, not found", name));
323         return NULL;
324
325     }
326 }
327
328 static char **_copy_env(pam_handle_t *pamh)
329 {
330     char **dump;
331     int i = pamh->env->requested;          /* reckon size of environment */
332     char *const *env = pamh->env->list;
333
334     D(("now get some memory for dump"));
335
336     /* allocate some memory for this (plus the null tail-pointer) */
337     dump = (char **) calloc(i, sizeof(char *));
338     D(("dump = %p", dump));
339     if (dump == NULL) {
340         return NULL;
341     }
342
343     /* now run through entries and copy the variables over */
344     dump[--i] = NULL;
345     while (i-- > 0) {
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) {
350             /* out of memory */
351
352             while (dump[++i]) {
353                 _pam_overwrite(dump[i]);
354                 _pam_drop(dump[i]);
355             }
356             return NULL;
357         }
358     }
359
360     env = NULL;                             /* forget now */
361
362     /* return transcribed environment */
363     return dump;
364 }
365
366 char **pam_getenvlist(pam_handle_t *pamh)
367 {
368     int i;
369
370     D(("called."));
371     IF_NO_PAMH("pam_getenvlist", pamh, NULL);
372
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" );
377         return NULL;
378     }
379
380     /* some quick checks */
381
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 */
386         return NULL;
387     }
388
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!? */
395         }
396     }
397
398     /* Seems fine; copy environment */
399
400     _pam_dump_env(pamh);                    /* only active when debugging */
401
402     return _copy_env(pamh);
403 }