~ubuntu-branches/ubuntu/breezy/pam/breezy

« back to all changes in this revision

Viewing changes to Linux-PAM/libpam/pam_handlers.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2004-06-28 14:28:08 UTC
  • mfrom: (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20040628142808-adikk7vtfg3pzcjw
Tags: 0.76-22
* Add uploaders
* Document location of repository
* Fix options containing arguments in pam_unix, Closes: #254904

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* pam_handlers.c -- pam config file parsing and module loading */
 
2
 
 
3
/*
 
4
 * created by Marc Ewing.
 
5
 * Currently maintained by Andrew G. Morgan <morgan@kernel.org>
 
6
 *
 
7
 * $Id: pam_handlers.c,v 1.2 2002/10/06 21:50:48 hartmans Exp $
 
8
 *
 
9
 */
 
10
 
 
11
#include <stdlib.h>
 
12
#include <stdio.h>
 
13
#include <string.h>
 
14
#include <sys/types.h>
 
15
#include <sys/stat.h>
 
16
#include <fcntl.h>
 
17
#include <unistd.h>
 
18
 
 
19
#ifdef PAM_DYNAMIC
 
20
# ifdef PAM_SHL
 
21
#  include <dl.h>
 
22
# else /* PAM_SHL */
 
23
#  include <dlfcn.h>
 
24
# endif /* PAM_SHL */
 
25
#endif /* PAM_DYNAMIC */
 
26
 
 
27
#include "pam_private.h"
 
28
 
 
29
/* If not required, define as nothing */
 
30
#ifndef SHLIB_SYM_PREFIX
 
31
# define SHLIB_SYM_PREFIX ""
 
32
#endif
 
33
 
 
34
#define BUF_SIZE                  1024
 
35
#define MODULE_CHUNK              4
 
36
#define UNKNOWN_MODULE_PATH       "<*unknown module path*>"
 
37
 
 
38
static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
 
39
 
 
40
static void _pam_free_handlers_aux(struct handler **hp);
 
41
 
 
42
static int _pam_add_handler(pam_handle_t *pamh
 
43
                     , int must_fail, int other, int type
 
44
                     , int *actions, const char *mod_path
 
45
                     , int argc, char **argv, int argvlen);
 
46
 
 
47
/* Values for module type */
 
48
 
 
49
#define PAM_T_AUTH    1
 
50
#define PAM_T_SESS    2
 
51
#define PAM_T_ACCT    4
 
52
#define PAM_T_PASS    8
 
53
 
 
54
static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
 
55
                                , const char *known_service /* specific file */
 
56
#ifdef PAM_READ_BOTH_CONFS
 
57
                                , int not_other
 
58
#endif /* PAM_READ_BOTH_CONFS */
 
59
    )
 
60
{
 
61
    char buf[BUF_SIZE];
 
62
    int x;                    /* read a line from the FILE *f ? */
 
63
    /*
 
64
     * read a line from the configuration (FILE *) f
 
65
     */
 
66
    while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) {
 
67
        char *tok, *nexttok=NULL;
 
68
        const char *this_service;
 
69
        const char *mod_path;
 
70
        int module_type, actions[_PAM_RETURN_VALUES];
 
71
        int other;            /* set if module is for PAM_DEFAULT_SERVICE */
 
72
        int res;              /* module added successfully? */
 
73
        int must_fail=0;      /* a badly formatted line must fail when used */
 
74
        int argc;
 
75
        char **argv;
 
76
        int argvlen;
 
77
 
 
78
        D(("_pam_init_handler: LINE: %s", buf));
 
79
        if (known_service != NULL) {
 
80
            nexttok = buf;
 
81
            /* No service field: all lines are for the known service. */
 
82
            this_service = known_service;
 
83
        } else {
 
84
            this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok);
 
85
        }
 
86
 
 
87
#ifdef PAM_READ_BOTH_CONFS
 
88
        if (not_other)
 
89
            other = 0;
 
90
        else
 
91
#endif /* PAM_READ_BOTH_CONFS */
 
92
        other = !_pam_strCMP(this_service, PAM_DEFAULT_SERVICE);
 
93
 
 
94
        /* accept "service name" or PAM_DEFAULT_SERVICE modules */
 
