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