diff options
author | Steve Langasek <steve.langasek@canonical.com> | 2020-08-11 14:54:29 -0700 |
---|---|---|
committer | Steve Langasek <steve.langasek@canonical.com> | 2020-08-11 14:54:29 -0700 |
commit | f6d08ed47a3da3c08345bce2ca366e961c52ad7c (patch) | |
tree | dcbd0efb229b17f696f7195671f05b354b4f70fc /modules/pam_env/pam_env.c | |
parent | 668b13da8f830c38388cecac45539972e80cb246 (diff) | |
parent | 9e5bea9e146dee574796259ca464ad2435be3590 (diff) | |
download | pam-f6d08ed47a3da3c08345bce2ca366e961c52ad7c.tar.gz pam-f6d08ed47a3da3c08345bce2ca366e961c52ad7c.tar.bz2 pam-f6d08ed47a3da3c08345bce2ca366e961c52ad7c.zip |
New upstream version 1.4.0
Diffstat (limited to 'modules/pam_env/pam_env.c')
-rw-r--r-- | modules/pam_env/pam_env.c | 123 |
1 files changed, 66 insertions, 57 deletions
diff --git a/modules/pam_env/pam_env.c b/modules/pam_env/pam_env.c index 3846e359..79d43722 100644 --- a/modules/pam_env/pam_env.c +++ b/modules/pam_env/pam_env.c @@ -1,6 +1,6 @@ -/* pam_env module */ - /* + * pam_env module + * * Written by Dave Kinchlea <kinch@kinch.ark.com> 1997/01/31 * Inspired by Andrew Morgan <morgan@kernel.org>, who also supplied the * template for this file (via pam_mail) @@ -10,7 +10,7 @@ #define DEFAULT_READ_ENVFILE 1 #define DEFAULT_USER_ENVFILE ".pam_environment" -#define DEFAULT_USER_READ_ENVFILE 1 +#define DEFAULT_USER_READ_ENVFILE 0 #include "config.h" @@ -26,22 +26,11 @@ #include <sys/types.h> #include <unistd.h> -/* - * here, we make a definition for the externally accessible function - * in this file (this definition is required for static a module - * but strongly encouraged generally) it is used to instruct the - * modules include file to define the function prototypes. - */ - -#define PAM_SM_AUTH /* This is primarily a AUTH_SETCRED module */ -#define PAM_SM_SESSION /* But I like to be friendly */ -#define PAM_SM_PASSWORD /* "" */ -#define PAM_SM_ACCOUNT /* "" */ - #include <security/pam_modules.h> #include <security/pam_modutil.h> #include <security/_pam_macros.h> #include <security/pam_ext.h> +#include "pam_inline.h" /* This little structure makes it easier to keep variables together */ @@ -52,7 +41,7 @@ typedef struct var { char *override; } VAR; -#define BUF_SIZE 1024 +#define BUF_SIZE 8192 #define MAX_ENV 8192 #define GOOD_LINE 0 @@ -63,7 +52,7 @@ typedef struct var { #define ILLEGAL_VAR 103 static int _assemble_line(FILE *, char *, int); -static int _parse_line(const pam_handle_t *, char *, VAR *); +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 **); @@ -71,8 +60,8 @@ 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 flag used to designate an empty string */ -static char quote='Z'; +/* This is a special value used to designate an empty string */ +static char quote='\0'; /* argument parsing */ @@ -93,40 +82,41 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv, /* step through arguments */ for (; argc-- > 0; ++argv) { + const char *str; /* generic options */ if (!strcmp(*argv,"debug")) ctrl |= PAM_DEBUG_ARG; - else if (!strncmp(*argv,"conffile=",9)) { - if ((*argv)[9] == '\0') { + else if ((str = pam_str_skip_prefix(*argv, "conffile=")) != NULL) { + if (str[0] == '\0') { pam_syslog(pamh, LOG_ERR, "conffile= specification missing argument - ignored"); } else { - *conffile = 9+*argv; + *conffile = str; D(("new Configuration File: %s", *conffile)); } - } else if (!strncmp(*argv,"envfile=",8)) { - if ((*argv)[8] == '\0') { + } else if ((str = pam_str_skip_prefix(*argv, "envfile=")) != NULL) { + if (str[0] == '\0') { pam_syslog (pamh, LOG_ERR, "envfile= specification missing argument - ignored"); } else { - *envfile = 8+*argv; + *envfile = str; D(("new Env File: %s", *envfile)); } - } else if (!strncmp(*argv,"user_envfile=",13)) { - if ((*argv)[13] == '\0') { + } else if ((str = pam_str_skip_prefix(*argv, "user_envfile=")) != NULL) { + if (str[0] == '\0') { pam_syslog (pamh, LOG_ERR, "user_envfile= specification missing argument - ignored"); } else { - *user_envfile = 13+*argv; + *user_envfile = str; D(("new User Env File: %s", *user_envfile)); } - } else if (!strncmp(*argv,"readenv=",8)) - *readenv = atoi(8+*argv); - else if (!strncmp(*argv,"user_readenv=",13)) - *user_readenv = atoi(13+*argv); - else + } else if ((str = pam_str_skip_prefix(*argv, "readenv=")) != NULL) { + *readenv = atoi(str); + } else if ((str = pam_str_skip_prefix(*argv, "user_readenv=")) != NULL) { + *user_readenv = atoi(str); + } else pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv); } @@ -228,9 +218,16 @@ _parse_env_file(pam_handle_t *pamh, int ctrl, const char *file) mark[0] = '\0'; /* - * sanity check, the key must be alpha-numeric + * 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, @@ -282,7 +279,7 @@ _parse_env_file(pam_handle_t *pamh, int ctrl, const char *file) /* * This is where we read a line of the PAM config file. The line may be - * preceeded by lines of comments and also extended with "\\\n" + * preceded by lines of comments and also extended with "\\\n" */ static int _assemble_line(FILE *f, char *buffer, int buf_len) @@ -310,6 +307,14 @@ static int _assemble_line(FILE *f, char *buffer, int buf_len) return 0; } } + if (p[0] == '\0') { + D(("_assemble_line: corrupted or binary file")); + return -1; + } + if (p[strlen(p)-1] != '\n') { + D(("_assemble_line: line too long")); + return -1; + } /* skip leading spaces --- line may be blank */ @@ -366,7 +371,7 @@ static int _assemble_line(FILE *f, char *buffer, int buf_len) } static int -_parse_line (const pam_handle_t *pamh, char *buffer, VAR *var) +_parse_line (const pam_handle_t *pamh, const char *buffer, VAR *var) { /* * parse buffer into var, legal syntax is @@ -377,7 +382,8 @@ _parse_line (const pam_handle_t *pamh, char *buffer, VAR *var) */ int length, quoteflg=0; - char *ptr, **valptr, *tmpptr; + const char *ptr, *tmpptr; + char **valptr; D(("Called buffer = <%s>", buffer)); @@ -405,12 +411,12 @@ _parse_line (const pam_handle_t *pamh, char *buffer, VAR *var) while ((length = strspn(ptr, " \t")) > 0) { ptr += length; /* remove leading whitespace */ D((ptr)); - if (strncmp(ptr,"DEFAULT=",8) == 0) { - ptr+=8; + if ((tmpptr = pam_str_skip_prefix(ptr, "DEFAULT=")) != NULL) { + ptr = tmpptr; D(("Default arg found: <%s>", ptr)); valptr=&(var->defval); - } else if (strncmp(ptr, "OVERRIDE=", 9) == 0) { - ptr+=9; + } else if ((tmpptr = pam_str_skip_prefix(ptr, "OVERRIDE=")) != NULL) { + ptr = tmpptr; D(("Override arg found: <%s>", ptr)); valptr=&(var->override); } else { @@ -500,7 +506,7 @@ static int _check_var(pam_handle_t *pamh, VAR *var) /* Now its easy */ - if (var->override && *(var->override) && "e != var->override) { + 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; @@ -513,7 +519,6 @@ static int _check_var(pam_handle_t *pamh, VAR *var) * This means that the empty string was given for defval value * which indicates that a variable should be defined with no value */ - *var->defval = '\0'; D(("An empty variable: <%s>", var->name)); retval = DEFINE_VAR; } else if (var->defval) { @@ -543,9 +548,11 @@ static int _expand_arg(pam_handle_t *pamh, char **value) /* I know this shouldn't be hard-coded but it's so much easier this way */ char tmp[MAX_ENV]; + size_t idx; D(("Remember to initialize tmp!")); memset(tmp, 0, MAX_ENV); + idx = 0; /* * (possibly non-existent) environment variables can be used as values @@ -563,8 +570,8 @@ static int _expand_arg(pam_handle_t *pamh, char **value) pam_syslog(pamh, LOG_ERR, "Unrecognized escaped character: <%c> - ignoring", *orig); - } else if ((strlen(tmp) + 1) < MAX_ENV) { - tmp[strlen(tmp)] = *orig++; /* Note the increment */ + } else if (idx + 1 < MAX_ENV) { + tmp[idx++] = *orig++; /* Note the increment */ } else { /* is it really a good idea to try to log this? */ D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); @@ -580,8 +587,8 @@ static int _expand_arg(pam_handle_t *pamh, char **value) " <%s> - ignoring", orig)); pam_syslog(pamh, LOG_ERR, "Expandable variables must be wrapped in {}" " <%s> - ignoring", orig); - if ((strlen(tmp) + 1) < MAX_ENV) { - tmp[strlen(tmp)] = *orig++; /* Note the increment */ + if (idx + 1 < MAX_ENV) { + tmp[idx++] = *orig++; /* Note the increment */ } continue; } else { @@ -625,8 +632,10 @@ static int _expand_arg(pam_handle_t *pamh, char **value) } /* switch */ if (tmpptr) { - if ((strlen(tmp) + strlen(tmpptr)) < MAX_ENV) { - strcat(tmp, tmpptr); + size_t len = strlen(tmpptr); + if (idx + len < MAX_ENV) { + strcpy(tmp + idx, tmpptr); + idx += len; } else { /* is it really a good idea to try to log this? */ D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); @@ -637,8 +646,8 @@ static int _expand_arg(pam_handle_t *pamh, char **value) } } /* if ('{' != *orig++) */ } else { /* if ( '$' == *orig || '@' == *orig) */ - if ((strlen(tmp) + 1) < MAX_ENV) { - tmp[strlen(tmp)] = *orig++; /* Note the increment */ + if (idx + 1 < MAX_ENV) { + tmp[idx++] = *orig++; /* Note the increment */ } else { /* is it really a good idea to try to log this? */ D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); @@ -649,17 +658,17 @@ static int _expand_arg(pam_handle_t *pamh, char **value) } } /* for (;*orig;) */ - if (strlen(tmp) > strlen(*value)) { + if (idx > strlen(*value)) { free(*value); - if ((*value = malloc(strlen(tmp) +1)) == NULL) { - D(("Couldn't malloc %d bytes for expanded var", strlen(tmp)+1)); + if ((*value = malloc(idx + 1)) == NULL) { + D(("Couldn't malloc %d bytes for expanded var", idx + 1)); pam_syslog (pamh, LOG_CRIT, "Couldn't malloc %lu bytes for expanded var", - (unsigned long)strlen(tmp)+1); + (unsigned long)idx+1); return PAM_BUF_ERR; } } strcpy(*value, tmp); - memset(tmp,'\0',sizeof(tmp)); + memset(tmp, '\0', sizeof(tmp)); D(("Exit.")); return PAM_SUCCESS; @@ -699,7 +708,7 @@ static const char * _pam_get_item_byname(pam_handle_t *pamh, const char *name) if (itemval && (strcmp(name, "HOME") == 0 || strcmp(name, "SHELL") == 0)) { struct passwd *user_entry; - user_entry = pam_modutil_getpwnam (pamh, (char *) itemval); + user_entry = pam_modutil_getpwnam (pamh, itemval); if (!user_entry) { pam_syslog(pamh, LOG_ERR, "No such user!?"); return NULL; |