95
        if (!_pam_strCMP(this_service, pamh->service_name) || other) {
 
96
            /* This is a service we are looking for */
 
97
            D(("_pam_init_handlers: Found PAM config entry for: %s"
 
98
               , this_service));
 
99
 
 
100
            tok = _pam_StrTok(NULL, " \n\t", &nexttok);
 
101
            if (!_pam_strCMP("auth", tok)) {
 
102
                module_type = PAM_T_AUTH;
 
103
            } else if (!_pam_strCMP("session", tok)) {
 
104
                module_type = PAM_T_SESS;
 
105
            } else if (!_pam_strCMP("account", tok)) {
 
106
                module_type = PAM_T_ACCT;
 
107
            } else if (!_pam_strCMP("password", tok)) {
 
108
                module_type = PAM_T_PASS;
 
109
            } else if (!_pam_strCMP("@include", tok)) {
 
110
                /* include a file here
 
111
                 * most of the code adapted from _pam_init_handlers */
 
112
                FILE *inc_f;
 
113
                int retval;
 
114
                int drop_f = 1;
 
115
 
 
116
                tok = _pam_StrTok(NULL, " \n\t", &nexttok);
 
117
                if (tok == NULL) {
 
118
                        D(("_pam_parse_conf_file: included file name not given"));
 
119
                        _pam_system_log(LOG_ERR,
 
120
                                "(%s) included file name not given",
 
121
                                this_service);
 
122
                } else {
 
123
                        char *filename;
 
124
                        struct stat test_d;
 
125
 
 
126
                        if (!_pam_strCMP("/", tok)) {
 
127
                                filename = tok;
 
128
                                drop_f = 0;
 
129
                        } else if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
 
130
                                D(("searching " PAM_CONFIG_D " for included file"));
 
131
                                filename = malloc(sizeof(PAM_CONFIG_DF)
 
132
                                                +strlen(tok));
 
133
                                if (filename == NULL) {
 
134
                                        _pam_system_log(LOG_ERR,
 
135
                                                "_pam_parse_conf_file: no memory; service %s",
 
136
                                                this_service);
 
137
                                        return PAM_BUF_ERR;
 
138
                                }
 
139
                                sprintf(filename, PAM_CONFIG_DF, tok);
 
140
                        }
 
141
                        D(("opening %s", filename));
 
142
                        inc_f = fopen(filename, "r");
 
143
                        if (inc_f != NULL) {
 
144
                                retval = _pam_parse_conf_file(pamh, inc_f, known_service
 
145
#ifdef PAM_READ_BOTH_CONFS
 
146
                                                              , not_other
 
147
#endif /* PAM_READ_BOTH_CONFS */
 
148
                                         );
 
149
                                fclose(inc_f);
 
150
                                if (retval != PAM_SUCCESS) {
 
151
                                    _pam_system_log(LOG_ERR,
 
152
                                            "_pam_parse_conf_file: error reading %s",
 
153
                                            filename);
 
154
                                    _pam_system_log(LOG_ERR, "_pam_parse_conf_file: [%s]",
 
155
                                            pam_strerror(pamh, retval));
 
156
                                    return retval;
 
157
                                }
 
158
                        }
 
159
                        if (drop_f)
 
160
                                _pam_drop(filename);
 
161
                }
 
162
                /* skip dealing with the module; and go to the next line */
 
163
                goto end;
 
164
            } else {
 
165
                /* Illegal module type */
 
166
                D(("_pam_init_handlers: bad module type: %s", tok));
 
167
                _pam_system_log(LOG_ERR, "(%s) illegal module type: %s",
 
168
                                this_service, tok);
 
169
                module_type = PAM_T_AUTH;                  /* most sensitive */
 
170
                must_fail = 1; /* install as normal but fail when dispatched */
 
171
            }
 
172
            D(("Using %s config entry: %s", must_fail?"BAD ":"", tok));
 
173
 
 
174
            /* reset the actions to .._UNDEF's -- this is so that
 
175
               we can work out which entries are not yet set (for default). */
 
176
            {
 
177
                int i;
 
178
                for (i=0; i<_PAM_RETURN_VALUES;
 
179
                     actions[i++] = _PAM_ACTION_UNDEF);
 
180
            }
 
181
            tok = _pam_StrTok(NULL, " \n\t", &nexttok);
 
182
            if (!_pam_strCMP("required", tok)) {
 
183
                D(("*PAM_F_REQUIRED*"));
 
184
                actions[PAM_SUCCESS] = _PAM_ACTION_OK;
 
185
                actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
 
186
                actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
 
187
                _pam_set_default_control(actions, _PAM_ACTION_BAD);
 
188
            } else if (!_pam_strCMP("requisite", tok)) {
 
189
                D(("*PAM_F_REQUISITE*"));
 
190
                actions[PAM_SUCCESS] = _PAM_ACTION_OK;
 
191
                actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
 
192
                actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
 
193
                _pam_set_default_control(actions, _PAM_ACTION_DIE);
 
194
            } else if (!_pam_strCMP("optional", tok)) {
 
195
                D(("*PAM_F_OPTIONAL*"));
 
196
                actions[PAM_SUCCESS] = _PAM_ACTION_OK;
 
197
                actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
 
198
                _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
 
199
            } else if (!_pam_strCMP("sufficient", tok)) {
 
200
                D(("*PAM_F_SUFFICIENT*"));
 
201
                actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
 
202
                actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
 
203
                _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
 
204
            } else {
 
205
                D(("will need to parse %s", tok));
 
206
                _pam_parse_control(actions, tok);
 
207
                /* by default the default is to treat as failure */
 
208
                _pam_set_default_control(actions, _PAM_ACTION_BAD);
 
209
            }
 
210
 
 
211
            tok = _pam_StrTok(NULL, " \n\t", &nexttok);
 
212
            if (tok != NULL) {
 
213
                mod_path = tok;
 
214
                D(("mod_path = %s",mod_path));
 
215
            } else {
 
216
                /* no module name given */
 
217
                D(("_pam_init_handlers: no module name supplied"));
 
218
                _pam_system_log(LOG_ERR,
 
219
                                "(%s) no module name supplied", this_service);
 
220
                mod_path = NULL;
 
221
                must_fail = 1;
 
222
            }
 
