diff options
author | markm <markm@FreeBSD.org> | 2001-07-09 18:14:43 +0000 |
---|---|---|
committer | markm <markm@FreeBSD.org> | 2001-07-09 18:14:43 +0000 |
commit | 1b8cb1cd38833815186cfb8cb20c2f5628992d82 (patch) | |
tree | 4be47053e4fbe71b772b0186a5f90e96b81162bc | |
parent | 5df25064461f5ca22954749947b42936989a0dcb (diff) | |
download | FreeBSD-src-1b8cb1cd38833815186cfb8cb20c2f5628992d82.zip FreeBSD-src-1b8cb1cd38833815186cfb8cb20c2f5628992d82.tar.gz |
Almost completely rewrite the PAM module options processing
routines, and provide a more extended API for doing this.
Provide an API for debug logging.
Audit and clean up the code.
-rw-r--r-- | lib/libpam/libpam/Makefile | 2 | ||||
-rw-r--r-- | lib/libpam/libpam/pam_debug_log.c | 96 | ||||
-rw-r--r-- | lib/libpam/libpam/pam_get_pass.c | 43 | ||||
-rw-r--r-- | lib/libpam/libpam/pam_mod_misc.h | 50 | ||||
-rw-r--r-- | lib/libpam/libpam/pam_prompt.c | 13 | ||||
-rw-r--r-- | lib/libpam/libpam/pam_std_option.c | 162 | ||||
-rw-r--r-- | lib/libpam/libpam/security/pam_mod_misc.h | 50 |
7 files changed, 334 insertions, 82 deletions
diff --git a/lib/libpam/libpam/Makefile b/lib/libpam/libpam/Makefile index 49186d3..ee3e5ce 100644 --- a/lib/libpam/libpam/Makefile +++ b/lib/libpam/libpam/Makefile @@ -61,7 +61,7 @@ SRCS+= help_env.c misc_conv.c xstrdup.c HDRS2= pam_misc.h # Files from ${.CURDIR}: -SRCS+= pam_get_pass.c pam_prompt.c pam_std_option.c +SRCS+= pam_get_pass.c pam_prompt.c pam_std_option.c pam_debug_log.c HDRS3= pam_mod_misc.h # Static PAM modules: diff --git a/lib/libpam/libpam/pam_debug_log.c b/lib/libpam/libpam/pam_debug_log.c new file mode 100644 index 0000000..0e39a2d --- /dev/null +++ b/lib/libpam/libpam/pam_debug_log.c @@ -0,0 +1,96 @@ +/*- + * Copyright 2001 Mark R V Murray + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <security/pam_modules.h> +#include <libgen.h> +#include <stdarg.h> +#include <string.h> +#include <syslog.h> + +#include "pam_mod_misc.h" + +#define FMTBUFSIZ 256 + +/* Log a debug message, including the function name and a + * cleaned up filename. + */ +void +_pam_log(struct options *options, const char *file, const char *function, + const char *format, ...) +{ + va_list ap; + char *period; + char fmtbuf[FMTBUFSIZ]; + + if (pam_test_option(options, PAM_OPT_DEBUG, NULL)) { + strncpy(fmtbuf, basename(file), FMTBUFSIZ); + period = strchr(fmtbuf, '.'); + if (period != NULL) + *period = '\0'; + strncat(fmtbuf, ": ", FMTBUFSIZ); + strncat(fmtbuf, function, FMTBUFSIZ); + strncat(fmtbuf, ": ", FMTBUFSIZ); + strncat(fmtbuf, format, FMTBUFSIZ); + va_start(ap, format); + vsyslog(LOG_DEBUG, fmtbuf, ap); + va_end(ap); + } +} + +/* Log a return value, including the function name and a + * cleaned up filename. + */ +void +_pam_log_retval(struct options *options, const char *file, const char *function, + int retval) +{ + char *period; + char fmtbuf[FMTBUFSIZ]; + + if (pam_test_option(options, PAM_OPT_DEBUG, NULL)) { + strncpy(fmtbuf, basename(file), FMTBUFSIZ); + period = strchr(fmtbuf, '.'); + if (period != NULL) + *period = '\0'; + strncat(fmtbuf, ": ", FMTBUFSIZ); + strncat(fmtbuf, function, FMTBUFSIZ); + switch (retval) { + case PAM_SUCCESS: + strncat(fmtbuf, ": returning PAM_SUCCESS", FMTBUFSIZ); + syslog(LOG_DEBUG, fmtbuf); + break; + case PAM_AUTH_ERR: + strncat(fmtbuf, ": returning PAM_AUTH_ERR", FMTBUFSIZ); + syslog(LOG_DEBUG, fmtbuf); + break; + default: + strncat(fmtbuf, ": returning %d", FMTBUFSIZ); + syslog(LOG_DEBUG, fmtbuf, retval); + } + } +} diff --git a/lib/libpam/libpam/pam_get_pass.c b/lib/libpam/libpam/pam_get_pass.c index 78ef75a..ba55b28 100644 --- a/lib/libpam/libpam/pam_get_pass.c +++ b/lib/libpam/libpam/pam_get_pass.c @@ -26,34 +26,35 @@ * $FreeBSD$ */ +#include <stdlib.h> #include <security/pam_modules.h> #include "pam_mod_misc.h" -static int pam_conv_pass(pam_handle_t *, const char *, int); +static int pam_conv_pass(pam_handle_t *, const char *, struct options *); static int -pam_conv_pass(pam_handle_t *pamh, const char *prompt, int options) +pam_conv_pass(pam_handle_t *pamh, const char *prompt, struct options *options) { - int retval; - const void *item; const struct pam_conv *conv; struct pam_message msg; const struct pam_message *msgs[1]; struct pam_response *resp; + const void *item; + int retval; - if ((retval = pam_get_item(pamh, PAM_CONV, &item)) != - PAM_SUCCESS) + retval = pam_get_item(pamh, PAM_CONV, &item); + if (retval != PAM_SUCCESS) return retval; conv = (const struct pam_conv *)item; - msg.msg_style = options & PAM_OPT_ECHO_PASS ? + msg.msg_style = pam_test_option(options, PAM_OPT_ECHO_PASS, NULL) ? PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF; msg.msg = prompt; msgs[0] = &msg; - if ((retval = conv->conv(1, msgs, &resp, conv->appdata_ptr)) != - PAM_SUCCESS) + retval = conv->conv(1, msgs, &resp, conv->appdata_ptr); + if (retval != PAM_SUCCESS) return retval; - if ((retval = pam_set_item(pamh, PAM_AUTHTOK, resp[0].resp)) != - PAM_SUCCESS) + retval = pam_set_item(pamh, PAM_AUTHTOK, resp[0].resp); + if (retval != PAM_SUCCESS) return retval; memset(resp[0].resp, 0, strlen(resp[0].resp)); free(resp[0].resp); @@ -63,7 +64,7 @@ pam_conv_pass(pam_handle_t *pamh, const char *prompt, int options) int pam_get_pass(pam_handle_t *pamh, const char **passp, const char *prompt, - int options) + struct options *options) { int retval; const void *item = NULL; @@ -71,21 +72,23 @@ pam_get_pass(pam_handle_t *pamh, const char **passp, const char *prompt, /* * Grab the already-entered password if we might want to use it. */ - if (options & (PAM_OPT_TRY_FIRST_PASS | PAM_OPT_USE_FIRST_PASS)) { - if ((retval = pam_get_item(pamh, PAM_AUTHTOK, &item)) != - PAM_SUCCESS) + if (pam_test_option(options, PAM_OPT_TRY_FIRST_PASS, NULL) || + pam_test_option(options, PAM_OPT_USE_FIRST_PASS, NULL)) { + retval = pam_get_item(pamh, PAM_AUTHTOK, &item); + if (retval != PAM_SUCCESS) return retval; } if (item == NULL) { /* The user hasn't entered a password yet. */ - if (options & PAM_OPT_USE_FIRST_PASS) + if (pam_test_option(options, PAM_OPT_USE_FIRST_PASS, NULL)) return PAM_AUTH_ERR; /* Use the conversation function to get a password. */ - if ((retval = pam_conv_pass(pamh, prompt, options)) != - PAM_SUCCESS || - (retval = pam_get_item(pamh, PAM_AUTHTOK, &item)) != - PAM_SUCCESS) + retval = pam_conv_pass(pamh, prompt, options); + if (retval != PAM_SUCCESS) + return retval; + retval = pam_get_item(pamh, PAM_AUTHTOK, &item); + if (retval != PAM_SUCCESS) return retval; } *passp = (const char *)item; diff --git a/lib/libpam/libpam/pam_mod_misc.h b/lib/libpam/libpam/pam_mod_misc.h index ff4dfa5..cefc052 100644 --- a/lib/libpam/libpam/pam_mod_misc.h +++ b/lib/libpam/libpam/pam_mod_misc.h @@ -31,22 +31,44 @@ #include <sys/cdefs.h> -/* Options */ -#define PAM_OPT_DEBUG 0x0001 -#define PAM_OPT_NO_WARN 0x0002 -#define PAM_OPT_USE_FIRST_PASS 0x0004 -#define PAM_OPT_TRY_FIRST_PASS 0x0008 -#define PAM_OPT_USE_MAPPED_PASS 0x0010 -#define PAM_OPT_ECHO_PASS 0x0020 -#define PAM_OPT_AUTH_AS_SELF 0x0040 -#define PAM_OPT_NULLOK 0x0080 -#define PAM_OPT_NO_ANON 0x0100 -#define PAM_OPT_IGNORE 0x0200 +/* Standard options + */ +enum opt { PAM_OPT_DEBUG, PAM_OPT_NO_WARN, PAM_OPT_ECHO_PASS, + PAM_OPT_USE_FIRST_PASS, PAM_OPT_TRY_FIRST_PASS, PAM_OPT_USE_MAPPED_PASS, + PAM_OPT_EXPOSE_ACCOUNT, PAM_OPT_STD_MAX /* XXX */ }; + +#define PAM_MAX_OPTIONS 20 + +struct opttab { + const char *name; + int value; +}; + +struct options { + struct { + int bool; + char *arg; + } opt[PAM_MAX_OPTIONS]; +}; __BEGIN_DECLS -int pam_get_pass(pam_handle_t *, const char **, const char *, int); -int pam_prompt(pam_handle_t *, int, const char *, char **); -int pam_std_option(int *, const char *); +int pam_get_pass(pam_handle_t *, const char **, const char *, struct options *); +int pam_prompt(pam_handle_t *, int, const char *, char **); +void pam_std_option(struct options *, struct opttab *, int, const char **); +int pam_test_option(struct options *, enum opt, char **); +void pam_set_option(struct options *, enum opt); +void pam_clear_option(struct options *, enum opt); +void _pam_log(struct options *, const char *, const char *, const char *, ...); +void _pam_log_retval(struct options *, const char *, const char *, int); __END_DECLS +#define PAM_LOG(args...) \ + _pam_log(&options, __FILE__, __FUNCTION__, ##args) + +#define PAM_RETURN(arg) \ + do { \ + _pam_log_retval(&options, __FILE__, __FUNCTION__, arg); \ + return arg; \ + } while (0) + #endif diff --git a/lib/libpam/libpam/pam_prompt.c b/lib/libpam/libpam/pam_prompt.c index 220616e..7d80745 100644 --- a/lib/libpam/libpam/pam_prompt.c +++ b/lib/libpam/libpam/pam_prompt.c @@ -27,6 +27,7 @@ */ #include <security/pam_modules.h> +#include <stdlib.h> #include "pam_mod_misc.h" /* @@ -36,22 +37,22 @@ int pam_prompt(pam_handle_t *pamh, int style, const char *prompt, char **user_msg) { - int retval; - const void *item; const struct pam_conv *conv; struct pam_message msg; const struct pam_message *msgs[1]; struct pam_response *resp; + const void *item; + int retval; - if ((retval = pam_get_item(pamh, PAM_CONV, &item)) != - PAM_SUCCESS) + retval = pam_get_item(pamh, PAM_CONV, &item); + if (retval != PAM_SUCCESS) return retval; conv = (const struct pam_conv *)item; msg.msg_style = style; msg.msg = prompt != NULL ? prompt : ""; msgs[0] = &msg; - if ((retval = conv->conv(1, msgs, &resp, conv->appdata_ptr)) != - PAM_SUCCESS) + retval = conv->conv(1, msgs, &resp, conv->appdata_ptr); + if (retval != PAM_SUCCESS) return retval; if (user_msg != NULL) *user_msg = resp[0].resp; diff --git a/lib/libpam/libpam/pam_std_option.c b/lib/libpam/libpam/pam_std_option.c index 266514e..4388197 100644 --- a/lib/libpam/libpam/pam_std_option.c +++ b/lib/libpam/libpam/pam_std_option.c @@ -27,40 +27,148 @@ */ #include <security/pam_modules.h> +#include <stdio.h> #include <string.h> +#include <syslog.h> #include "pam_mod_misc.h" -/* - * If the given name is a standard option, set the corresponding flag in - * the options word and return 0. Else return -1. +/* Everyone has to have these options. It is not an error to + * specify them and then not use them. */ +static struct opttab std_options[PAM_MAX_OPTIONS] = { + { "debug", PAM_OPT_DEBUG }, + { "no_warn", PAM_OPT_NO_WARN }, + { "echo_pass", PAM_OPT_ECHO_PASS }, + { "use_first_pass", PAM_OPT_USE_FIRST_PASS }, + { "try_first_pass", PAM_OPT_TRY_FIRST_PASS }, + { "use_mapped_pass", PAM_OPT_USE_MAPPED_PASS }, + { "expose_account", PAM_OPT_EXPOSE_ACCOUNT }, + { NULL, 0 } +}; + +/* Populate the options structure, syslogging all errors */ +void +pam_std_option(struct options *options, struct opttab other_options[], + int argc, const char **argv) +{ + struct opttab *oo; + int i, j, arglen, found; + + j = 0; + for (i = 0; i < PAM_MAX_OPTIONS; i++) { + options->opt[i].bool = 0; + options->opt[i].arg = NULL; + if (j == 0 && std_options[i].name == NULL) + j = i; + /* XXX Bad juju happens if loop exits with j == 0 */ + } + if (other_options) + for (oo = other_options; oo->name != NULL; oo++) { + if (oo == NULL || oo->name == NULL) + break; + std_options[j].name = oo->name; + std_options[j].value = oo->value; + j++; + } + if (j < PAM_MAX_OPTIONS) { + std_options[j].name = NULL; + std_options[j].value = 0; + } + for (j = 0; j < argc; j++) { +#ifdef DEBUG + syslog(LOG_DEBUG, "Doing arg %s ", argv[j]); +#endif + found = 0; + for (i = 0; i < PAM_MAX_OPTIONS; i++) { + if (std_options[i].name == NULL) + break; + if (strcmp(argv[j], std_options[i].name) == 0) { + options->opt[std_options[i].value].bool = 1; + found = 1; + break; + } + else { + arglen = strlen(std_options[i].name); + if (strncmp(argv[j], std_options[i].name, + arglen) == 0 + && argv[j][arglen] == '=') { + options->opt[std_options[i].value].bool + = 1; + options->opt[std_options[i].value].arg = + strdup(&argv[j][arglen + 1]); + found = 1; + break; + } + } + } + if (!found) + syslog(LOG_WARNING, "PAM option: %s invalid", argv[j]); + } +} + +/* Test if option is set in options */ +int +pam_test_option(struct options *options, enum opt option, char **arg) +{ + if (arg != NULL) + *arg = options->opt[option].arg; + return options->opt[option].bool; +} + +/* Set option in options, errors to syslog */ +void +pam_set_option(struct options *options, enum opt option) +{ + if (option < PAM_OPT_STD_MAX) + options->opt[option].bool = 1; +#ifdef DEBUG + else + syslog(LOG_DEBUG, "PAM options: attempt to set option %d", + option); +#endif +} + +/* Clear option in options, errors to syslog */ +void +pam_clear_option(struct options *options, enum opt option) +{ + if (option < PAM_OPT_STD_MAX) + options->opt[option].bool = 0; +#ifdef DEBUG + else + syslog(LOG_DEBUG, "PAM options: attempt to clear option %d", + option); +#endif +} + +#if DEBUG1 +enum { PAM_OPT_FOO=PAM_OPT_STD_MAX, PAM_OPT_BAR, PAM_OPT_BAZ, PAM_OPT_QUX }; + +struct opttab other_options[] = { + { "foo", PAM_OPT_FOO }, + { "bar", PAM_OPT_BAR }, + { "baz", PAM_OPT_BAZ }, + { "qux", PAM_OPT_QUX }, + { NULL, 0 } +}; + int -pam_std_option(int *options, const char *name) +main(int argc, const char *argv[]) { - struct opttab { - const char *name; - int value; - }; - static struct opttab std_options[] = { - { "debug", PAM_OPT_DEBUG }, - { "no_warn", PAM_OPT_NO_WARN }, - { "use_first_pass", PAM_OPT_USE_FIRST_PASS }, - { "try_first_pass", PAM_OPT_TRY_FIRST_PASS }, - { "use_mapped_pass", PAM_OPT_USE_MAPPED_PASS }, - { "echo_pass", PAM_OPT_ECHO_PASS }, - { "auth_as_self", PAM_OPT_AUTH_AS_SELF }, - { "nullok", PAM_OPT_NULLOK }, - { "no_anon", PAM_OPT_NO_ANON }, - { "ignore", PAM_OPT_IGNORE }, - { NULL, 0 } - }; - struct opttab *p; + struct options options; + int i, opt; + char *arg; - for (p = std_options; p->name != NULL; p++) { - if (strcmp(name, p->name) == 0) { - *options |= p->value; - return 0; + pam_std_option(&options, other_options, argc, argv); + for (i = 0; i < PAM_MAX_OPTIONS; i++) { + opt = pam_test_option(&options, i, &arg); + if (opt) { + if (arg == NULL) + printf("%d []\n", i); + else + printf("%d [%s]\n", i, arg); } } - return -1; + return 0; } +#endif diff --git a/lib/libpam/libpam/security/pam_mod_misc.h b/lib/libpam/libpam/security/pam_mod_misc.h index ff4dfa5..cefc052 100644 --- a/lib/libpam/libpam/security/pam_mod_misc.h +++ b/lib/libpam/libpam/security/pam_mod_misc.h @@ -31,22 +31,44 @@ #include <sys/cdefs.h> -/* Options */ -#define PAM_OPT_DEBUG 0x0001 -#define PAM_OPT_NO_WARN 0x0002 -#define PAM_OPT_USE_FIRST_PASS 0x0004 -#define PAM_OPT_TRY_FIRST_PASS 0x0008 -#define PAM_OPT_USE_MAPPED_PASS 0x0010 -#define PAM_OPT_ECHO_PASS 0x0020 -#define PAM_OPT_AUTH_AS_SELF 0x0040 -#define PAM_OPT_NULLOK 0x0080 -#define PAM_OPT_NO_ANON 0x0100 -#define PAM_OPT_IGNORE 0x0200 +/* Standard options + */ +enum opt { PAM_OPT_DEBUG, PAM_OPT_NO_WARN, PAM_OPT_ECHO_PASS, + PAM_OPT_USE_FIRST_PASS, PAM_OPT_TRY_FIRST_PASS, PAM_OPT_USE_MAPPED_PASS, + PAM_OPT_EXPOSE_ACCOUNT, PAM_OPT_STD_MAX /* XXX */ }; + +#define PAM_MAX_OPTIONS 20 + +struct opttab { + const char *name; + int value; +}; + +struct options { + struct { + int bool; + char *arg; + } opt[PAM_MAX_OPTIONS]; +}; __BEGIN_DECLS -int pam_get_pass(pam_handle_t *, const char **, const char *, int); -int pam_prompt(pam_handle_t *, int, const char *, char **); -int pam_std_option(int *, const char *); +int pam_get_pass(pam_handle_t *, const char **, const char *, struct options *); +int pam_prompt(pam_handle_t *, int, const char *, char **); +void pam_std_option(struct options *, struct opttab *, int, const char **); +int pam_test_option(struct options *, enum opt, char **); +void pam_set_option(struct options *, enum opt); +void pam_clear_option(struct options *, enum opt); +void _pam_log(struct options *, const char *, const char *, const char *, ...); +void _pam_log_retval(struct options *, const char *, const char *, int); __END_DECLS +#define PAM_LOG(args...) \ + _pam_log(&options, __FILE__, __FUNCTION__, ##args) + +#define PAM_RETURN(arg) \ + do { \ + _pam_log_retval(&options, __FILE__, __FUNCTION__, arg); \ + return arg; \ + } while (0) + #endif |