diff options
author | Dmitry V. Levin <ldv@altlinux.org> | 2022-04-23 08:00:00 +0000 |
---|---|---|
committer | Dmitry V. Levin <ldv@altlinux.org> | 2022-04-24 08:00:00 +0000 |
commit | d3b73b6cd818f4fd9c923822592eccbe8ecdd121 (patch) | |
tree | cb587ab07a57464e9b2a476efa47d85050c6bdec /modules/pam_env/pam_env.c | |
parent | 095af08413e5a0f4b8a9f86fda8a85bcfa1d9153 (diff) | |
download | pam-d3b73b6cd818f4fd9c923822592eccbe8ecdd121.tar.gz pam-d3b73b6cd818f4fd9c923822592eccbe8ecdd121.tar.bz2 pam-d3b73b6cd818f4fd9c923822592eccbe8ecdd121.zip |
pam_env: reorder definitions of static functions to avoid forward declarations
* modules/pam_env/pam_env.c (_assemble_line, _parse_line, _check_var,
_clean_var, _expand_arg, _pam_get_item_byname, _define_var,
_undefine_var): Move definitions of static functions before their first
use to avoid forward declarations cluttering the code.
Diffstat (limited to 'modules/pam_env/pam_env.c')
-rw-r--r-- | modules/pam_env/pam_env.c | 531 |
1 files changed, 263 insertions, 268 deletions
diff --git a/modules/pam_env/pam_env.c b/modules/pam_env/pam_env.c index c03ec3a3..66fbe240 100644 --- a/modules/pam_env/pam_env.c +++ b/modules/pam_env/pam_env.c @@ -53,15 +53,6 @@ typedef struct var { #define UNDEFINE_VAR 102 #define ILLEGAL_VAR 103 -static int _assemble_line(FILE *, char *, int); -static int _parse_line(const pam_handle_t *, const char *, VAR *); -static int _check_var(pam_handle_t *, VAR *); /* This is the real meat */ -static void _clean_var(VAR *); -static int _expand_arg(pam_handle_t *, char **); -static const char * _pam_get_item_byname(pam_handle_t *, const char *); -static int _define_var(pam_handle_t *, int, VAR *); -static int _undefine_var(pam_handle_t *, int, VAR *); - /* This is a special value used to designate an empty string */ static char quote='\0'; @@ -128,166 +119,12 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv, return ctrl; } -static int -_parse_config_file(pam_handle_t *pamh, int ctrl, const char *file) -{ - int retval; - char buffer[BUF_SIZE]; - FILE *conf; - VAR Var, *var=&Var; - - D(("Called.")); - - var->name=NULL; var->defval=NULL; var->override=NULL; - - D(("Config file name is: %s", file)); - - /* - * Lets try to open the config file, parse it and process - * any variables found. - */ - - if ((conf = fopen(file,"r")) == NULL) { - pam_syslog(pamh, LOG_ERR, "Unable to open config file: %s: %m", file); - return PAM_IGNORE; - } - - /* _pam_assemble_line will provide a complete line from the config file, - * with all comments removed and any escaped newlines fixed up - */ - - while (( retval = _assemble_line(conf, buffer, BUF_SIZE)) > 0) { - D(("Read line: %s", buffer)); - - if ((retval = _parse_line(pamh, buffer, var)) == GOOD_LINE) { - retval = _check_var(pamh, var); - - if (DEFINE_VAR == retval) { - retval = _define_var(pamh, ctrl, var); - - } else if (UNDEFINE_VAR == retval) { - retval = _undefine_var(pamh, ctrl, var); - } - } - if (PAM_SUCCESS != retval && ILLEGAL_VAR != retval - && BAD_LINE != retval && PAM_BAD_ITEM != retval) break; - - _clean_var(var); - - } /* while */ - - (void) fclose(conf); - - /* tidy up */ - _clean_var(var); /* We could have got here prematurely, - * this is safe though */ - D(("Exit.")); - return (retval != 0 ? PAM_ABORT : PAM_SUCCESS); -} - -static int -_parse_env_file(pam_handle_t *pamh, int ctrl, const char *file) -{ - int retval=PAM_SUCCESS, i, t; - char buffer[BUF_SIZE], *key, *mark; - FILE *conf; - - D(("Env file name is: %s", file)); - - if ((conf = fopen(file,"r")) == NULL) { - pam_syslog(pamh, LOG_ERR, "Unable to open env file: %s: %m", file); - return PAM_IGNORE; - } - - while (_assemble_line(conf, buffer, BUF_SIZE) > 0) { - D(("Read line: %s", buffer)); - key = buffer; - - /* skip leading white space */ - key += strspn(key, " \n\t"); - - /* skip blanks lines and comments */ - if (key[0] == '#') - continue; - - /* skip over "export " if present so we can be compat with - bash type declarations */ - if (strncmp(key, "export ", (size_t) 7) == 0) - key += 7; - - /* now find the end of value */ - mark = key; - while(mark[0] != '\n' && mark[0] != '#' && mark[0] != '\0') - mark++; - if (mark[0] != '\0') - mark[0] = '\0'; - - /* - * sanity check, the key must be alphanumeric - */ - - if (key[0] == '=') { - pam_syslog(pamh, LOG_ERR, - "missing key name '%s' in %s', ignoring", - key, file); - continue; - } - - for ( i = 0 ; key[i] != '=' && key[i] != '\0' ; i++ ) - if (!isalnum(key[i]) && key[i] != '_') { - pam_syslog(pamh, LOG_ERR, - "non-alphanumeric key '%s' in %s', ignoring", - key, file); - break; - } - /* non-alphanumeric key, ignore this line */ - if (key[i] != '=' && key[i] != '\0') - continue; - - /* now we try to be smart about quotes around the value, - but not too smart, we can't get all fancy with escaped - values like bash */ - if (key[i] == '=' && (key[++i] == '\"' || key[i] == '\'')) { - for ( t = i+1 ; key[t] != '\0' ; t++) - if (key[t] != '\"' && key[t] != '\'') - key[i++] = key[t]; - else if (key[t+1] != '\0') - key[i++] = key[t]; - key[i] = '\0'; - } - - /* if this is a request to delete a variable, check that it's - actually set first, so we don't get a vague error back from - pam_putenv() */ - for (i = 0; key[i] != '=' && key[i] != '\0'; i++); - - if (key[i] == '\0' && !pam_getenv(pamh,key)) - continue; - - /* set the env var, if it fails, we break out of the loop */ - retval = pam_putenv(pamh, key); - if (retval != PAM_SUCCESS) { - D(("error setting env \"%s\"", key)); - break; - } else if (ctrl & PAM_DEBUG_ARG) { - pam_syslog(pamh, LOG_DEBUG, - "pam_putenv(\"%s\")", key); - } - } - - (void) fclose(conf); - - /* tidy up */ - D(("Exit.")); - return retval; -} - /* * This is where we read a line of the PAM config file. The line may be * preceded by lines of comments and also extended with "\\\n" */ - -static int _assemble_line(FILE *f, char *buffer, int buf_len) +static int +_assemble_line(FILE *f, char *buffer, int buf_len) { char *p = buffer; char *s, *os; @@ -376,7 +213,7 @@ static int _assemble_line(FILE *f, char *buffer, int buf_len) } static int -_parse_line (const pam_handle_t *pamh, const char *buffer, VAR *var) +_parse_line(const pam_handle_t *pamh, const char *buffer, VAR *var) { /* * parse buffer into var, legal syntax is @@ -471,75 +308,57 @@ _parse_line (const pam_handle_t *pamh, const char *buffer, VAR *var) return GOOD_LINE; } -static int _check_var(pam_handle_t *pamh, VAR *var) +static const char * +_pam_get_item_byname(pam_handle_t *pamh, const char *name) { /* - * Examine the variable and determine what action to take. - * Returns DEFINE_VAR, UNDEFINE_VAR depending on action to take - * or a PAM_* error code if passed back from other routines - * - * if no DEFAULT provided, the empty string is assumed - * if no OVERRIDE provided, the empty string is assumed - * if DEFAULT= and OVERRIDE evaluates to the empty string, - * this variable should be undefined - * if DEFAULT="" and OVERRIDE evaluates to the empty string, - * this variable should be defined with no value - * if OVERRIDE=value and value turns into the empty string, DEFAULT is used - * - * If DEFINE_VAR is to be returned, the correct value to define will - * be pointed to by var->value + * This function just allows me to use names as given in the config + * file and translate them into the appropriate PAM_ITEM macro */ - int retval; + int item; + const void *itemval; D(("Called.")); - - /* - * First thing to do is to expand any arguments, but only - * if they are not the special quote values (cause expand_arg - * changes memory). - */ - - if (var->defval && ("e != var->defval) && - ((retval = _expand_arg(pamh, &(var->defval))) != PAM_SUCCESS)) { - return retval; - } - if (var->override && ("e != var->override) && - ((retval = _expand_arg(pamh, &(var->override))) != PAM_SUCCESS)) { - return retval; + if (strcmp(name, "PAM_USER") == 0 || strcmp(name, "HOME") == 0 || strcmp(name, "SHELL") == 0) { + item = PAM_USER; + } else if (strcmp(name, "PAM_USER_PROMPT") == 0) { + item = PAM_USER_PROMPT; + } else if (strcmp(name, "PAM_TTY") == 0) { + item = PAM_TTY; + } else if (strcmp(name, "PAM_RUSER") == 0) { + item = PAM_RUSER; + } else if (strcmp(name, "PAM_RHOST") == 0) { + item = PAM_RHOST; + } else { + D(("Unknown PAM_ITEM: <%s>", name)); + pam_syslog (pamh, LOG_ERR, "Unknown PAM_ITEM: <%s>", name); + return NULL; } - /* Now its easy */ - - if (var->override && *(var->override)) { - /* if there is a non-empty string in var->override, we use it */ - D(("OVERRIDE variable <%s> being used: <%s>", var->name, var->override)); - var->value = var->override; - retval = DEFINE_VAR; - } else { + if (pam_get_item(pamh, item, &itemval) != PAM_SUCCESS) { + D(("pam_get_item failed")); + return NULL; /* let pam_get_item() log the error */ + } - var->value = var->defval; - if ("e == var->defval) { - /* - * This means that the empty string was given for defval value - * which indicates that a variable should be defined with no value - */ - D(("An empty variable: <%s>", var->name)); - retval = DEFINE_VAR; - } else if (var->defval) { - D(("DEFAULT variable <%s> being used: <%s>", var->name, var->defval)); - retval = DEFINE_VAR; - } else { - D(("UNDEFINE variable <%s>", var->name)); - retval = UNDEFINE_VAR; + if (itemval && (strcmp(name, "HOME") == 0 || strcmp(name, "SHELL") == 0)) { + struct passwd *user_entry; + user_entry = pam_modutil_getpwnam (pamh, itemval); + if (!user_entry) { + pam_syslog(pamh, LOG_ERR, "No such user!?"); + return NULL; } + return (strcmp(name, "SHELL") == 0) ? + user_entry->pw_shell : + user_entry->pw_dir; } D(("Exit.")); - return retval; + return itemval; } -static int _expand_arg(pam_handle_t *pamh, char **value) +static int +_expand_arg(pam_handle_t *pamh, char **value) { const char *orig=*value, *tmpptr=NULL; char *ptr; /* @@ -679,55 +498,96 @@ static int _expand_arg(pam_handle_t *pamh, char **value) return PAM_SUCCESS; } -static const char * _pam_get_item_byname(pam_handle_t *pamh, const char *name) +static int +_check_var(pam_handle_t *pamh, VAR *var) { /* - * This function just allows me to use names as given in the config - * file and translate them into the appropriate PAM_ITEM macro + * Examine the variable and determine what action to take. + * Returns DEFINE_VAR, UNDEFINE_VAR depending on action to take + * or a PAM_* error code if passed back from other routines + * + * if no DEFAULT provided, the empty string is assumed + * if no OVERRIDE provided, the empty string is assumed + * if DEFAULT= and OVERRIDE evaluates to the empty string, + * this variable should be undefined + * if DEFAULT="" and OVERRIDE evaluates to the empty string, + * this variable should be defined with no value + * if OVERRIDE=value and value turns into the empty string, DEFAULT is used + * + * If DEFINE_VAR is to be returned, the correct value to define will + * be pointed to by var->value */ - int item; - const void *itemval; + int retval; D(("Called.")); - if (strcmp(name, "PAM_USER") == 0 || strcmp(name, "HOME") == 0 || strcmp(name, "SHELL") == 0) { - item = PAM_USER; - } else if (strcmp(name, "PAM_USER_PROMPT") == 0) { - item = PAM_USER_PROMPT; - } else if (strcmp(name, "PAM_TTY") == 0) { - item = PAM_TTY; - } else if (strcmp(name, "PAM_RUSER") == 0) { - item = PAM_RUSER; - } else if (strcmp(name, "PAM_RHOST") == 0) { - item = PAM_RHOST; - } else { - D(("Unknown PAM_ITEM: <%s>", name)); - pam_syslog (pamh, LOG_ERR, "Unknown PAM_ITEM: <%s>", name); - return NULL; - } - if (pam_get_item(pamh, item, &itemval) != PAM_SUCCESS) { - D(("pam_get_item failed")); - return NULL; /* let pam_get_item() log the error */ + /* + * First thing to do is to expand any arguments, but only + * if they are not the special quote values (cause expand_arg + * changes memory). + */ + + if (var->defval && ("e != var->defval) && + ((retval = _expand_arg(pamh, &(var->defval))) != PAM_SUCCESS)) { + return retval; + } + if (var->override && ("e != var->override) && + ((retval = _expand_arg(pamh, &(var->override))) != PAM_SUCCESS)) { + return retval; } - if (itemval && (strcmp(name, "HOME") == 0 || strcmp(name, "SHELL") == 0)) { - struct passwd *user_entry; - user_entry = pam_modutil_getpwnam (pamh, itemval); - if (!user_entry) { - pam_syslog(pamh, LOG_ERR, "No such user!?"); - return NULL; + /* Now its easy */ + + if (var->override && *(var->override)) { + /* if there is a non-empty string in var->override, we use it */ + D(("OVERRIDE variable <%s> being used: <%s>", var->name, var->override)); + var->value = var->override; + retval = DEFINE_VAR; + } else { + + var->value = var->defval; + if ("e == var->defval) { + /* + * This means that the empty string was given for defval value + * which indicates that a variable should be defined with no value + */ + D(("An empty variable: <%s>", var->name)); + retval = DEFINE_VAR; + } else if (var->defval) { + D(("DEFAULT variable <%s> being used: <%s>", var->name, var->defval)); + retval = DEFINE_VAR; + } else { + D(("UNDEFINE variable <%s>", var->name)); + retval = UNDEFINE_VAR; } - return (strcmp(name, "SHELL") == 0) ? - user_entry->pw_shell : - user_entry->pw_dir; } D(("Exit.")); - return itemval; + return retval; +} + +static void +_clean_var(VAR *var) +{ + if (var->name) { + free(var->name); + } + if (var->defval && ("e != var->defval)) { + free(var->defval); + } + if (var->override && ("e != var->override)) { + free(var->override); + } + var->name = NULL; + var->value = NULL; /* never has memory specific to it */ + var->defval = NULL; + var->override = NULL; + return; } -static int _define_var(pam_handle_t *pamh, int ctrl, VAR *var) +static int +_define_var(pam_handle_t *pamh, int ctrl, VAR *var) { /* We have a variable to define, this is a simple function */ @@ -749,7 +609,8 @@ static int _define_var(pam_handle_t *pamh, int ctrl, VAR *var) return retval; } -static int _undefine_var(pam_handle_t *pamh, int ctrl, VAR *var) +static int +_undefine_var(pam_handle_t *pamh, int ctrl, VAR *var) { /* We have a variable to undefine, this is a simple function */ @@ -760,25 +621,159 @@ static int _undefine_var(pam_handle_t *pamh, int ctrl, VAR *var) return pam_putenv(pamh, var->name); } -static void _clean_var(VAR *var) +static int +_parse_config_file(pam_handle_t *pamh, int ctrl, const char *file) { - if (var->name) { - free(var->name); + int retval; + char buffer[BUF_SIZE]; + FILE *conf; + VAR Var, *var=&Var; + + D(("Called.")); + + var->name=NULL; var->defval=NULL; var->override=NULL; + + D(("Config file name is: %s", file)); + + /* + * Lets try to open the config file, parse it and process + * any variables found. + */ + + if ((conf = fopen(file,"r")) == NULL) { + pam_syslog(pamh, LOG_ERR, "Unable to open config file: %s: %m", file); + return PAM_IGNORE; } - if (var->defval && ("e != var->defval)) { - free(var->defval); + + /* _pam_assemble_line will provide a complete line from the config file, + * with all comments removed and any escaped newlines fixed up + */ + + while (( retval = _assemble_line(conf, buffer, BUF_SIZE)) > 0) { + D(("Read line: %s", buffer)); + + if ((retval = _parse_line(pamh, buffer, var)) == GOOD_LINE) { + retval = _check_var(pamh, var); + + if (DEFINE_VAR == retval) { + retval = _define_var(pamh, ctrl, var); + + } else if (UNDEFINE_VAR == retval) { + retval = _undefine_var(pamh, ctrl, var); + } + } + if (PAM_SUCCESS != retval && ILLEGAL_VAR != retval + && BAD_LINE != retval && PAM_BAD_ITEM != retval) break; + + _clean_var(var); + + } /* while */ + + (void) fclose(conf); + + /* tidy up */ + _clean_var(var); /* We could have got here prematurely, + * this is safe though */ + D(("Exit.")); + return (retval != 0 ? PAM_ABORT : PAM_SUCCESS); +} + +static int +_parse_env_file(pam_handle_t *pamh, int ctrl, const char *file) +{ + int retval=PAM_SUCCESS, i, t; + char buffer[BUF_SIZE], *key, *mark; + FILE *conf; + + D(("Env file name is: %s", file)); + + if ((conf = fopen(file,"r")) == NULL) { + pam_syslog(pamh, LOG_ERR, "Unable to open env file: %s: %m", file); + return PAM_IGNORE; } - if (var->override && ("e != var->override)) { - free(var->override); + + while (_assemble_line(conf, buffer, BUF_SIZE) > 0) { + D(("Read line: %s", buffer)); + key = buffer; + + /* skip leading white space */ + key += strspn(key, " \n\t"); + + /* skip blanks lines and comments */ + if (key[0] == '#') + continue; + + /* skip over "export " if present so we can be compat with + bash type declarations */ + if (strncmp(key, "export ", (size_t) 7) == 0) + key += 7; + + /* now find the end of value */ + mark = key; + while(mark[0] != '\n' && mark[0] != '#' && mark[0] != '\0') + mark++; + if (mark[0] != '\0') + mark[0] = '\0'; + + /* + * sanity check, the key must be alphanumeric + */ + + if (key[0] == '=') { + pam_syslog(pamh, LOG_ERR, + "missing key name '%s' in %s', ignoring", + key, file); + continue; + } + + for ( i = 0 ; key[i] != '=' && key[i] != '\0' ; i++ ) + if (!isalnum(key[i]) && key[i] != '_') { + pam_syslog(pamh, LOG_ERR, + "non-alphanumeric key '%s' in %s', ignoring", + key, file); + break; + } + /* non-alphanumeric key, ignore this line */ + if (key[i] != '=' && key[i] != '\0') + continue; + + /* now we try to be smart about quotes around the value, + but not too smart, we can't get all fancy with escaped + values like bash */ + if (key[i] == '=' && (key[++i] == '\"' || key[i] == '\'')) { + for ( t = i+1 ; key[t] != '\0' ; t++) + if (key[t] != '\"' && key[t] != '\'') + key[i++] = key[t]; + else if (key[t+1] != '\0') + key[i++] = key[t]; + key[i] = '\0'; + } + + /* if this is a request to delete a variable, check that it's + actually set first, so we don't get a vague error back from + pam_putenv() */ + for (i = 0; key[i] != '=' && key[i] != '\0'; i++); + + if (key[i] == '\0' && !pam_getenv(pamh,key)) + continue; + + /* set the env var, if it fails, we break out of the loop */ + retval = pam_putenv(pamh, key); + if (retval != PAM_SUCCESS) { + D(("error setting env \"%s\"", key)); + break; + } else if (ctrl & PAM_DEBUG_ARG) { + pam_syslog(pamh, LOG_DEBUG, + "pam_putenv(\"%s\")", key); + } } - var->name = NULL; - var->value = NULL; /* never has memory specific to it */ - var->defval = NULL; - var->override = NULL; - return; -} + (void) fclose(conf); + /* tidy up */ + D(("Exit.")); + return retval; +} /* --- authentication management functions (only) --- */ |