223
 
 
224
            /* nexttok points to remaining arguments... */
 
225
 
 
226
            if (nexttok != NULL) {
 
227
                D(("list: %s",nexttok));
 
228
                argvlen = _pam_mkargv(nexttok, &argv, &argc);
 
229
                D(("argvlen = %d",argvlen));
 
230
            } else {               /* there are no arguments so fix by hand */
 
231
                D(("_pam_init_handlers: empty argument list"));
 
232
                argvlen = argc = 0;
 
233
                argv = NULL;
 
234
            }
 
235
 
 
236
#ifdef DEBUG
 
237
            {
 
238
                int y;
 
239
 
 
240
                D(("CONF%s: %s%s %d %s %d"
 
241
                   , must_fail?"<*will fail*>":""
 
242
                   , this_service, other ? "(backup)":""
 
243
                   , module_type
 
244
                   , mod_path, argc));
 
245
                for (y = 0; y < argc; y++) {
 
246
                    D(("CONF: %s", argv[y]));
 
247
                }
 
248
                for (y = 0; y<_PAM_RETURN_VALUES; ++y) {
 
249
                    D(("RETURN %s(%d) -> %d %s",
 
250
                       _pam_token_returns[y], y, actions[y],
 
251
                       actions[y]>0 ? "jump":
 
252
                        _pam_token_actions[-actions[y]]));
 
253
                }
 
254
            }
 
255
#endif
 
256
 
 
257
            res = _pam_add_handler(pamh, must_fail, other
 
258
                                   , module_type, actions, mod_path
 
259
                                   , argc, argv, argvlen);
 
260
            if (res != PAM_SUCCESS) {
 
261
                _pam_system_log(LOG_ERR, "error loading %s", mod_path);
 
262
                D(("failed to load module - aborting"));
 
263
                return PAM_ABORT;
 
264
            }
 
265
        }
 
266
end:
 
267
    }
 
268
 
 
269
    return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
 
270
}
 
271
 
 
272
/* Parse config file, allocate handler structures, dlopen() */
 
273
int _pam_init_handlers(pam_handle_t *pamh)
 
274
{
 
275
    FILE *f;
 
276
    int retval;
 
277
 
 
278
    D(("_pam_init_handlers called"));
 
279
    IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
 
280
 
 
281
    /* Return immediately if everything is already loaded */
 
282
    if (pamh->handlers.handlers_loaded) {
 
283
        return PAM_SUCCESS;
 
284
    }
 
285
 
 
286
    D(("_pam_init_handlers: initializing"));
 
287
    
 
288
    /* First clean the service structure */
 
289
 
 
290
    _pam_free_handlers(pamh);
 
291
    if (! pamh->handlers.module) {
 
292
        if ((pamh->handlers.module =
 
293
             malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
 
294
            _pam_system_log(LOG_CRIT,
 
295
                            "_pam_init_handlers: no memory loading module");
 
296
            return PAM_BUF_ERR;
 
297
        }
 
298
        pamh->handlers.modules_allocated = MODULE_CHUNK;
 
299
        pamh->handlers.modules_used = 0;
 
300
    }
 
301
 
 
302
    if (pamh->service_name == NULL) {
 
303
        return PAM_BAD_ITEM;                /* XXX - better error? */
 
304
    }
 
305
 
 
306
#ifdef PAM_LOCKING
 
307
    /* Is the PAM subsystem locked? */
 
308
    {
 
309
         int fd_tmp;
 
310
 
 
311
         if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
 
312
             _pam_system_log(LOG_ERR, "_pam_init_handlers: PAM lockfile ("
 
313
                             PAM_LOCK_FILE ") exists - aborting");
 
314
              (void) close(fd_tmp);
 
315
              /*
 
316
               * to avoid swamping the system with requests
 
317
               */
 
318
              _pam_start_timer(pamh);
 
319
              pam_fail_delay(pamh, 5000000);
 
320
              _pam_await_timer(pamh, PAM_ABORT);
 
321
 
 
322
              return PAM_ABORT;
 
323
         }
 
324
    }
 
325
#endif /* PAM_LOCKING */
 
326
 
 
327
    /*
 
328
     * Now parse the config file(s) and add handlers
 
329
     */
 
330
    {
 
331
        struct stat test_d;
 
332
        
 
333
        /* Is there a PAM_CONFIG_D directory? */
 
334
        if ( stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode) ) {
 
335
            char *filename;
 
336
            int read_something=0;
 
337
 
 
338
            D(("searching " PAM_CONFIG_D " for config files"));
 
339
            filename = malloc(sizeof(PAM_CONFIG_DF)
 
340
                              +strlen(pamh->service_name));
 
341
            if (filename == NULL) {
 
342
                _pam_system_log(LOG_ERR,
 
343
                                "_pam_init_handlers: no memory; service %s",
 
344
                                pamh->service_name);
 
345
                return PAM_BUF_ERR;
 
346
            }
 
347
            sprintf(filename, PAM_CONFIG_DF, pamh->service_name);
 
348
            D(("opening %s", filename));
 
349
            f = fopen(filename, "r");
 
350
            if (f != NULL) {
 
351
                /* would test magic here? */
 
352
                retval = _pam_parse_conf_file(pamh, f, pamh->service_name
 
353
#ifdef PAM_READ_BOTH_CONFS
 
354
                                              , 0
 
355
#endif /* PAM_READ_BOTH_CONFS */
 
356
                    );
 
357
                fclose(f);
 
358
                if (retval != PAM_SUCCESS) {
 
359
                    _pam_system_log(LOG_ERR,
 
360
                                    "_pam_init_handlers: error reading %s",
 
361
                                    filename);
 
362
                    _pam_system_log(LOG_ERR, "_pam_init_handlers: [%s]",
 
363
                                    pam_strerror(pamh, retval));
 
364
                } else {
 
365
                    read_something = 1;
 
366
                }
 
367
            } else {
 
368
                D(("unable to open %s", filename));
 
369
#ifdef PAM_READ_BOTH_CONFS
 
370
                D(("checking %s", PAM_CONFIG));
 
371
 
 
372
                if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
 
373
                    retval = _pam_parse_conf_file(pamh, f, NULL, 1);
 
374
                    fclose(f);
 
375
                } else
 
376
#endif /* PAM_READ_BOTH_CONFS */
 
377
                retval = PAM_SUCCESS;
 
378
                /*
 
379
                 * XXX - should we log an error? Some people want to always
 
380
                 * use "other"
 
381
                 */
 
382
            }
 
383
            _pam_drop(filename);
 
384
 
 
385
            if (retval == PAM_SUCCESS) {
 
386
                /* now parse the PAM_DEFAULT_SERVICE_FILE */
 
387
 
 
388
                D(("opening %s", PAM_DEFAULT_SERVICE_FILE));
 
389
                f = fopen(PAM_DEFAULT_SERVICE_FILE, "r");
 
390
                if (f != NULL) {
 
391
                    /* would test magic here? */
 
392
                    retval = _pam_parse_conf_file(pamh, f
 
393
                                                  , PAM_DEFAULT_SERVICE
 
394
#ifdef PAM_READ_BOTH_CONFS
 
395
                                                  , 0
 
396
#endif /* PAM_READ_BOTH_CONFS */
 
397
                        );
 
398
                    fclose(f);
 
399
                    if (retval != PAM_SUCCESS) {
 
400
                        _pam_system_log(LOG_ERR,
 
401
                                        "_pam_init_handlers: error reading %s",
 
402
                                        PAM_DEFAULT_SERVICE_FILE);
 
403
                        _pam_system_log(LOG_ERR,
 
404
                                        "_pam_init_handlers: [%s]",
 
405
                                        pam_strerror(pamh, retval));
 
406
                    } else {
 
407
                        read_something = 1;
 
408
                    }
 
409
                } else {
 
410
                    D(("unable to open %s", PAM_DEFAULT_SERVICE_FILE));
 
411
                    _pam_system_log(LOG_ERR,
 
412
                                    "_pam_init_handlers: no default config %s",
 
413
                                    PAM_DEFAULT_SERVICE_FILE);
 
414
                }
 
415
                if (!read_something) {          /* nothing read successfully */
 
416
                    retval = PAM_ABORT;
 
417
                }
 
418
            }
 
419
        } else {
 
420
            if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
 
421
                _pam_system_log(LOG_ERR, "_pam_init_handlers: could not open "
 
422
                                PAM_CONFIG );
 
423
                return PAM_ABORT;
 
424
            }
 
425
 
 
426
            retval = _pam_parse_conf_file(pamh, f, NULL
 
427
#ifdef PAM_READ_BOTH_CONFS
 
428
                                          , 0
 
429
#endif /* PAM_READ_BOTH_CONFS */
 
430
                );
 
431
 
 
432
            D(("closing configuration file"));
 
433
            fclose(f);
 
434
        }
 
435
    }
 
436
 
 
437
    if (retval != PAM_SUCCESS) {
 
438
        /* Read error */
 
439
        _pam_system_log(LOG_ERR, "error reading PAM configuration file");
 
440
        return PAM_ABORT;
 
441
    }
 
442
 
 
443
    pamh->handlers.handlers_loaded = 1;
 
444
 
 
445
    D(("_pam_init_handlers exiting"));
 
446
    return PAM_SUCCESS;
 
447
}
 
448
 
 
449
/*
 
450
 * This is where we read a line of the PAM config file. The line may be
 
451
 * preceeded by lines of comments and also extended with "\\\n"
 
452
 */
 
453
 
 
454
static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
 
455
{
 
456
    char *p = buffer;
 
457
    char *s, *os;
 
458
    int used = 0;
 
459
 
 
460
    /* loop broken with a 'break' when a non-'\\n' ended line is read */
 
461
 
 
462
    D(("called."));
 
463
    for (;;) {
 
464
        if (used >= buf_len) {
 
465
            /* Overflow */
 
466
            D(("_pam_assemble_line: overflow"));
 
467
            return -1;
 
468
        }
 
469
        if (fgets(p, buf_len - used, f) == NULL) {
 
470
            if (used) {
 
471
                /* Incomplete read */
 
472
                return -1;
 
473
            } else {
 
474
                /* EOF */
 
475
                return 0;
 
476
            }
 
477
        }
 
478
 
 
479
        /* skip leading spaces --- line may be blank */
 
480
 
 
481
        s = p + strspn(p, " \n\t");
 
482
        if (*s && (*s != '#')) {
 
483
            os = s;
 
484
 
 
485
            /*
 
486
             * we are only interested in characters before the first '#'
 
487
             * character
 
488
             */
 
489
 
 
490
            while (*s && *s != '#')
 
491
                 ++s;
 
492
            if (*s == '#') {
 
493
                 *s = '\0';
 
494
                 used += strlen(os);
 
495
                 break;                /* the line has been read */
 
496
            }
 
497
 
 
498
            s = os;
 
499
 
 
500
            /*
 
501
             * Check for backslash by scanning back from the end of
 
502
             * the entered line, the '\n' has been included since
 
503
             * normally a line is terminated with this
 
504
             * character. fgets() should only return one though!
 
505
             */
 
506
 
 
507
            s += strlen(s);
 
508
            while (s > os && ((*--s == ' ') || (*s == '\t')
 
509
                              || (*s == '\n')));
 
510
 
 
511
            /* check if it ends with a backslash */
 
512
            if (*s == '\\') {
 
513
                *s++ = ' ';             /* replace backslash with ' ' */
 
514
                *s = '\0';              /* truncate the line here */
 
515
                used += strlen(os);
 
516
                p = s;                  /* there is more ... */
 
517
            } else {
 
518
                /* End of the line! */
 
519
                used += strlen(os);
 
520
                break;                  /* this is the complete line */
 
521
            }
 
522
 
 
523
        } else {
 
524
            /* Nothing in this line */
 
525
            /* Don't move p         */
 
526
        }
 
527
    }
 
528
 
 
529
    return used;
 
530
}
 
531
 
 
532
typedef int (*servicefn)(pam_handle_t *, int, int, char **);
 
533
 
 
534
int _pam_add_handler(pam_handle_t *pamh
 
535
                     , int must_fail, int other, int type
 
536
                     , int *actions, const char *mod_path
 
537
                     , int argc, char **argv, int argvlen)
 
538
{
 
539
    struct loaded_module *mod;
 
540
    int x = 0;
 
541
    struct handler **handler_p;
 
542
    struct handler **handler_p2;
 
543
    struct handlers *the_handlers;
 
544
    const char *sym, *sym2;
 
545
#ifdef PAM_SHL
 
546
    const char *_sym, *_sym2;
 
547
#endif
 
548
    char *mod_full_path=NULL;
 
549
    servicefn func, func2;
 
550
    int success;
 
551
 
 
552
    D(("called."));
 
553
    IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
 
554
 
 
555
    /* if NULL set to something that can be searched for */
 
556
    switch (mod_path != NULL) {
 
557
    default:
 
558
        if (mod_path[0] == '/') {
 
559
            break;
 
560
        }
 
561
        mod_full_path = malloc(sizeof(DEFAULT_MODULE_PATH)+strlen(mod_path));
 
562
        if (mod_full_path) {
 
563
            sprintf(mod_full_path, DEFAULT_MODULE_PATH "%s", mod_path);
 
564
            mod_path = mod_full_path;
 
565
            break;
 
566
        }
 
567
        _pam_system_log(LOG_CRIT, "cannot malloc full mod path");
 
568
    case 0:
 
569
        mod_path = UNKNOWN_MODULE_PATH;
 
570
    }
 
571
 
 
572
    D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path));
 
573
    mod  = pamh->handlers.module;
 
574
 
 
575
    /* First, ensure the module is loaded */
 
576
    while (x < pamh->handlers.modules_used) {
 
577
        if (!strcmp(mod[x].name, mod_path)) {  /* case sensitive ! */
 
578
            break;
 
579
        }
 
580
        x++;
 
581
    }
 
582
    if (x == pamh->handlers.modules_used) {
 
583
        /* Not found */
 
584
        if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
 
585
            /* will need more memory */
 
586
            void *tmp = realloc(pamh->handlers.module,
 
587
                               (pamh->handlers.modules_allocated+MODULE_CHUNK)
 
588
                               *sizeof(struct loaded_module));
 
589
            if (tmp == NULL) {
 
590
                D(("cannot enlarge module pointer memory"));
 
591
                _pam_system_log(LOG_ERR,
 
592
                                "realloc returned NULL in _pam_add_handler");
 
593
                _pam_drop(mod_full_path);
 
594
                return PAM_ABORT;
 
595
            }
 
596
            pamh->handlers.module = tmp;
 
597
            pamh->handlers.modules_allocated += MODULE_CHUNK;
 
598
        }
 
599
        mod = &(pamh->handlers.module[x]);
 
600
        /* Be pessimistic... */
 
601
        success = PAM_ABORT;
 
602
 
 
603
#ifdef PAM_DYNAMIC
 
604
        D(("_pam_add_handler: dlopen(%s) -> %lx", mod_path, &mod->dl_handle));
 
605
        mod->dl_handle =
 
606
# ifdef PAM_SHL
 
607
            shl_load(mod_path, BIND_IMMEDIATE, 0L);
 
608
# else /* PAM_SHL */
 
609
            dlopen(mod_path, RTLD_NOW);
 
610
# endif /* PAM_SHL */
 
611
        D(("_pam_add_handler: dlopen'ed"));
 
612
        if (mod->dl_handle == NULL) {
 
613
            D(("_pam_add_handler: dlopen(%s) failed", mod_path));
 
614
            _pam_system_log(LOG_ERR, "unable to dlopen(%s)", mod_path);
 
615
# ifndef PAM_SHL
 
616
            _pam_system_log(LOG_ERR, "[dlerror: %s]", dlerror());
 
617
# endif /* PAM_SHL */
 
618
            /* Don't abort yet; static code may be able to find function.
 
619
             * But defaults to abort if nothing found below... */
 
620
        } else {
 
621
            D(("module added successfully"));
 
622
            success = PAM_SUCCESS;
 
623
            mod->type = PAM_MT_DYNAMIC_MOD;
 
624
            pamh->handlers.modules_used++;
 
625
        }
 
626
#endif
 
627
#ifdef PAM_STATIC
 
628
        /* Only load static function if function was not found dynamically.
 
629
         * This code should work even if no dynamic loading is available. */
 
630
        if (success != PAM_SUCCESS) {
 
631
            D(("_pam_add_handler: open static handler %s", mod_path));
 
632
            mod->dl_handle = _pam_open_static_handler(mod_path);
 
633
            if (mod->dl_handle == NULL) {
 
634
                D(("_pam_add_handler: unable to find static handler %s",
 
635
                   mod_path));
 
636
                _pam_system_log(LOG_ERR,
 
637
                                "unable to open static handler %s", mod_path);
 
638
                /* Didn't find module in dynamic or static..will mark bad */
 
639
            } else {
 
640
                D(("static module added successfully"));
 
641
                success = PAM_SUCCESS;
 
642
                mod->type = PAM_MT_STATIC_MOD;
 
643
                pamh->handlers.modules_used++;
 
644
            }
 
645
        }
 
646
#endif
 
647
 
 
648
        if (success != PAM_SUCCESS) {            /* add a malformed module */
 
649
            mod->dl_handle = NULL;
 
650
            mod->type = PAM_MT_FAULTY_MOD;
 
651
            pamh->handlers.modules_used++;
 
652
            _pam_system_log(LOG_ERR, "adding faulty module: %s", mod_path);
 
653
            success = PAM_SUCCESS;  /* We have successfully added a module */
 
654
        }
 
655
 
 
656
        /* indicate its name - later we will search for it by this */
 
657
        if ((mod->name = _pam_strdup(mod_path)) == NULL) {
 
658
            D(("_pam_handler: couldn't get memory for mod_path"));
 
659
            _pam_system_log(LOG_ERR, "no memory for module path", mod_path);
 
660
            success = PAM_ABORT;
 
661
        }
 
662
 
 
663
    } else {                           /* x != pamh->handlers.modules_used */
 
664
        mod += x;                                    /* the located module */
 
665
        success = PAM_SUCCESS;
 
666
    }
 
667
 
 
668
    _pam_drop(mod_full_path);
 
669
    mod_path = NULL;                        /* no longer needed or trusted */
 
670
 
 
671
    /* Now return error if necessary after trying all possible ways... */
 
672
    if (success != PAM_SUCCESS)
 
673
        return(success);
 
674
 
 
675
    /*
 
676
     * At this point 'mod' points to the stored/loaded module. If its
 
677
     * dl_handle is unknown, then we must be able to indicate dispatch
 
678
     * failure with 'must_fail'
 
679
     */
 
680
 
 
681
    /* Now define the handler(s) based on mod->dlhandle and type */
 
682
 
 
683
    /* decide which list of handlers to use */
 
684
    the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
 
685
 
 
686
    handler_p = handler_p2 = NULL;
 
687
    func = func2 = NULL;
 
688
#ifdef PAM_SHL
 
689
    _sym2 =
 
690
#endif /* PAM_SHL */
 
691
    sym2 = NULL;
 
692
 
 
693
    /* point handler_p's at the root addresses of the function stacks */
 
694
    switch (type) {
 
695
    case PAM_T_AUTH:
 
696
        handler_p = &the_handlers->authenticate;
 
697
        sym = SHLIB_SYM_PREFIX "pam_sm_authenticate";
 
698
        handler_p2 = &the_handlers->setcred;
 
699
        sym2 = SHLIB_SYM_PREFIX "pam_sm_setcred";
 
700
#ifdef PAM_SHL
 
701
        _sym = "_pam_sm_authenticate";
 
702
        _sym2 = "_pam_sm_setcred";
 
703
#endif
 
704
        break;
 
705
    case PAM_T_SESS:
 
706
        handler_p = &the_handlers->open_session;
 
707
        sym = SHLIB_SYM_PREFIX "pam_sm_open_session";
 
708
        handler_p2 = &the_handlers->close_session;
 
709
        sym2 = SHLIB_SYM_PREFIX "pam_sm_close_session";
 
710
#ifdef PAM_SHL
 
711
        _sym = "_pam_sm_open_session";
 
712
        _sym2 = "_pam_sm_close_session";
 
713
#endif
 
714
        break;
 
715
    case PAM_T_ACCT:
 
716
        handler_p = &the_handlers->acct_mgmt;
 
717
        sym = SHLIB_SYM_PREFIX "pam_sm_acct_mgmt";
 
718
#ifdef PAM_SHL
 
719
        _sym = "_pam_sm_acct_mgmt";
 
720
#endif
 
721
        break;
 
722
    case PAM_T_PASS:
 
723
        handler_p = &the_handlers->chauthtok;
 
724
        sym = SHLIB_SYM_PREFIX "pam_sm_chauthtok";
 
725
#ifdef PAM_SHL
 
726
        _sym = "_pam_sm_chauthtok";
 
727
#endif
 
728
        break;
 
729
    default:
 
730
        /* Illegal module type */
 
731
        D(("_pam_add_handler: illegal module type %d", type));
 
732
        return PAM_ABORT;
 
733
    }
 
734
 
 
735
    /* are the modules reliable? */
 
736
    if (
 
737
#ifdef PAM_DYNAMIC
 
738
         mod->type != PAM_MT_DYNAMIC_MOD
 
739
         &&
 
740
#endif /* PAM_DYNAMIC */
 
741
#ifdef PAM_STATIC
 
742
         mod->type != PAM_MT_STATIC_MOD
 
743
         &&
 
744
#endif /* PAM_STATIC */
 
745
         mod->type != PAM_MT_FAULTY_MOD
 
746
        ) {
 
747
        D(("_pam_add_handlers: illegal module library type; %d", mod->type));
 
748
        _pam_system_log(LOG_ERR,
 
749
                        "internal error: module library type not known: %s;%d",
 
750
                        sym, mod->type);
 
751
        return PAM_ABORT;
 
752
    }
 
753
 
 
754
    /* now identify this module's functions - for non-faulty modules */
 
755
    
 
756
#ifdef PAM_DYNAMIC
 
757
    if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
 
758
# ifdef PAM_SHL
 
759
        (shl_findsym(&mod->dl_handle, sym, (short) TYPE_PROCEDURE, &func) &&
 
760
         shl_findsym(&mod->dl_handle, _sym, (short) TYPE_PROCEDURE, &func))
 
761
# else /* PAM_SHL */
 
762
        (func = (servicefn) dlsym(mod->dl_handle, sym)) == NULL
 
763
# endif /* PAM_SHL */
 
764
        ) {
 
765
        _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym);
 
766
    }
 
767
#endif
 
768
#ifdef PAM_STATIC
 
769
    if ((mod->type == PAM_MT_STATIC_MOD) &&
 
770
        (func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) {
 
771
        _pam_system_log(LOG_ERR, "unable to resolve static symbol: %s", sym);
 
772
    }
 
773
#endif
 
774
    if (sym2) {
 
775
#ifdef PAM_DYNAMIC
 
776
        if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
 
777
# ifdef PAM_SHL
 
778
            (shl_findsym(&mod->dl_handle,sym2,(short)TYPE_PROCEDURE, &func2)&&
 
779
             shl_findsym(&mod->dl_handle,_sym2,(short)TYPE_PROCEDURE, &func2))
 
780
# else /* PAM_SHL */
 
781
            (func2 = (servicefn) dlsym(mod->dl_handle, sym2)) == NULL
 
782
# endif /* PAM_SHL */
 
783
            ) {
 
784
            _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2);
 
785
        }
 
786
#endif
 
787
#ifdef PAM_STATIC
 
788
        if ((mod->type == PAM_MT_STATIC_MOD) &&
 
789
            (func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2))
 
790
            == NULL) {
 
791
            _pam_system_log(LOG_ERR, "unable to resolve symbol: %s", sym2);
 
792
        }
 
793
#endif
 
794
    }
 
795
 
 
796
    /* here func (and perhaps func2) point to the appropriate functions */
 
797
 
 
798
    /* add new handler to end of existing list */
 
799
    while (*handler_p != NULL) {
 
800
        handler_p = &((*handler_p)->next);
 
801
    }
 
802
 
 
803
    if ((*handler_p = malloc(sizeof(struct handler))) == NULL) {
 
804
        _pam_system_log(LOG_CRIT, "cannot malloc struct handler #1");
 
805
        return (PAM_ABORT);
 
806
    }
 
807
 
 
808
    (*handler_p)->must_fail = must_fail;        /* failure forced? */
 
809
    (*handler_p)->func = func;
 
810
    memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
 
811
    (*handler_p)->cached_retval = _PAM_INVALID_RETVAL;
 
812
    (*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
 
813
    (*handler_p)->argc = argc;
 
814
    (*handler_p)->argv = argv;                       /* not a copy */
 
815
    (*handler_p)->next = NULL;
 
816
 
 
817
    /* some of the modules have a second calling function */
 
818
    if (handler_p2) {
 
819
        /* add new handler to end of existing list */
 
820
        while (*handler_p2) {
 
821
            handler_p2 = &((*handler_p2)->next);
 
822
        }
 
823
 
 
824
        if ((*handler_p2 = malloc(sizeof(struct handler))) == NULL) {
 
825
            _pam_system_log(LOG_CRIT, "cannot malloc struct handler #2");
 
826
            return (PAM_ABORT);
 
827
        }
 
828
 
 
829
        (*handler_p2)->must_fail = must_fail;        /* failure forced? */
 
830
        (*handler_p2)->func = func2;
 
831
        memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
 
832
        (*handler_p2)->cached_retval =  _PAM_INVALID_RETVAL;     /* ignored */
 
833
        /* Note, this next entry points to the handler_p value! */
 
834
        (*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval);
 
835
        (*handler_p2)->argc = argc;
 
836
        if (argv) {
 
837
            if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
 
838
                _pam_system_log(LOG_CRIT, "cannot malloc argv for handler #2");
 
839
                return (PAM_ABORT);
 
840
            }
 
841
            memcpy((*handler_p2)->argv, argv, argvlen);
 
842
        } else {
 
843
            (*handler_p2)->argv = NULL;              /* no arguments */
 
844
        }
 
845
        (*handler_p2)->next = NULL;
 
846
    }
 
847
 
 
848
    D(("_pam_add_handler: returning successfully"));
 
849
 
 
850
    return PAM_SUCCESS;
 
851
}
 
852
 
 
853
/* Free various allocated structures and dlclose() the libs */
 
854
int _pam_free_handlers(pam_handle_t *pamh)
 
855
{
 
856
    struct loaded_module *mod;
 
857
 
 
858
    D(("called."));
 
859
    IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
 
860
 
 
861
    mod = pamh->handlers.module;
 
862
 
 
863
    /* Close all loaded modules */
 
864
 
 
865
    while (pamh->handlers.modules_used) {
 
866
        D(("_pam_free_handlers: dlclose(%s)", mod->name));
 
867
        free(mod->name);
 
868
#ifdef PAM_DYNAMIC
 
869
        if (mod->type == PAM_MT_DYNAMIC_MOD) {
 
870
# ifdef PAM_SHL
 
871
            shl_unload(mod->dl_handle);
 
872
# else
 
873
            dlclose(mod->dl_handle);
 
874
# endif
 
875
        }
 
876
#endif
 
877
        mod++;
 
878
        pamh->handlers.modules_used--;
 
879
    }
 
880
 
 
881
    /* Free all the handlers */
 
882
    
 
883
    _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
 
884
    _pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
 
885
    _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
 
886
    _pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
 
887
    _pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
 
888
    _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
 
889
 
 
890
    _pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
 
891
    _pam_free_handlers_aux(&(pamh->handlers.other.setcred));
 
892
    _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
 
893
    _pam_free_handlers_aux(&(pamh->handlers.other.open_session));
 
894
    _pam_free_handlers_aux(&(pamh->handlers.other.close_session));
 
895
    _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
 
896
 
 
897
    /* no more loaded modules */
 
898
 
 
899
    _pam_drop(pamh->handlers.module);
 
900
 
 
901
    /* Indicate that handlers are not initialized for this pamh */
 
902
 
 
903
    pamh->handlers.handlers_loaded = 0;
 
904
 
 
905
    return PAM_SUCCESS;
 
906
}
 
907
 
 
908
void _pam_start_handlers(pam_handle_t *pamh)
 
909
{
 
910
    D(("called."));
 
911
    /* NB. There is no check for a NULL pamh here, since no return
 
912
     * value to communicate the fact!  */
 
913
 
 
914
    /* Indicate that handlers are not initialized for this pamh */
 
915
    pamh->handlers.handlers_loaded = 0;
 
916
 
 
917
    pamh->handlers.modules_allocated = 0;
 
918
    pamh->handlers.modules_used = 0;
 
919
    pamh->handlers.module = NULL;
 
920
 
 
921
    /* initialize the .conf and .other entries */
 
922
    
 
923
    pamh->handlers.conf.authenticate = NULL;
 
924
    pamh->handlers.conf.setcred = NULL;
 
925
    pamh->handlers.conf.acct_mgmt = NULL;
 
926
    pamh->handlers.conf.open_session = NULL;
 
927
    pamh->handlers.conf.close_session = NULL;
 
928
    pamh->handlers.conf.chauthtok = NULL;
 
929
 
 
930
    pamh->handlers.other.authenticate = NULL;
 
931
    pamh->handlers.other.setcred = NULL;
 
932
    pamh->handlers.other.acct_mgmt = NULL;
 
933
    pamh->handlers.other.open_session = NULL;
 
934
    pamh->handlers.other.close_session = NULL;
 
935
    pamh->handlers.other.chauthtok = NULL;
 
936
}
 
937
 
 
938
void _pam_free_handlers_aux(struct handler **hp)
 
939
{
 
940
    struct handler *h = *hp;
 
941
    struct handler *last;
 
942
 
 
943
    D(("called."));
 
944
    while (h) {
 
945
        last = h;
 
946
        _pam_drop(h->argv);  /* This is all alocated in a single chunk */
 
947
        h = h->next;
 
948
        memset(last, 0, sizeof(*last));
 
949
        free(last);
 
950
    }
 
951
 
 
952
    *hp = NULL;
 
953
}