From 5c58f28cb4fa9965d5755b0eb1d0fcbd593b51ca Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 11 Nov 2010 16:15:52 +0000 Subject: Relevant BUGIDs: Purpose of commit: bugfix Commit summary: --------------- 2010-11-11 Tomas Mraz * modules/pam_selinux/pam_selinux.c (pam_sm_open_session): Fix potential use after free in case SELinux is misconfigured. * modules/pam_namespace/pam_namespace.c (process_line): Fix memory leak when parsing empty config file lines. --- modules/pam_namespace/pam_namespace.c | 8 ++++---- modules/pam_selinux/pam_selinux.c | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'modules') diff --git a/modules/pam_namespace/pam_namespace.c b/modules/pam_namespace/pam_namespace.c index a13f9599..baa7f85a 100644 --- a/modules/pam_namespace/pam_namespace.c +++ b/modules/pam_namespace/pam_namespace.c @@ -307,10 +307,6 @@ static int process_line(char *line, const char *home, const char *rhome, const char *rvar_values[] = {rhome, idata->ruser}; int len; - poly = calloc(1, sizeof(*poly)); - if (poly == NULL) - goto erralloc; - /* * skip the leading white space */ @@ -337,6 +333,10 @@ static int process_line(char *line, const char *home, const char *rhome, if (line[0] == 0) return 0; + poly = calloc(1, sizeof(*poly)); + if (poly == NULL) + goto erralloc; + /* * Initialize and scan the five strings from the line from the * namespace configuration file. diff --git a/modules/pam_selinux/pam_selinux.c b/modules/pam_selinux/pam_selinux.c index 64fabafd..c31278e9 100644 --- a/modules/pam_selinux/pam_selinux.c +++ b/modules/pam_selinux/pam_selinux.c @@ -642,10 +642,10 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, if (debug) pam_syslog(pamh, LOG_DEBUG, "Username= %s SELinux User = %s Level= %s", username, seuser, level); - free(seuser); free(level); } if (num_contexts > 0) { + free(seuser); default_user_context=strdup(contextlist[0]); freeconary(contextlist); if (default_user_context == NULL) { @@ -672,7 +672,10 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, } } else { - user_context = manual_context(pamh,seuser,debug); + if (seuser != NULL) { + user_context = manual_context(pamh,seuser,debug); + free(seuser); + } if (user_context == NULL) { pam_syslog (pamh, LOG_ERR, "Unable to get valid context for %s", username); -- cgit v1.2.3 From 7aba472d5255f0e64a5ea42221c0d5f225f3b42d Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 16 Nov 2010 09:51:50 +0000 Subject: Relevant BUGIDs: Purpose of commit: bugfix Commit summary: --------------- 2010-11-16 Tomas Mraz * modules/pam_pwhistory/pam_pwhistory.c (pam_sm_chauthtok): Remove dead and duplicate code. Return PAM_INCOMPLETE instead of PAM_CONV_AGAIN. --- modules/pam_pwhistory/pam_pwhistory.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'modules') diff --git a/modules/pam_pwhistory/pam_pwhistory.c b/modules/pam_pwhistory/pam_pwhistory.c index 0f6ffca3..9b588958 100644 --- a/modules/pam_pwhistory/pam_pwhistory.c +++ b/modules/pam_pwhistory/pam_pwhistory.c @@ -187,12 +187,13 @@ pam_sm_chauthtok (pam_handle_t *pamh, int flags, int argc, const char **argv) { retval = pam_get_authtok (pamh, PAM_AUTHTOK, &newpass, NULL); if (retval != PAM_SUCCESS && retval != PAM_TRY_AGAIN) - return retval; + { + if (retval == PAM_CONV_AGAIN) + retval = PAM_INCOMPLETE; + return retval; + } tries++; - if (newpass == NULL || retval == PAM_TRY_AGAIN) - continue; - if (options.debug) { if (newpass) @@ -201,12 +202,8 @@ pam_sm_chauthtok (pam_handle_t *pamh, int flags, int argc, const char **argv) pam_syslog (pamh, LOG_DEBUG, "got no auth token"); } - if (retval != PAM_SUCCESS || newpass == NULL) - { - if (retval == PAM_CONV_AGAIN) - retval = PAM_INCOMPLETE; - return retval; - } + if (newpass == NULL || retval == PAM_TRY_AGAIN) + continue; if (options.debug) pam_syslog (pamh, LOG_DEBUG, "check against old password file"); @@ -219,7 +216,6 @@ pam_sm_chauthtok (pam_handle_t *pamh, int flags, int argc, const char **argv) newpass = NULL; /* Remove password item, else following module will use it */ pam_set_item (pamh, PAM_AUTHTOK, (void *) NULL); - continue; } } @@ -230,8 +226,7 @@ pam_sm_chauthtok (pam_handle_t *pamh, int flags, int argc, const char **argv) return PAM_MAXTRIES; } - /* Remember new password */ - return pam_set_item (pamh, PAM_AUTHTOK, newpass); + return PAM_SUCCESS; } -- cgit v1.2.3 From ff1e893b0e22e6848d78ae8094d1e10e3993ed7b Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 18 Nov 2010 09:37:31 +0000 Subject: Relevant BUGIDs: Purpose of commit: cleanup Commit summary: --------------- 2010-11-18 Tomas Mraz * modules/pam_limits/pam_limits.c (pam_parse,pam_sm_open_session): Drop obsolete and broken option change_uid. * modules/pam_limits/pam_limits.8.xml: Likewise. --- modules/pam_limits/pam_limits.8.xml | 16 ---------------- modules/pam_limits/pam_limits.c | 7 ------- 2 files changed, 23 deletions(-) (limited to 'modules') diff --git a/modules/pam_limits/pam_limits.8.xml b/modules/pam_limits/pam_limits.8.xml index 0be7ef4d..7b944f9e 100644 --- a/modules/pam_limits/pam_limits.8.xml +++ b/modules/pam_limits/pam_limits.8.xml @@ -22,9 +22,6 @@ pam_limits.so - - change_uid - conf=/path/to/limits.conf @@ -70,19 +67,6 @@ OPTIONS - - - - - - - Change real uid to the user for who the limits are set up. Use this - option if you have problems like login not forking a shell for user - who has no processes. Be warned that something else may break when - you do this. - - - diff --git a/modules/pam_limits/pam_limits.c b/modules/pam_limits/pam_limits.c index f446f9e3..79cc717e 100644 --- a/modules/pam_limits/pam_limits.c +++ b/modules/pam_limits/pam_limits.c @@ -103,7 +103,6 @@ struct pam_limit_s { /* argument parsing */ #define PAM_DEBUG_ARG 0x0001 -#define PAM_DO_SETREUID 0x0002 #define PAM_UTMP_EARLY 0x0004 #define PAM_NO_AUDIT 0x0008 @@ -127,8 +126,6 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv, ctrl |= PAM_DEBUG_ARG; } else if (!strncmp(*argv,"conf=",5)) { pl->conf_file = *argv+5; - } else if (!strncmp(*argv,"change_uid",10)) { - ctrl |= PAM_DO_SETREUID; } else if (!strcmp(*argv,"utmp_early")) { ctrl |= PAM_UTMP_EARLY; } else if (!strcmp(*argv,"noaudit")) { @@ -777,10 +774,6 @@ out: return retval; } - if (ctrl & PAM_DO_SETREUID) { - setreuid(pwd->pw_uid, -1); - } - retval = setup_limits(pamh, pwd->pw_name, pwd->pw_uid, ctrl, pl); if (retval & LOGIN_ERR) pam_error(pamh, _("Too many logins for '%s'."), pwd->pw_name); -- cgit v1.2.3 From a56c03f5b878796f8357e1b306b00279350ebf7a Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 24 Nov 2010 08:49:30 +0000 Subject: Relevant BUGIDs: Purpose of commit: docfix Commit summary: --------------- 2010-11-24 Tomas Mraz * modules/pam_limits/limits.conf.5.xml: Document the %group syntax. --- modules/pam_limits/limits.conf.5.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/pam_limits/limits.conf.5.xml b/modules/pam_limits/limits.conf.5.xml index a9757a7f..e9174bc1 100644 --- a/modules/pam_limits/limits.conf.5.xml +++ b/modules/pam_limits/limits.conf.5.xml @@ -53,7 +53,11 @@ the wildcard %, for maxlogins limit only, - can also be used with %group syntax. + can also be used with %group syntax. If the + % wildcard is used alone it is identical + to using * with maxsyslogins limit. With + a group specified after % it limits the total + number of logins of all users that are member of the group. @@ -182,7 +186,7 @@ - maximum number of logins on system + maximum number of all logins on system -- cgit v1.2.3 From 76d789aa7a3ced98ed8421c6c8ed978042ebd477 Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Wed, 24 Nov 2010 12:28:01 +0000 Subject: Relevant BUGIDs: Purpose of commit: new feature Commit summary: --------------- 2010-11-24 Thorsten Kukuk * modules/pam_securetty/pam_securetty.c: Parse console= kernel option, add noconsole option. * modules/pam_securetty/pam_securetty.8.xml: Document new behavior for serial console. Patch from Lennart Poettering. --- modules/pam_securetty/pam_securetty.8.xml | 13 +++++++++++ modules/pam_securetty/pam_securetty.c | 39 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'modules') diff --git a/modules/pam_securetty/pam_securetty.8.xml b/modules/pam_securetty/pam_securetty.8.xml index dd57705b..90d99a3d 100644 --- a/modules/pam_securetty/pam_securetty.8.xml +++ b/modules/pam_securetty/pam_securetty.8.xml @@ -61,6 +61,19 @@ + + + + + + + By default pam_securetty will allow root logins on the + kernel console device, as specified with the console= + switch on the kernel command line. Use this switch to turn + of this behaviour. + + + diff --git a/modules/pam_securetty/pam_securetty.c b/modules/pam_securetty/pam_securetty.c index a3c2010d..99c6371f 100644 --- a/modules/pam_securetty/pam_securetty.c +++ b/modules/pam_securetty/pam_securetty.c @@ -2,6 +2,7 @@ #define SECURETTY_FILE "/etc/securetty" #define TTY_PREFIX "/dev/" +#define CMDLINE_FILE "/proc/cmdline" /* * by Elliot Lee , Red Hat Software. @@ -22,6 +23,7 @@ #include #include #include +#include /* * here, we make a definition for the externally accessible function @@ -38,6 +40,7 @@ #include #define PAM_DEBUG_ARG 0x0001 +#define PAM_NOCONSOLE_ARG 0x0002 static int _pam_parse (const pam_handle_t *pamh, int argc, const char **argv) @@ -51,6 +54,8 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv) if (!strcmp(*argv,"debug")) ctrl |= PAM_DEBUG_ARG; + else if (!strcmp(*argv, "noconsole")) + ctrl |= PAM_NOCONSOLE_ARG; else { pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv); } @@ -144,6 +149,40 @@ securetty_perform_check (pam_handle_t *pamh, int ctrl, } fclose(ttyfile); + if (retval && !(ctrl & PAM_NOCONSOLE_ARG)) { + FILE *cmdlinefile; + + /* Allow access from the kernel console, if enabled */ + cmdlinefile = fopen(CMDLINE_FILE, "r"); + + if (cmdlinefile != NULL) { + char line[LINE_MAX], *p; + + line[0] = 0; + fgets(line, sizeof(line), cmdlinefile); + fclose(cmdlinefile); + + for (p = line; p; p = strstr(p+1, "console=")) { + char *e; + + /* Test whether this is a beginning of a word? */ + if (p > line && p[-1] != ' ') + continue; + + /* Ist this our console? */ + if (strncmp(p + 8, uttyname, strlen(uttyname))) + continue; + + /* Is there any garbage after the TTY name? */ + e = p + 8 + strlen(uttyname); + if (*e == ',' || *e == ' ' || *e == '\n' || *e == 0) { + retval = 0; + break; + } + } + } + } + if (retval) { pam_syslog(pamh, LOG_WARNING, "access denied: tty '%s' is not secure !", uttyname); -- cgit v1.2.3 From ecb0e6385aace15a6dce31749b34962058f2ebab Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 25 Nov 2010 16:58:59 +0000 Subject: Relevant BUGIDs: Purpose of commit: docfix Commit summary: --------------- 2010-11-25 Tomas Mraz * modules/pam_securetty/pam_securetty.8.xml: Improve documentation of the kernel console feature and the noconsole option. --- modules/pam_securetty/pam_securetty.8.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'modules') diff --git a/modules/pam_securetty/pam_securetty.8.xml b/modules/pam_securetty/pam_securetty.8.xml index 90d99a3d..c5d6c5fe 100644 --- a/modules/pam_securetty/pam_securetty.8.xml +++ b/modules/pam_securetty/pam_securetty.8.xml @@ -33,7 +33,9 @@ user is logging in on a "secure" tty, as defined by the listing in /etc/securetty. pam_securetty also checks to make sure that /etc/securetty is a plain - file and not world writable. + file and not world writable. It will also allow root logins on + the tty specified with switch on the + kernel command line. This module has no effect on non-root users and requires that the @@ -67,10 +69,9 @@ - By default pam_securetty will allow root logins on the - kernel console device, as specified with the console= - switch on the kernel command line. Use this switch to turn - of this behaviour. + Do not automatically allow root logins on the kernel console + device, as specified on the kernel command line, if it is + not also specified in the /etc/securetty file. -- cgit v1.2.3 From 19eb6b29412491d272210938259c574bf9728d94 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 14 Dec 2010 08:40:40 +0000 Subject: Relevant BUGIDs: Purpose of commit: new feature Commit summary: --------------- 2010-12-14 Tomas Mraz * modules/pam_limits/pam_limits.c (parse_uid_range): New function to parse the range of uids or gids. (parse_config_file): Call parse_uid_range() and if uid/gid range is identified, setup the limits if the range matches. New parameters containing user's uid and primary gid. (pam_sm_open_session): Pass the user's uid and primary gid to parse_config_file(). * modules/pam_limits/limits.conf.5.xml: Document the uid/gid ranges. --- modules/pam_limits/limits.conf.5.xml | 32 +++++- modules/pam_limits/pam_limits.c | 198 ++++++++++++++++++++++++++++++----- 2 files changed, 204 insertions(+), 26 deletions(-) (limited to 'modules') diff --git a/modules/pam_limits/limits.conf.5.xml b/modules/pam_limits/limits.conf.5.xml index e9174bc1..a1e84102 100644 --- a/modules/pam_limits/limits.conf.5.xml +++ b/modules/pam_limits/limits.conf.5.xml @@ -60,6 +60,33 @@ number of logins of all users that are member of the group. + + + an uid range specified as <min_uid>:<max_uid>. If min_uid + is omitted, the match is exact for the max_uid. If max_uid is omitted, all + uids greater than or equal min_uid match. + + + + + a gid range specified as @<min_gid>:<max_gid>. If min_gid + is omitted, the match is exact for the max_gid. If max_gid is omitted, all + gids greater than or equal min_gid match. For the exact match all groups including + the user's supplementary groups are examined. For the range matches only + the user's primary group is examined. + + + + + a gid specified as %:<gid> applicable + to maxlogins limit only. It limits the total number of logins of all users + that are member of the group with the specified gid. + + @@ -276,12 +303,15 @@ * soft core 0 -* hard rss 10000 +* hard nofile 512 @student hard nproc 20 @faculty soft nproc 20 @faculty hard nproc 50 ftp hard nproc 0 @student - maxlogins 4 +:123 hard cpu 5000 +@500: soft cpu 10000 +600:700 hard locks 10 diff --git a/modules/pam_limits/pam_limits.c b/modules/pam_limits/pam_limits.c index 79cc717e..88146523 100644 --- a/modules/pam_limits/pam_limits.c +++ b/modules/pam_limits/pam_limits.c @@ -55,6 +55,12 @@ #define LIMITS_DEF_DEFAULT 4 /* limit was set by an default entry */ #define LIMITS_DEF_NONE 5 /* this limit was not set yet */ +#define LIMIT_RANGE_ERR -1 /* error in specified uid/gid range */ +#define LIMIT_RANGE_NONE 0 /* no range specified */ +#define LIMIT_RANGE_ONE 1 /* exact uid/gid specified (:max_uid)*/ +#define LIMIT_RANGE_MIN 2 /* only minimum uid/gid specified (min_uid:) */ +#define LIMIT_RANGE_MM 3 /* both min and max uid/gid specified (min_uid:max_uid) */ + static const char *limits_def_names[] = { "USER", "GROUP", @@ -520,8 +526,57 @@ process_limit (const pam_handle_t *pamh, int source, const char *lim_type, return; } -static int parse_config_file(pam_handle_t *pamh, const char *uname, int ctrl, - struct pam_limit_s *pl) +static int +parse_uid_range(pam_handle_t *pamh, const char *domain, + uid_t *min_uid, uid_t *max_uid) +{ + const char *range = domain; + char *pmax; + char *endptr; + int rv = LIMIT_RANGE_MM; + + if ((pmax=strchr(range, ':')) == NULL) + return LIMIT_RANGE_NONE; + ++pmax; + + if (range[0] == '@' || range[0] == '%') + ++range; + + if (range[0] == ':') + rv = LIMIT_RANGE_ONE; + else { + errno = 0; + *min_uid = strtoul (range, &endptr, 10); + if (errno != 0 || (range == endptr) || *endptr != ':') { + pam_syslog(pamh, LOG_DEBUG, + "wrong min_uid/gid value in '%s'", domain); + return LIMIT_RANGE_ERR; + } + } + + if (*pmax == '\0') { + if (rv == LIMIT_RANGE_ONE) + return LIMIT_RANGE_ERR; + else + return LIMIT_RANGE_MIN; + } + + errno = 0; + *max_uid = strtoul (pmax, &endptr, 10); + if (errno != 0 || (pmax == endptr) || *endptr != '\0') { + pam_syslog(pamh, LOG_DEBUG, + "wrong max_uid/gid value in '%s'", domain); + return LIMIT_RANGE_ERR; + } + + if (rv == LIMIT_RANGE_ONE) + *min_uid = *max_uid; + return rv; +} + +static int +parse_config_file(pam_handle_t *pamh, const char *uname, uid_t uid, gid_t gid, + int ctrl, struct pam_limit_s *pl) { FILE *fil; char buf[LINE_LENGTH]; @@ -543,8 +598,10 @@ static int parse_config_file(pam_handle_t *pamh, const char *uname, int ctrl, char item[LINE_LENGTH]; char value[LINE_LENGTH]; int i; + int rngtype; size_t j; char *tptr,*line; + uid_t min_uid = (uid_t)-1, max_uid = (uid_t)-1; line = buf; /* skip the leading white space */ @@ -572,6 +629,11 @@ static int parse_config_file(pam_handle_t *pamh, const char *uname, int ctrl, for(j=0; j < strlen(ltype); j++) ltype[j]=tolower(ltype[j]); + if ((rngtype=parse_uid_range(pamh, domain, &min_uid, &max_uid)) < 0) { + pam_syslog(pamh, LOG_WARNING, "invalid uid range '%s' - skipped", domain); + continue; + } + if (i == 4) { /* a complete line */ for(j=0; j < strlen(item); j++) item[j]=tolower(item[j]); @@ -581,47 +643,133 @@ static int parse_config_file(pam_handle_t *pamh, const char *uname, int ctrl, if (strcmp(uname, domain) == 0) /* this user have a limit */ process_limit(pamh, LIMITS_DEF_USER, ltype, item, value, ctrl, pl); else if (domain[0]=='@') { - if (ctrl & PAM_DEBUG_ARG) { + if (ctrl & PAM_DEBUG_ARG) { pam_syslog(pamh, LOG_DEBUG, "checking if %s is in group %s", uname, domain + 1); - } - if (pam_modutil_user_in_group_nam_nam(pamh, uname, domain+1)) - process_limit(pamh, LIMITS_DEF_GROUP, ltype, item, value, ctrl, + } + switch(rngtype) { + case LIMIT_RANGE_NONE: + if (pam_modutil_user_in_group_nam_nam(pamh, uname, domain+1)) + process_limit(pamh, LIMITS_DEF_GROUP, ltype, item, value, ctrl, + pl); + break; + case LIMIT_RANGE_ONE: + if (pam_modutil_user_in_group_nam_gid(pamh, uname, (gid_t)max_uid)) + process_limit(pamh, LIMITS_DEF_GROUP, ltype, item, value, ctrl, pl); + break; + case LIMIT_RANGE_MM: + if (gid > (gid_t)max_uid) + break; + /* fallthrough */ + case LIMIT_RANGE_MIN: + if (gid >= (gid_t)min_uid) + process_limit(pamh, LIMITS_DEF_GROUP, ltype, item, value, ctrl, + pl); + } } else if (domain[0]=='%') { - if (ctrl & PAM_DEBUG_ARG) { + if (ctrl & PAM_DEBUG_ARG) { pam_syslog(pamh, LOG_DEBUG, "checking if %s is in group %s", uname, domain + 1); - } - if (strcmp(domain,"%") == 0) - process_limit(pamh, LIMITS_DEF_ALL, ltype, item, value, ctrl, - pl); - else if (pam_modutil_user_in_group_nam_nam(pamh, uname, domain+1)) { - strcpy(pl->login_group, domain+1); - process_limit(pamh, LIMITS_DEF_ALLGROUP, ltype, item, value, ctrl, - pl); } - } else if (strcmp(domain, "*") == 0) - process_limit(pamh, LIMITS_DEF_DEFAULT, ltype, item, value, ctrl, - pl); + switch(rngtype) { + case LIMIT_RANGE_NONE: + if (strcmp(domain,"%") == 0) + process_limit(pamh, LIMITS_DEF_ALL, ltype, item, value, ctrl, + pl); + else if (pam_modutil_user_in_group_nam_nam(pamh, uname, domain+1)) { + strcpy(pl->login_group, domain+1); + process_limit(pamh, LIMITS_DEF_ALLGROUP, ltype, item, value, ctrl, + pl); + } + break; + case LIMIT_RANGE_ONE: + if (pam_modutil_user_in_group_nam_gid(pamh, uname, (gid_t)max_uid)) { + struct group *grp; + grp = pam_modutil_getgrgid(pamh, (gid_t)max_uid); + strncpy(pl->login_group, grp->gr_name, sizeof(pl->login_group)); + pl->login_group[sizeof(pl->login_group)-1] = '\0'; + process_limit(pamh, LIMITS_DEF_ALLGROUP, ltype, item, value, ctrl, + pl); + } + break; + case LIMIT_RANGE_MIN: + case LIMIT_RANGE_MM: + pam_syslog(pamh, LOG_WARNING, "range unsupported for %%group matching - ignored"); + } + } else { + switch(rngtype) { + case LIMIT_RANGE_NONE: + if (strcmp(domain, "*") == 0) + process_limit(pamh, LIMITS_DEF_DEFAULT, ltype, item, value, ctrl, + pl); + break; + case LIMIT_RANGE_ONE: + if (uid != max_uid) + break; + /* fallthrough */ + case LIMIT_RANGE_MM: + if (uid > max_uid) + break; + /* fallthrough */ + case LIMIT_RANGE_MIN: + if (uid >= min_uid) + process_limit(pamh, LIMITS_DEF_USER, ltype, item, value, ctrl, pl); + } + } } else if (i == 2 && ltype[0] == '-') { /* Probably a no-limit line */ if (strcmp(uname, domain) == 0) { if (ctrl & PAM_DEBUG_ARG) { pam_syslog(pamh, LOG_DEBUG, "no limits for '%s'", uname); } - fclose(fil); - return PAM_IGNORE; - } else if (domain[0] == '@' && pam_modutil_user_in_group_nam_nam(pamh, uname, domain+1)) { + } else if (domain[0] == '@') { + switch(rngtype) { + case LIMIT_RANGE_NONE: + if (!pam_modutil_user_in_group_nam_nam(pamh, uname, domain+1)) + continue; /* next line */ + break; + case LIMIT_RANGE_ONE: + if (!pam_modutil_user_in_group_nam_gid(pamh, uname, (gid_t)max_uid)) + continue; /* next line */ + break; + case LIMIT_RANGE_MM: + if (gid > (gid_t)max_uid) + continue; /* next line */ + /* fallthrough */ + case LIMIT_RANGE_MIN: + if (gid < (gid_t)min_uid) + continue; /* next line */ + } if (ctrl & PAM_DEBUG_ARG) { pam_syslog(pamh, LOG_DEBUG, "no limits for '%s' in group '%s'", uname, domain+1); } - fclose(fil); - return PAM_IGNORE; + } else { + switch(rngtype) { + case LIMIT_RANGE_NONE: + continue; /* next line */ + case LIMIT_RANGE_ONE: + if (uid != max_uid) + continue; /* next line */ + break; + case LIMIT_RANGE_MM: + if (uid > max_uid) + continue; /* next line */ + /* fallthrough */ + case LIMIT_RANGE_MIN: + if (uid >= min_uid) + break; + continue; /* next line */ + } + if (ctrl & PAM_DEBUG_ARG) { + pam_syslog(pamh, LOG_DEBUG, "no limits for '%s'", uname); + } } + fclose(fil); + return PAM_IGNORE; } else { pam_syslog(pamh, LOG_WARNING, "invalid line '%s' - skipped", line); } @@ -731,7 +879,7 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, return PAM_ABORT; } - retval = parse_config_file(pamh, pwd->pw_name, ctrl, pl); + retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl); if (retval == PAM_IGNORE) { D(("the configuration file ('%s') has an applicable ' -' entry", CONF_FILE)); return PAM_SUCCESS; @@ -755,7 +903,7 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, /* Parse the *.conf files. */ for (i = 0; globbuf.gl_pathv[i] != NULL; i++) { pl->conf_file = globbuf.gl_pathv[i]; - retval = parse_config_file(pamh, pwd->pw_name, ctrl, pl); + retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl); if (retval == PAM_IGNORE) { D(("the configuration file ('%s') has an applicable ' -' entry", pl->conf_file)); globfree(&globbuf); -- cgit v1.2.3 From 4c2362ccac4c8e967af619f4550be3a5fb165433 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 21 Dec 2010 08:54:14 +0000 Subject: Relevant BUGIDs: Purpose of commit: bugfix Commit summary: --------------- 2010-12-21 Tomas Mraz * modules/pam_selinux/pam_selinux.c (mls_range_allowed): Unhardcode values for security class and av permission bit. --- modules/pam_selinux/pam_selinux.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'modules') diff --git a/modules/pam_selinux/pam_selinux.c b/modules/pam_selinux/pam_selinux.c index c31278e9..a6ca8af2 100644 --- a/modules/pam_selinux/pam_selinux.c +++ b/modules/pam_selinux/pam_selinux.c @@ -236,19 +236,35 @@ static int mls_range_allowed(pam_handle_t *pamh, security_context_t src, securit { struct av_decision avd; int retval; - unsigned int bit = CONTEXT__CONTAINS; - context_t src_context = context_new (src); - context_t dst_context = context_new (dst); + security_class_t class; + access_vector_t bit; + context_t src_context; + context_t dst_context; + + class = string_to_security_class("context"); + if (!class) { + pam_syslog(pamh, LOG_ERR, "Failed to translate security class context. %m"); + return 0; + } + + bit = string_to_av_perm(class, "contains"); + if (!bit) { + pam_syslog(pamh, LOG_ERR, "Failed to translate av perm contains. %m"); + return 0; + } + + src_context = context_new (src); + dst_context = context_new (dst); context_range_set(dst_context, context_range_get(src_context)); if (debug) pam_syslog(pamh, LOG_NOTICE, "Checking if %s mls range valid for %s", dst, context_str(dst_context)); - retval = security_compute_av(context_str(dst_context), dst, SECCLASS_CONTEXT, bit, &avd); + retval = security_compute_av(context_str(dst_context), dst, class, bit, &avd); context_free(src_context); context_free(dst_context); if (retval || ((bit & avd.allowed) != bit)) return 0; - + return 1; } -- cgit v1.2.3 From 10a49cdcd91b313f665421a65a8511315665cf0a Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 22 Feb 2011 22:44:39 +0000 Subject: Relevant BUGIDs: Purpose of commit: docfix Commit summary: --------------- 2011-02-22 Tomas Mraz * modules/pam_nologin/pam_nologin.8.xml: Add missing space. * modules/pam_limits/limits.conf.5.xml: Fix typo. --- modules/pam_limits/limits.conf.5.xml | 2 +- modules/pam_nologin/pam_nologin.8.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/pam_limits/limits.conf.5.xml b/modules/pam_limits/limits.conf.5.xml index a1e84102..939fa0fe 100644 --- a/modules/pam_limits/limits.conf.5.xml +++ b/modules/pam_limits/limits.conf.5.xml @@ -236,7 +236,7 @@ - + maximum memory used by POSIX message queues (bytes) (Linux 2.6 and higher) diff --git a/modules/pam_nologin/pam_nologin.8.xml b/modules/pam_nologin/pam_nologin.8.xml index 94c4887b..e4f63707 100644 --- a/modules/pam_nologin/pam_nologin.8.xml +++ b/modules/pam_nologin/pam_nologin.8.xml @@ -34,7 +34,7 @@ pam_nologin is a PAM module that prevents users from logging into the system when /var/run/nologin or - /etc/nologinexists. The contents + /etc/nologin exists. The contents of the file are displayed to the user. The pam_nologin module has no effect on the root user's ability to log in. -- cgit v1.2.3 From 24557b231f549dc6511d62f5ad35d15d95e1f44f Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 17 Mar 2011 17:04:34 +0000 Subject: Relevant BUGIDs: Purpose of commit: bugfix Commit summary: --------------- 2011-03-17 Tomas Mraz * modules/pam_selinux/pam_selinux.c (config_context): Fix leak of type. (manual_context): Likewise. (context_from_env): Remove extraneous auditing in success case. * modules/pam_unix/support.c (_unix_run_helper_binary): Remove extra close() call. --- modules/pam_selinux/pam_selinux.c | 19 ++++++++++++------- modules/pam_unix/support.c | 2 -- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'modules') diff --git a/modules/pam_selinux/pam_selinux.c b/modules/pam_selinux/pam_selinux.c index a6ca8af2..f99d433a 100644 --- a/modules/pam_selinux/pam_selinux.c +++ b/modules/pam_selinux/pam_selinux.c @@ -196,6 +196,7 @@ manual_context (pam_handle_t *pamh, const char *user, int debug) goto fail_set; if (context_type_set (new_context, type)) goto fail_set; + _pam_drop(type); } _pam_drop(response); @@ -306,6 +307,7 @@ config_context (pam_handle_t *pamh, security_context_t defaultcon, int use_curre goto fail_set; if (context_type_set (new_context, type)) goto fail_set; + _pam_drop(type); } } _pam_drop(response); @@ -390,6 +392,7 @@ context_from_env (pam_handle_t *pamh, security_context_t defaultcon, int env_par int mls_enabled = is_selinux_mls_enabled(); const char *env = NULL; char *type = NULL; + int fail = 1; if ((new_context = context_new(defaultcon)) == NULL) goto fail_set; @@ -450,9 +453,6 @@ context_from_env (pam_handle_t *pamh, security_context_t defaultcon, int env_par /* Get the string value of the context and see if it is valid. */ if (security_check_context(newcon)) { pam_syslog(pamh, LOG_NOTICE, "Not a valid security context %s", newcon); - send_audit_message(pamh, 0, defaultcon, newcon); - freecon(newcon); - newcon = NULL; goto fail_set; } @@ -462,16 +462,21 @@ context_from_env (pam_handle_t *pamh, security_context_t defaultcon, int env_par be checked at setexeccon time */ if (mls_enabled && !mls_range_allowed(pamh, defaultcon, newcon, debug)) { pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon); - send_audit_message(pamh, 0, defaultcon, newcon); - freecon(newcon); - newcon = NULL; + + goto fail_set; } + fail = 0; + fail_set: free(type); context_free(my_context); context_free(new_context); - send_audit_message(pamh, 0, defaultcon, NULL); + if (fail) { + send_audit_message(pamh, 0, defaultcon, newcon); + freecon(newcon); + newcon = NULL; + } return newcon; } diff --git a/modules/pam_unix/support.c b/modules/pam_unix/support.c index bddafd4b..0b8d4d64 100644 --- a/modules/pam_unix/support.c +++ b/modules/pam_unix/support.c @@ -493,14 +493,12 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd, if (passwd != NULL) { /* send the password to the child */ if (write(fds[1], passwd, strlen(passwd)+1) == -1) { pam_syslog (pamh, LOG_ERR, "Cannot send password to helper: %m"); - close(fds[1]); retval = PAM_AUTH_ERR; } passwd = NULL; } else { /* blank password */ if (write(fds[1], "", 1) == -1) { pam_syslog (pamh, LOG_ERR, "Cannot send password to helper: %m"); - close(fds[1]); retval = PAM_AUTH_ERR; } } -- cgit v1.2.3 From f052833acfa231b68d024fef7637883d81400e42 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Fri, 18 Mar 2011 23:15:54 +0000 Subject: Relevant BUGIDs: Purpose of commit: bugfix Commit summary: --------------- 2011-03-18 Tomas Mraz * modules/pam_namespace/md5.c (MD5Final): Clear the whole ctx. * modules/pam_namespace/pam_namespace.c (del_polydir): Guard for NULL poly. (protect_dir): Guard for -1 passing to close(). (ns_setup): Likewise. (pam_sm_open_session): Correctly test for SELinux enabled flag. --- modules/pam_namespace/argv_parse.c | 29 ++++++++++++++++++----------- modules/pam_namespace/md5.c | 2 +- modules/pam_namespace/pam_namespace.c | 17 ++++++++++------- 3 files changed, 29 insertions(+), 19 deletions(-) (limited to 'modules') diff --git a/modules/pam_namespace/argv_parse.c b/modules/pam_namespace/argv_parse.c index acc76d74..40510542 100644 --- a/modules/pam_namespace/argv_parse.c +++ b/modules/pam_namespace/argv_parse.c @@ -44,15 +44,15 @@ int argv_parse(const char *in_buf, int *ret_argc, char ***ret_argv) { int argc = 0, max_argc = 0; char **argv, **new_argv, *buf, ch; - const char *cp = 0; - char *outcp = 0; + const char *cp = NULL; + char *outcp = NULL; int state = STATE_WHITESPACE; buf = malloc(strlen(in_buf)+1); if (!buf) return -1; - max_argc = 0; argc = 0; argv = 0; + argv = NULL; outcp = buf; for (cp = in_buf; (ch = *cp); cp++) { if (state == STATE_WHITESPACE) { @@ -111,23 +111,30 @@ int argv_parse(const char *in_buf, int *ret_argc, char ***ret_argv) } if (state != STATE_WHITESPACE) *outcp++ = '\0'; - if (argv == 0) { - argv = malloc(sizeof(char *)); + if (ret_argv) { + if (argv == NULL) { + free(buf); + if ((argv=malloc(sizeof(char *))) == NULL) + return -1; + } + argv[argc] = NULL; + *ret_argv = argv; + } else { free(buf); + free(argv); } - argv[argc] = 0; if (ret_argc) *ret_argc = argc; - if (ret_argv) - *ret_argv = argv; return 0; } void argv_free(char **argv) { - if (*argv) - free(*argv); - free(argv); + if (argv) { + if (*argv) + free(*argv); + free(argv); + } } #ifdef DEBUG_ARGV_PARSE diff --git a/modules/pam_namespace/md5.c b/modules/pam_namespace/md5.c index 3094a130..c79fb357 100644 --- a/modules/pam_namespace/md5.c +++ b/modules/pam_namespace/md5.c @@ -148,7 +148,7 @@ void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx) MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ diff --git a/modules/pam_namespace/pam_namespace.c b/modules/pam_namespace/pam_namespace.c index baa7f85a..c47599e0 100644 --- a/modules/pam_namespace/pam_namespace.c +++ b/modules/pam_namespace/pam_namespace.c @@ -61,9 +61,11 @@ static void add_polydir_entry(struct instance_data *idata, static void del_polydir(struct polydir_s *poly) { - free(poly->uid); - free(poly->init_script); - free(poly); + if (poly) { + free(poly->uid); + free(poly->init_script); + free(poly); + } } /* @@ -1093,7 +1095,7 @@ static int protect_dir(const char *path, mode_t mode, int do_mkdir, error: save_errno = errno; free(p); - if (dfd != AT_FDCWD) + if (dfd != AT_FDCWD && dfd >= 0) close(dfd); errno = save_errno; @@ -1453,8 +1455,9 @@ static int ns_setup(struct polydir_s *polyptr, return PAM_SESSION_ERR; } - if (retval < 0 && (polyptr->flags & POLYDIR_CREATE)) { - if (create_polydir(polyptr, idata) != PAM_SUCCESS) + if (retval < 0) { + if ((polyptr->flags & POLYDIR_CREATE) && + create_polydir(polyptr, idata) != PAM_SUCCESS) return PAM_SESSION_ERR; } else { close(retval); @@ -1966,7 +1969,7 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, if (strcmp(argv[i], "unmnt_only") == 0) unmnt = UNMNT_ONLY; if (strcmp(argv[i], "require_selinux") == 0) { - if (~(idata.flags & PAMNS_SELINUX_ENABLED)) { + if (!(idata.flags & PAMNS_SELINUX_ENABLED)) { pam_syslog(idata.pamh, LOG_ERR, "selinux_required option given and selinux is disabled"); return PAM_SESSION_ERR; -- cgit v1.2.3 From 7698a76cf4983fe69944a810305183f1fe6cc031 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 21 Mar 2011 22:02:16 +0100 Subject: Clear the whole MD5 context. --- modules/pam_unix/md5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/pam_unix/md5.c b/modules/pam_unix/md5.c index d88d6810..94d1c9da 100644 --- a/modules/pam_unix/md5.c +++ b/modules/pam_unix/md5.c @@ -148,7 +148,7 @@ void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx) MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } #ifndef ASM_MD5 -- cgit v1.2.3 From 6ee536baa197e2d78019e6eab3990c0b9d367fb8 Mon Sep 17 00:00:00 2001 From: kukuk Date: Wed, 4 May 2011 17:26:16 +0200 Subject: 2011-05-04 Thorsten Kukuk * modules/pam_lastlog/pam_lastlog.c (last_login_failed): Don't abort with error if btmp file does not exist. --- modules/pam_lastlog/pam_lastlog.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/pam_lastlog/pam_lastlog.c b/modules/pam_lastlog/pam_lastlog.c index b44c1755..9e8da7d2 100644 --- a/modules/pam_lastlog/pam_lastlog.c +++ b/modules/pam_lastlog/pam_lastlog.c @@ -403,9 +403,13 @@ last_login_failed(pam_handle_t *pamh, int announce, const char *user, time_t llt /* obtain the failed login attempt records from btmp */ fd = open(_PATH_BTMP, O_RDONLY); if (fd < 0) { + int save_errno = errno; pam_syslog(pamh, LOG_ERR, "unable to open %s: %m", _PATH_BTMP); D(("unable to open %s file", _PATH_BTMP)); - return PAM_SERVICE_ERR; + if (save_errno == ENOENT) + return PAM_SUCCESS; + else + return PAM_SERVICE_ERR; } while ((retval=pam_modutil_read(fd, (void *)&ut, -- cgit v1.2.3 From 4f9bffa18076e4ee197513555a4021530b1a1f38 Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Tue, 24 May 2011 16:48:11 +0200 Subject: 2011-05-24 Thorsten Kukuk * modules/pam_listfile/pam_listfile.c (pam_sm_authenticate): quiet option has no argument, print no missing file if quiet is set [sf#3194930]. --- modules/pam_listfile/pam_listfile.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'modules') diff --git a/modules/pam_listfile/pam_listfile.c b/modules/pam_listfile/pam_listfile.c index 616d2201..2af2afd8 100644 --- a/modules/pam_listfile/pam_listfile.c +++ b/modules/pam_listfile/pam_listfile.c @@ -78,8 +78,14 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, { const char *junk; + /* option quiet has no value */ + if(!strcmp(argv[i],"quiet")) { + quiet = 1; + continue; + } + memset(mybuf,'\0',sizeof(mybuf)); - memset(myval,'\0',sizeof(mybuf)); + memset(myval,'\0',sizeof(myval)); junk = strchr(argv[i], '='); if((junk == NULL) || (junk - argv[i]) >= (int) sizeof(mybuf)) { pam_syslog(pamh,LOG_ERR, "Bad option: \"%s\"", @@ -142,8 +148,6 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, apply_type=APPLY_TYPE_USER; strncpy(apply_val,myval,sizeof(apply_val)-1); } - } else if (!strcmp(mybuf,"quiet")) { - quiet = 1; } else { free(ifname); pam_syslog(pamh,LOG_ERR, "Unknown option: %s",mybuf); @@ -283,7 +287,8 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, ifname, citem, citemp, sense); #endif if(lstat(ifname,&fileinfo)) { - pam_syslog(pamh,LOG_ERR, "Couldn't open %s",ifname); + if(!quiet) + pam_syslog(pamh,LOG_ERR, "Couldn't open %s",ifname); free(ifname); return onerr; } -- cgit v1.2.3 From 9ac26f8f0a23a396e3cec5c1949fb2f90a097643 Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Mon, 30 May 2011 11:12:30 +0200 Subject: 2011-05-30 Thorsten Kukuk * modules/pam_env/pam_env.c (_pam_parse): Implement debug option. Based on patch by Tomas Mraz. --- modules/pam_env/pam_env.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'modules') diff --git a/modules/pam_env/pam_env.c b/modules/pam_env/pam_env.c index 8ac8ed33..865fbafe 100644 --- a/modules/pam_env/pam_env.c +++ b/modules/pam_env/pam_env.c @@ -68,8 +68,8 @@ static int _check_var(pam_handle_t *, VAR *); /* This is the real mea 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 *, VAR *); -static int _undefine_var(pam_handle_t *, VAR *); +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'; @@ -134,7 +134,7 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv, } static int -_parse_config_file(pam_handle_t *pamh, const char *file) +_parse_config_file(pam_handle_t *pamh, int ctrl, const char *file) { int retval; char buffer[BUF_SIZE]; @@ -168,10 +168,10 @@ _parse_config_file(pam_handle_t *pamh, const char *file) retval = _check_var(pamh, var); if (DEFINE_VAR == retval) { - retval = _define_var(pamh, var); + retval = _define_var(pamh, ctrl, var); } else if (UNDEFINE_VAR == retval) { - retval = _undefine_var(pamh, var); + retval = _undefine_var(pamh, ctrl, var); } } if (PAM_SUCCESS != retval && ILLEGAL_VAR != retval @@ -191,7 +191,7 @@ _parse_config_file(pam_handle_t *pamh, const char *file) } static int -_parse_env_file(pam_handle_t *pamh, const char *file) +_parse_env_file(pam_handle_t *pamh, int ctrl, const char *file) { int retval=PAM_SUCCESS, i, t; char buffer[BUF_SIZE], *key, *mark; @@ -267,6 +267,9 @@ _parse_env_file(pam_handle_t *pamh, const char *file) 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); } } @@ -691,7 +694,7 @@ static const char * _pam_get_item_byname(pam_handle_t *pamh, const char *name) return itemval; } -static int _define_var(pam_handle_t *pamh, 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 */ @@ -705,16 +708,22 @@ static int _define_var(pam_handle_t *pamh, VAR *var) } retval = pam_putenv(pamh, envvar); + if (ctrl & PAM_DEBUG_ARG) { + pam_syslog(pamh, LOG_DEBUG, "pam_putenv(\"%s\")", envvar); + } _pam_drop(envvar); D(("Exit.")); return retval; } -static int _undefine_var(pam_handle_t *pamh, 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 */ D(("Called and exit.")); + if (ctrl & PAM_DEBUG_ARG) { + pam_syslog(pamh, LOG_DEBUG, "remove variable \"%s\"", var->name); + } return pam_putenv(pamh, var->name); } @@ -762,10 +771,10 @@ handle_env (pam_handle_t *pamh, int argc, const char **argv) ctrl = _pam_parse(pamh, argc, argv, &conf_file, &env_file, &readenv, &user_env_file, &user_readenv); - retval = _parse_config_file(pamh, conf_file); + retval = _parse_config_file(pamh, ctrl, conf_file); if(readenv && retval == PAM_SUCCESS) { - retval = _parse_env_file(pamh, env_file); + retval = _parse_env_file(pamh, ctrl, env_file); if (retval == PAM_IGNORE) retval = PAM_SUCCESS; } @@ -795,7 +804,7 @@ handle_env (pam_handle_t *pamh, int argc, const char **argv) if (pam_modutil_drop_priv(pamh, &privs, user_entry)) { retval = PAM_SESSION_ERR; } else { - retval = _parse_config_file(pamh, envpath); + retval = _parse_config_file(pamh, ctrl, envpath); if (pam_modutil_regain_priv(pamh, &privs)) retval = PAM_SESSION_ERR; } -- cgit v1.2.3 From a1950248ee3fb08374b5733afc3d9f123634319b Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Mon, 30 May 2011 19:36:56 +0200 Subject: 2011-05-30 Thorsten Kukuk * modules/pam_timestamp/pam_timestamp.c (main): Remove unsused variable pretval. * modules/pam_stress/pam_stress.c (converse): **message is const. (stress_get_password): pmsg is const. (pam_sm_chauthtok): Likewise. * libpam/pam_item.c (pam_get_user): Make pmsg const and remove casts. --- modules/pam_stress/pam_stress.c | 11 ++++++----- modules/pam_timestamp/pam_timestamp.c | 3 +-- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'modules') diff --git a/modules/pam_stress/pam_stress.c b/modules/pam_stress/pam_stress.c index 01587fea..b75a597d 100644 --- a/modules/pam_stress/pam_stress.c +++ b/modules/pam_stress/pam_stress.c @@ -116,7 +116,7 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv) } static int converse(pam_handle_t *pamh, int nargs - , struct pam_message **message + , const struct pam_message **message , struct pam_response **response) { int retval; @@ -126,8 +126,7 @@ static int converse(pam_handle_t *pamh, int nargs retval = pam_get_item(pamh,PAM_CONV,&void_conv); conv = void_conv; if (retval == PAM_SUCCESS && conv) { - retval = conv->conv(nargs, (const struct pam_message **) message - , response, conv->appdata_ptr); + retval = conv->conv(nargs, message, response, conv->appdata_ptr); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "converse returned %d: %s", retval, pam_strerror(pamh, retval)); @@ -159,7 +158,8 @@ static int stress_get_password(pam_handle_t *pamh, int flags pam_syslog(pamh, LOG_WARNING, "no forwarded password"); return PAM_PERM_DENIED; } else { /* we will have to get one */ - struct pam_message msg[1],*pmsg[1]; + struct pam_message msg[1]; + const struct pam_message *pmsg[1]; struct pam_response *resp; int retval; @@ -412,7 +412,8 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags, return PAM_SUCCESS; } else if (flags & PAM_UPDATE_AUTHTOK) { /* second call */ - struct pam_message msg[3],*pmsg[3]; + struct pam_message msg[3]; + const struct pam_message *pmsg[3]; struct pam_response *resp; const void *text; char *txt=NULL; diff --git a/modules/pam_timestamp/pam_timestamp.c b/modules/pam_timestamp/pam_timestamp.c index 26876769..7bcf3d12 100644 --- a/modules/pam_timestamp/pam_timestamp.c +++ b/modules/pam_timestamp/pam_timestamp.c @@ -684,7 +684,7 @@ struct pam_module _pam_timestamp_modstruct = { int main(int argc, char **argv) { - int i, pretval = -1, retval = 0, dflag = 0, kflag = 0; + int i, retval = 0, dflag = 0, kflag = 0; const char *target_user = NULL, *user = NULL, *tty = NULL; struct passwd *pwd; struct timeval tv; @@ -826,7 +826,6 @@ main(int argc, char **argv) select(STDOUT_FILENO + 1, NULL, NULL, &write_fds, &tv); - pretval = retval; retval = 0; } } while (dflag > 0); -- cgit v1.2.3 From be52e613145564d55becf220111c0c81038eb7f6 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 2 Jun 2011 21:50:11 +0200 Subject: Add support for the mount_private option to pam_namespace. --- modules/pam_namespace/pam_namespace.8.xml | 18 ++++++++++++++++++ modules/pam_namespace/pam_namespace.c | 29 ++++++++++++++++++++++++----- modules/pam_namespace/pam_namespace.h | 1 + 3 files changed, 43 insertions(+), 5 deletions(-) (limited to 'modules') diff --git a/modules/pam_namespace/pam_namespace.8.xml b/modules/pam_namespace/pam_namespace.8.xml index 0433f0fd..f0ebe2c6 100644 --- a/modules/pam_namespace/pam_namespace.8.xml +++ b/modules/pam_namespace/pam_namespace.8.xml @@ -52,6 +52,9 @@ use_default_context + + mount_private + @@ -234,6 +237,21 @@ + + + + + + + This option should be used on systems where the / mount point and + its submounts are made shared (for example with a + mount --make-rshared / command). + The module will make the polyinstantiated directory mount points + private. + + + + diff --git a/modules/pam_namespace/pam_namespace.c b/modules/pam_namespace/pam_namespace.c index c47599e0..d5a2d781 100644 --- a/modules/pam_namespace/pam_namespace.c +++ b/modules/pam_namespace/pam_namespace.c @@ -1003,7 +1003,7 @@ static int protect_mount(int dfd, const char *path, struct instance_data *idata) return 0; } -static int protect_dir(const char *path, mode_t mode, int do_mkdir, +static int protect_dir(const char *path, mode_t mode, int do_mkdir, int always, struct instance_data *idata) { char *p = strdup(path); @@ -1082,7 +1082,7 @@ static int protect_dir(const char *path, mode_t mode, int do_mkdir, } } - if (flags & O_NOFOLLOW) { + if ((flags & O_NOFOLLOW) || always) { /* we are inside user-owned dir - protect */ if (protect_mount(rv, p, idata) == -1) { save_errno = errno; @@ -1124,7 +1124,7 @@ static int check_inst_parent(char *ipath, struct instance_data *idata) if (trailing_slash) *trailing_slash = '\0'; - dfd = protect_dir(inst_parent, 0, 1, idata); + dfd = protect_dir(inst_parent, 0, 1, 0, idata); if (dfd == -1 || fstat(dfd, &instpbuf) < 0) { pam_syslog(idata->pamh, LOG_ERR, @@ -1259,7 +1259,7 @@ static int create_polydir(struct polydir_s *polyptr, } #endif - rc = protect_dir(dir, mode, 1, idata); + rc = protect_dir(dir, mode, 1, idata->flags & PAMNS_MOUNT_PRIVATE, idata); if (rc == -1) { pam_syslog(idata->pamh, LOG_ERR, "Error creating directory %s: %m", dir); @@ -1447,7 +1447,7 @@ static int ns_setup(struct polydir_s *polyptr, pam_syslog(idata->pamh, LOG_DEBUG, "Set namespace for directory %s", polyptr->dir); - retval = protect_dir(polyptr->dir, 0, 0, idata); + retval = protect_dir(polyptr->dir, 0, 0, idata->flags & PAMNS_MOUNT_PRIVATE, idata); if (retval < 0 && errno != ENOENT) { pam_syslog(idata->pamh, LOG_ERR, "Polydir %s access error: %m", @@ -1534,6 +1534,22 @@ static int ns_setup(struct polydir_s *polyptr, goto error_out; } + if (idata->flags & PAMNS_MOUNT_PRIVATE) { + /* + * Make the polyinstantiated dir private mount. This depends + * on making the dir a mount point in the protect_dir call. + */ + if (mount(polyptr->dir, polyptr->dir, NULL, MS_PRIVATE|MS_REC, NULL) < 0) { + pam_syslog(idata->pamh, LOG_ERR, "Error making %s a private mount, %m", + polyptr->dir); + goto error_out; + } + if (idata->flags & PAMNS_DEBUG) + pam_syslog(idata->pamh, LOG_DEBUG, + "Polyinstantiated directory %s made as private mount", polyptr->dir); + + } + /* * Bind mount instance directory on top of the polyinstantiated * directory to provide an instance of polyinstantiated directory @@ -1964,6 +1980,9 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, idata.flags |= PAMNS_USE_DEFAULT_CONTEXT; idata.flags |= PAMNS_CTXT_BASED_INST; } + if (strcmp(argv[i], "mount_private") == 0) { + idata.flags |= PAMNS_MOUNT_PRIVATE; + } if (strcmp(argv[i], "unmnt_remnt") == 0) unmnt = UNMNT_REMNT; if (strcmp(argv[i], "unmnt_only") == 0) diff --git a/modules/pam_namespace/pam_namespace.h b/modules/pam_namespace/pam_namespace.h index da21bd70..7b39068b 100644 --- a/modules/pam_namespace/pam_namespace.h +++ b/modules/pam_namespace/pam_namespace.h @@ -96,6 +96,7 @@ #define PAMNS_NO_UNMOUNT_ON_CLOSE 0x00010000 /* no unmount at session close */ #define PAMNS_USE_CURRENT_CONTEXT 0x00020000 /* use getcon instead of getexeccon */ #define PAMNS_USE_DEFAULT_CONTEXT 0x00040000 /* use get_default_context instead of getexeccon */ +#define PAMNS_MOUNT_PRIVATE 0x00080000 /* Make the polydir mounts private */ /* polydir flags */ #define POLYDIR_EXCLUSIVE 0x00000001 /* polyinstatiate exclusively for override uids */ -- cgit v1.2.3 From 48590abce86b34e55c84f71424449f16d285eaf2 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 2 Jun 2011 21:53:55 +0200 Subject: Guards for memory allocation errors in pam_cracklib module. --- modules/pam_cracklib/pam_cracklib.c | 38 +++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'modules') diff --git a/modules/pam_cracklib/pam_cracklib.c b/modules/pam_cracklib/pam_cracklib.c index 2e911261..1955b83f 100644 --- a/modules/pam_cracklib/pam_cracklib.c +++ b/modules/pam_cracklib/pam_cracklib.c @@ -473,6 +473,9 @@ static char * str_lower(char *string) { char *cp; + if (!string) + return NULL; + for (cp = string; *cp; cp++) *cp = tolower(*cp); return string; @@ -492,15 +495,26 @@ static const char *password_check(struct cracklib_options *opt, } newmono = str_lower(x_strdup(new)); + if (!newmono) + msg = _("memory allocation error"); + usermono = str_lower(x_strdup(user)); - if (old) { - oldmono = str_lower(x_strdup(old)); - wrapped = malloc(strlen(oldmono) * 2 + 1); - strcpy (wrapped, oldmono); - strcat (wrapped, oldmono); + if (!usermono) + msg = _("memory allocation error"); + + if (!msg && old) { + oldmono = str_lower(x_strdup(old)); + if (oldmono) + wrapped = malloc(strlen(oldmono) * 2 + 1); + if (wrapped) { + strcpy (wrapped, oldmono); + strcat (wrapped, oldmono); + } else { + msg = _("memory allocation error"); + } } - if (palindrome(newmono)) + if (!msg && palindrome(newmono)) msg = _("is a palindrome"); if (!msg && oldmono && strcmp(oldmono, newmono) == 0) @@ -524,13 +538,17 @@ static const char *password_check(struct cracklib_options *opt, if (!msg && usercheck(opt, newmono, usermono)) msg = _("contains the user name in some form"); - memset(newmono, 0, strlen(newmono)); - free(newmono); free(usermono); - if (old) { + if (newmono) { + memset(newmono, 0, strlen(newmono)); + free(newmono); + } + if (oldmono) { memset(oldmono, 0, strlen(oldmono)); - memset(wrapped, 0, strlen(wrapped)); free(oldmono); + } + if (wrapped) { + memset(wrapped, 0, strlen(wrapped)); free(wrapped); } -- cgit v1.2.3 From 26747b9b490d190dd20543ea9cbde082ae667402 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 2 Jun 2011 21:55:41 +0200 Subject: Guard for pam_get_user() error in pam_filter module. --- modules/pam_filter/pam_filter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/pam_filter/pam_filter.c b/modules/pam_filter/pam_filter.c index 2f290fd5..da98148f 100644 --- a/modules/pam_filter/pam_filter.c +++ b/modules/pam_filter/pam_filter.c @@ -177,8 +177,8 @@ static int process_args(pam_handle_t *pamh #define USER_OFFSET 5 /* strlen('USER='); */ #define USER_NAME "USER=" - pam_get_user(pamh, &user, NULL); - if (user == NULL) { + if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || + user == NULL) { user = ""; } size = USER_OFFSET+strlen(user); -- cgit v1.2.3 From 3475dbeb44238b5b8910cea4abfde106c6e90618 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 2 Jun 2011 21:57:31 +0200 Subject: Check for return value of pam_get_item() in pam_echo module. --- modules/pam_echo/pam_echo.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/pam_echo/pam_echo.c b/modules/pam_echo/pam_echo.c index 31ebca22..043ff703 100644 --- a/modules/pam_echo/pam_echo.c +++ b/modules/pam_echo/pam_echo.c @@ -119,7 +119,10 @@ replace_and_print (pam_handle_t *pamh, const char *mesg) str = &myhostname; } else - pam_get_item (pamh, item, &str); + { + if (pam_get_item (pamh, item, &str) != PAM_SUCCESS) + str = NULL; + } if (str == NULL) str = "(null)"; for (q = str; *q != '\0' && len < length - 1; ++q) -- cgit v1.2.3 From 74b8ffc6d088f06e5c9fd017b5499a406dfb3fb0 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 6 Jun 2011 12:22:02 +0200 Subject: Rewrite of the field parsing in pam_group and pam_time. --- modules/pam_group/pam_group.c | 281 ++++++++++++++++++++---------------------- modules/pam_time/pam_time.c | 273 ++++++++++++++++++++-------------------- 2 files changed, 268 insertions(+), 286 deletions(-) (limited to 'modules') diff --git a/modules/pam_group/pam_group.c b/modules/pam_group/pam_group.c index 310b2622..be5f20f3 100644 --- a/modules/pam_group/pam_group.c +++ b/modules/pam_group/pam_group.c @@ -2,6 +2,7 @@ /* * Written by Andrew Morgan 1996/7/6 + * Field parsing rewritten by Tomas Mraz */ #include "config.h" @@ -50,166 +51,156 @@ typedef enum { AND, OR } operator; /* --- static functions for checking whether the user should be let in --- */ -static void shift_bytes(char *mem, int from, int by) +static char * +shift_buf(char *mem, int from) { - while (by-- > 0) { - *mem = mem[from]; + char *start = mem; + while ((*mem = mem[from]) != '\0') ++mem; + memset(mem, '\0', PAM_GROUP_BUFLEN - (mem - start)); + return mem; +} + +static void +trim_spaces(char *buf, char *from) +{ + while (from > buf) { + --from; + if (*from == ' ') + *from = '\0'; + else + break; } } -/* This function should initially be called with buf = NULL. If - * an error occurs, the file descriptor is closed. Subsequent - * calls with a closed descriptor will cause buf to be deallocated. - * Therefore, always check buf after calling this to see if an error - * occurred. - */ +#define STATE_NL 0 /* new line starting */ +#define STATE_COMMENT 1 /* inside comment */ +#define STATE_FIELD 2 /* field following */ +#define STATE_EOF 3 /* end of file or error */ + static int -read_field (const pam_handle_t *pamh, int fd, char **buf, int *from, int *to) +read_field(const pam_handle_t *pamh, int fd, char **buf, int *from, int *state) { - /* is buf set ? */ + char *to; + char *src; + int i; + char c; + int onspace; + /* is buf set ? */ if (! *buf) { - *buf = (char *) malloc(PAM_GROUP_BUFLEN); + *buf = (char *) calloc(1, PAM_GROUP_BUFLEN+1); if (! *buf) { pam_syslog(pamh, LOG_ERR, "out of memory"); + D(("no memory")); + *state = STATE_EOF; return -1; } - *from = *to = 0; + *from = 0; + *state = STATE_NL; fd = open(PAM_GROUP_CONF, O_RDONLY); + if (fd < 0) { + pam_syslog(pamh, LOG_ERR, "error opening %s: %m", PAM_GROUP_CONF); + _pam_drop(*buf); + *state = STATE_EOF; + return -1; + } } - /* do we have a file open ? return error */ - - if (fd < 0 && *to <= 0) { - pam_syslog(pamh, LOG_ERR, "%s not opened", PAM_GROUP_CONF); - memset(*buf, 0, PAM_GROUP_BUFLEN); - _pam_drop(*buf); - return -1; - } - - /* check if there was a newline last time */ - - if ((*to > *from) && (*to > 0) - && ((*buf)[*from] == '\0')) { /* previous line ended */ - (*from)++; - (*buf)[0] = '\0'; - return fd; - } - - /* ready for more data: first shift the buffer's remaining data */ - - *to -= *from; - shift_bytes(*buf, *from, *to); - *from = 0; - (*buf)[*to] = '\0'; - - while (fd >= 0 && *to < PAM_GROUP_BUFLEN) { - int i; - - /* now try to fill the remainder of the buffer */ + if (*from > 0) + to = shift_buf(*buf, *from); + else + to = *buf; - i = read(fd, *to + *buf, PAM_GROUP_BUFLEN - *to); + while (fd != -1 && to - *buf < PAM_GROUP_BUFLEN) { + i = pam_modutil_read(fd, to, PAM_GROUP_BUFLEN - (to - *buf)); if (i < 0) { pam_syslog(pamh, LOG_ERR, "error reading %s: %m", PAM_GROUP_CONF); close(fd); + memset(*buf, 0, PAM_GROUP_BUFLEN); + _pam_drop(*buf); + *state = STATE_EOF; return -1; } else if (!i) { close(fd); fd = -1; /* end of file reached */ - } else - *to += i; + } - /* - * contract the buffer. Delete any comments, and replace all - * multiple spaces with single commas - */ + to += i; + } - i = 0; -#ifdef DEBUG_DUMP - D(("buffer=<%s>",*buf)); -#endif - while (i < *to) { - if ((*buf)[i] == ',') { - int j; - - for (j=++i; j<*to && (*buf)[j] == ','; ++j); - if (j!=i) { - shift_bytes(i + (*buf), j-i, (*to) - j); - *to -= j-i; + if (to == *buf) { + /* nothing previously in buf, nothing read */ + _pam_drop(*buf); + *state = STATE_EOF; + return -1; + } + + memset(to, '\0', PAM_GROUP_BUFLEN - (to - *buf)); + + to = *buf; + onspace = 1; /* delete any leading spaces */ + + for (src = to; (c=*src) != '\0'; ++src) { + if (*state == STATE_COMMENT && c != '\n') { + continue; + } + + switch (c) { + case '\n': + *state = STATE_NL; + *to = '\0'; + *from = (src - *buf) + 1; + trim_spaces(*buf, to); + return fd; + + case '\t': + case ' ': + if (!onspace) { + onspace = 1; + *to++ = ' '; } - } - switch ((*buf)[i]) { - int j, c; + break; + + case '!': + onspace = 1; /* ignore following spaces */ + *to++ = '!'; + break; + case '#': - c = 0; - for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j); - if (j >= *to) { - (*buf)[*to = ++i] = '\0'; - } else if (c == '\n') { - shift_bytes(i + (*buf), j-i, (*to) - j); - *to -= j-i; - ++i; - } else { - pam_syslog(pamh, LOG_CRIT, - "internal error in file %s at line %d", - __FILE__, __LINE__); - close(fd); - return -1; - } + *state = STATE_COMMENT; break; + + case FIELD_SEPARATOR: + *state = STATE_FIELD; + *to = '\0'; + *from = (src - *buf) + 1; + trim_spaces(*buf, to); + return fd; + case '\\': - if ((*buf)[i+1] == '\n') { - shift_bytes(i + *buf, 2, *to - (i+2)); - *to -= 2; - } else { - ++i; /* we don't escape non-newline characters */ + if (src[1] == '\n') { + ++src; /* skip it */ + break; } - break; - case '!': - case ' ': - case '\t': - if ((*buf)[i] != '!') - (*buf)[i] = ','; - /* delete any trailing spaces */ - for (j=++i; j < *to && ( (c = (*buf)[j]) == ' ' - || c == '\t' ); ++j); - shift_bytes(i + *buf, j-i, (*to)-j ); - *to -= j-i; - break; default: - ++i; - } + *to++ = c; + onspace = 0; } + if (src > to) + *src = '\0'; /* clearing */ } - (*buf)[*to] = '\0'; - - /* now return the next field (set the from/to markers) */ - { - int i; - - for (i=0; i<*to; ++i) { - switch ((*buf)[i]) { - case '#': - case '\n': /* end of the line/file */ - (*buf)[i] = '\0'; - *from = i; - return fd; - case FIELD_SEPARATOR: /* end of the field */ - (*buf)[i] = '\0'; - *from = ++i; - return fd; - } - } - *from = i; - (*buf)[*from] = '\0'; + if (*state != STATE_COMMENT) { + *state = STATE_COMMENT; + pam_syslog(pamh, LOG_ERR, "field too long - ignored"); + **buf = '\0'; + } else { + *to = '\0'; + trim_spaces(*buf, to); } - if (*to <= 0) { - D(("[end of text]")); - *buf = NULL; - } + *from = 0; return fd; } @@ -582,7 +573,7 @@ static int mkgrplist(pam_handle_t *pamh, char *buf, gid_t **list, int len) static int check_account(pam_handle_t *pamh, const char *service, const char *tty, const char *user) { - int from=0,to=0,fd=-1; + int from=0, state=STATE_NL, fd=-1; char *buffer=NULL; int count=0; TIME here_and_now; @@ -627,7 +618,7 @@ static int check_account(pam_handle_t *pamh, const char *service, /* here we get the service name field */ - fd = read_field(pamh,fd,&buffer,&from,&to); + fd = read_field(pamh, fd, &buffer, &from, &state); if (!buffer || !buffer[0]) { /* empty line .. ? */ continue; @@ -635,15 +626,21 @@ static int check_account(pam_handle_t *pamh, const char *service, ++count; D(("working on rule #%d",count)); + if (state != STATE_FIELD) { + pam_syslog(pamh, LOG_ERR, + "%s: malformed rule #%d", PAM_GROUP_CONF, count); + continue; + } + good = logic_field(pamh,service, buffer, count, is_same); D(("with service: %s", good ? "passes":"fails" )); /* here we get the terminal name field */ - fd = read_field(pamh,fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { + fd = read_field(pamh, fd, &buffer, &from, &state); + if (state != STATE_FIELD) { pam_syslog(pamh, LOG_ERR, - "%s: no tty entry #%d", PAM_GROUP_CONF, count); + "%s: malformed rule #%d", PAM_GROUP_CONF, count); continue; } good &= logic_field(pamh,tty, buffer, count, is_same); @@ -651,10 +648,10 @@ static int check_account(pam_handle_t *pamh, const char *service, /* here we get the username field */ - fd = read_field(pamh,fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { + fd = read_field(pamh, fd, &buffer, &from, &state); + if (state != STATE_FIELD) { pam_syslog(pamh, LOG_ERR, - "%s: no user entry #%d", PAM_GROUP_CONF, count); + "%s: malformed rule #%d", PAM_GROUP_CONF, count); continue; } /* If buffer starts with @, we are using netgroups */ @@ -669,20 +666,20 @@ static int check_account(pam_handle_t *pamh, const char *service, /* here we get the time field */ - fd = read_field(pamh,fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { + fd = read_field(pamh, fd, &buffer, &from, &state); + if (state != STATE_FIELD) { pam_syslog(pamh, LOG_ERR, - "%s: no time entry #%d", PAM_GROUP_CONF, count); + "%s: malformed rule #%d", PAM_GROUP_CONF, count); continue; } good &= logic_field(pamh,&here_and_now, buffer, count, check_time); D(("with time: %s", good ? "passes":"fails" )); - fd = read_field(pamh,fd,&buffer,&from,&to); - if (!buffer || !buffer[0]) { + fd = read_field(pamh, fd, &buffer, &from, &state); + if (state == STATE_FIELD) { pam_syslog(pamh, LOG_ERR, - "%s: no listed groups for rule #%d", PAM_GROUP_CONF, count); + "%s: poorly terminated rule #%d", PAM_GROUP_CONF, count); continue; } @@ -701,14 +698,6 @@ static int check_account(pam_handle_t *pamh, const char *service, } } - /* check the line is terminated correctly */ - - fd = read_field(pamh,fd,&buffer,&from,&to); - if (buffer && buffer[0]) { - pam_syslog(pamh, LOG_ERR, - "%s: poorly terminated rule #%d", PAM_GROUP_CONF, count); - } - if (good > 0) { D(("rule #%d passed, added %d groups", count, good)); } else if (good < 0) { @@ -717,7 +706,7 @@ static int check_account(pam_handle_t *pamh, const char *service, D(("rule #%d failed", count)); } - } while (buffer); + } while (state != STATE_EOF); /* now set the groups for the user */ diff --git a/modules/pam_time/pam_time.c b/modules/pam_time/pam_time.c index 7e418808..dff4a6da 100644 --- a/modules/pam_time/pam_time.c +++ b/modules/pam_time/pam_time.c @@ -4,6 +4,7 @@ * Written by Andrew Morgan 1996/6/22 * (File syntax and much other inspiration from the shadow package * shadow-960129) + * Field parsing rewritten by Tomas Mraz */ #include "config.h" @@ -23,7 +24,7 @@ #include #ifdef HAVE_LIBAUDIT -#include +#include #endif #define PAM_TIME_BUFLEN 1000 @@ -79,163 +80,157 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv) /* --- static functions for checking whether the user should be let in --- */ -static void -shift_bytes(char *mem, int from, int by) +static char * +shift_buf(char *mem, int from) { - while (by-- > 0) { - *mem = mem[from]; + char *start = mem; + while ((*mem = mem[from]) != '\0') ++mem; + memset(mem, '\0', PAM_TIME_BUFLEN - (mem - start)); + return mem; +} + +static void +trim_spaces(char *buf, char *from) +{ + while (from > buf) { + --from; + if (*from == ' ') + *from = '\0'; + else + break; } } +#define STATE_NL 0 /* new line starting */ +#define STATE_COMMENT 1 /* inside comment */ +#define STATE_FIELD 2 /* field following */ +#define STATE_EOF 3 /* end of file or error */ + static int -read_field(const pam_handle_t *pamh, int fd, char **buf, int *from, int *to) +read_field(const pam_handle_t *pamh, int fd, char **buf, int *from, int *state) { - /* is buf set ? */ + char *to; + char *src; + int i; + char c; + int onspace; + /* is buf set ? */ if (! *buf) { - *buf = (char *) malloc(PAM_TIME_BUFLEN); + *buf = (char *) calloc(1, PAM_TIME_BUFLEN+1); if (! *buf) { pam_syslog(pamh, LOG_ERR, "out of memory"); D(("no memory")); + *state = STATE_EOF; return -1; } - *from = *to = 0; + *from = 0; + *state = STATE_NL; fd = open(PAM_TIME_CONF, O_RDONLY); + if (fd < 0) { + pam_syslog(pamh, LOG_ERR, "error opening %s: %m", PAM_TIME_CONF); + _pam_drop(*buf); + *state = STATE_EOF; + return -1; + } } + - /* do we have a file open ? return error */ - - if (fd < 0 && *to <= 0) { - pam_syslog(pamh, LOG_ERR, "error opening %s: %m", PAM_TIME_CONF); - memset(*buf, 0, PAM_TIME_BUFLEN); - _pam_drop(*buf); - return -1; - } - - /* check if there was a newline last time */ - - if ((*to > *from) && (*to > 0) - && ((*buf)[*from] == '\0')) { /* previous line ended */ - (*from)++; - (*buf)[0] = '\0'; - return fd; - } - - /* ready for more data: first shift the buffer's remaining data */ - - *to -= *from; - shift_bytes(*buf, *from, *to); - *from = 0; - (*buf)[*to] = '\0'; - - while (fd >= 0 && *to < PAM_TIME_BUFLEN) { - int i; - - /* now try to fill the remainder of the buffer */ + if (*from > 0) + to = shift_buf(*buf, *from); + else + to = *buf; - i = read(fd, *to + *buf, PAM_TIME_BUFLEN - *to); + while (fd != -1 && to - *buf < PAM_TIME_BUFLEN) { + i = pam_modutil_read(fd, to, PAM_TIME_BUFLEN - (to - *buf)); if (i < 0) { pam_syslog(pamh, LOG_ERR, "error reading %s: %m", PAM_TIME_CONF); close(fd); + memset(*buf, 0, PAM_TIME_BUFLEN); + _pam_drop(*buf); + *state = STATE_EOF; return -1; } else if (!i) { close(fd); fd = -1; /* end of file reached */ - } else - *to += i; + } - /* - * contract the buffer. Delete any comments, and replace all - * multiple spaces with single commas - */ + to += i; + } - i = 0; -#ifdef DEBUG_DUMP - D(("buffer=<%s>",*buf)); -#endif - while (i < *to) { - if ((*buf)[i] == ',') { - int j; - - for (j=++i; j<*to && (*buf)[j] == ','; ++j); - if (j!=i) { - shift_bytes(i + (*buf), j-i, (*to) - j); - *to -= j-i; - } - } - switch ((*buf)[i]) { - int j,c; - case '#': - c = 0; - for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j); - if (j >= *to) { - (*buf)[*to = ++i] = '\0'; - } else if (c == '\n') { - shift_bytes(i + (*buf), j-i, (*to) - j); - *to -= j-i; - ++i; - } else { - pam_syslog(pamh, LOG_CRIT, - "internal error in file %s at line %d", - __FILE__, __LINE__); - close(fd); - return -1; - } - break; - case '\\': - if ((*buf)[i+1] == '\n') { - shift_bytes(i + *buf, 2, *to - (i+2)); - *to -= 2; - } else { - ++i; /* we don't escape non-newline characters */ - } - break; - case '!': - case ' ': - case '\t': - if ((*buf)[i] != '!') - (*buf)[i] = ','; - /* delete any trailing spaces */ - for (j=++i; j < *to && ( (c = (*buf)[j]) == ' ' - || c == '\t' ); ++j); - shift_bytes(i + *buf, j-i, (*to)-j ); - *to -= j-i; - break; - default: - ++i; - } - } + if (to == *buf) { + /* nothing previously in buf, nothing read */ + _pam_drop(*buf); + *state = STATE_EOF; + return -1; } - (*buf)[*to] = '\0'; + memset(to, '\0', PAM_TIME_BUFLEN - (to - *buf)); - /* now return the next field (set the from/to markers) */ - { - int i; + to = *buf; + onspace = 1; /* delete any leading spaces */ + + for (src = to; (c=*src) != '\0'; ++src) { + if (*state == STATE_COMMENT && c != '\n') { + continue; + } + + switch (c) { + case '\n': + *state = STATE_NL; + *to = '\0'; + *from = (src - *buf) + 1; + trim_spaces(*buf, to); + return fd; + + case '\t': + case ' ': + if (!onspace) { + onspace = 1; + *to++ = ' '; + } + break; + + case '!': + onspace = 1; /* ignore following spaces */ + *to++ = '!'; + break; - for (i=0; i<*to; ++i) { - switch ((*buf)[i]) { case '#': - case '\n': /* end of the line/file */ - (*buf)[i] = '\0'; - *from = i; + *state = STATE_COMMENT; + break; + + case FIELD_SEPARATOR: + *state = STATE_FIELD; + *to = '\0'; + *from = (src - *buf) + 1; + trim_spaces(*buf, to); return fd; - case FIELD_SEPARATOR: /* end of the field */ - (*buf)[i] = '\0'; - *from = ++i; - return fd; - } + + case '\\': + if (src[1] == '\n') { + ++src; /* skip it */ + break; + } + default: + *to++ = c; + onspace = 0; } - *from = i; - (*buf)[*from] = '\0'; + if (src > to) + *src = '\0'; /* clearing */ } - if (*to <= 0) { - D(("[end of text]")); - *buf = NULL; + if (*state != STATE_COMMENT) { + *state = STATE_COMMENT; + pam_syslog(pamh, LOG_ERR, "field too long - ignored"); + **buf = '\0'; + } else { + *to = '\0'; + trim_spaces(*buf, to); } + *from = 0; return fd; } @@ -511,7 +506,7 @@ static int check_account(pam_handle_t *pamh, const char *service, const char *tty, const char *user) { - int from=0,to=0,fd=-1; + int from=0, state=STATE_NL, fd=-1; char *buffer=NULL; int count=0; TIME here_and_now; @@ -523,23 +518,28 @@ check_account(pam_handle_t *pamh, const char *service, /* here we get the service name field */ - fd = read_field(pamh, fd, &buffer, &from, &to); - + fd = read_field(pamh, fd, &buffer, &from, &state); if (!buffer || !buffer[0]) { /* empty line .. ? */ continue; } ++count; + if (state != STATE_FIELD) { + pam_syslog(pamh, LOG_ERR, + "%s: malformed rule #%d", PAM_TIME_CONF, count); + continue; + } + good = logic_field(pamh, service, buffer, count, is_same); D(("with service: %s", good ? "passes":"fails" )); /* here we get the terminal name field */ - fd = read_field(pamh, fd, &buffer, &from, &to); - if (!buffer || !buffer[0]) { + fd = read_field(pamh, fd, &buffer, &from, &state); + if (state != STATE_FIELD) { pam_syslog(pamh, LOG_ERR, - "%s: no tty entry #%d", PAM_TIME_CONF, count); + "%s: malformed rule #%d", PAM_TIME_CONF, count); continue; } good &= logic_field(pamh, tty, buffer, count, is_same); @@ -547,10 +547,10 @@ check_account(pam_handle_t *pamh, const char *service, /* here we get the username field */ - fd = read_field(pamh, fd, &buffer, &from, &to); - if (!buffer || !buffer[0]) { + fd = read_field(pamh, fd, &buffer, &from, &state); + if (state != STATE_FIELD) { pam_syslog(pamh, LOG_ERR, - "%s: no user entry #%d", PAM_TIME_CONF, count); + "%s: malformed rule #%d", PAM_TIME_CONF, count); continue; } /* If buffer starts with @, we are using netgroups */ @@ -562,23 +562,16 @@ check_account(pam_handle_t *pamh, const char *service, /* here we get the time field */ - fd = read_field(pamh, fd, &buffer, &from, &to); - if (!buffer || !buffer[0]) { + fd = read_field(pamh, fd, &buffer, &from, &state); + if (state == STATE_FIELD) { pam_syslog(pamh, LOG_ERR, - "%s: no time entry #%d", PAM_TIME_CONF, count); + "%s: poorly terminated rule #%d", PAM_TIME_CONF, count); continue; } intime = logic_field(pamh, &here_and_now, buffer, count, check_time); D(("with time: %s", intime ? "passes":"fails" )); - fd = read_field(pamh, fd, &buffer, &from, &to); - if (buffer && buffer[0]) { - pam_syslog(pamh, LOG_ERR, - "%s: poorly terminated rule #%d", PAM_TIME_CONF, count); - continue; - } - if (good && !intime) { /* * for security parse whole file.. also need to ensure @@ -588,7 +581,7 @@ check_account(pam_handle_t *pamh, const char *service, } else { D(("rule passed")); } - } while (buffer); + } while (state != STATE_EOF); return retval; } -- cgit v1.2.3 From c99be5959bc7e7b407f7dd9ba6637f8fbb6c9249 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 6 Jun 2011 18:22:32 +0200 Subject: Define the MS_PRIVATE and MS_REC flags if they are not in sys/mount.h. --- modules/pam_namespace/pam_namespace.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'modules') diff --git a/modules/pam_namespace/pam_namespace.h b/modules/pam_namespace/pam_namespace.h index 7b39068b..c49995c0 100644 --- a/modules/pam_namespace/pam_namespace.h +++ b/modules/pam_namespace/pam_namespace.h @@ -74,6 +74,14 @@ #define CLONE_NEWNS 0x00020000 /* Flag to create new namespace */ #endif +/* mount flags for mount_private */ +#ifndef MS_REC +#define MS_REC (1<<14) +#endif +#ifndef MS_PRIVATE +#define MS_PRIVATE (1<<18) +#endif + /* * Module defines */ -- cgit v1.2.3 From 2cd2fb864a52e71a5f6c15aea1cc7e953674aeb6 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 7 Jun 2011 17:22:30 +0200 Subject: Detect the shared / mount and enable private mounts based on that. --- modules/pam_namespace/pam_namespace.8.xml | 7 +++-- modules/pam_namespace/pam_namespace.c | 51 +++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/pam_namespace/pam_namespace.8.xml b/modules/pam_namespace/pam_namespace.8.xml index f0ebe2c6..48021c80 100644 --- a/modules/pam_namespace/pam_namespace.8.xml +++ b/modules/pam_namespace/pam_namespace.8.xml @@ -243,11 +243,14 @@ - This option should be used on systems where the / mount point and + This option can be used on systems where the / mount point or its submounts are made shared (for example with a mount --make-rshared / command). The module will make the polyinstantiated directory mount points - private. + private. Normally the pam_namespace will try to detect the + shared / mount point and make the polyinstantiated directories + private automatically. This option has to be used just when + only a subtree is shared and / is not. diff --git a/modules/pam_namespace/pam_namespace.c b/modules/pam_namespace/pam_namespace.c index d5a2d781..4a99184a 100644 --- a/modules/pam_namespace/pam_namespace.c +++ b/modules/pam_namespace/pam_namespace.c @@ -1890,6 +1890,53 @@ static int ctxt_based_inst_needed(void) } #endif +static int root_shared(void) +{ + FILE *f; + char *line = NULL; + size_t n = 0; + int rv = 0; + + f = fopen("/proc/self/mountinfo", "r"); + + if (f == NULL) + return 0; + + while(getline(&line, &n, f) != -1) { + char *l; + char *sptr; + int i; + + l = line; + sptr = NULL; + for (i = 0; i < 7; i++) { + char *tok; + + tok = strtok_r(l, " ", &sptr); + l = NULL; + if (tok == NULL) + /* next mountinfo line */ + break; + + if (i == 4 && strcmp(tok, "/") != 0) + /* next mountinfo line */ + break; + + if (i == 6) { + if (strncmp(tok, "shared:", 7) == 0) + /* there might be more / mounts, the last one counts */ + rv = 1; + else + rv = 0; + } + } + } + + free(line); + fclose(f); + + return rv; +} static int get_user_data(struct instance_data *idata) { @@ -2002,6 +2049,10 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, if (retval != PAM_SUCCESS) return retval; + if (root_shared()) { + idata.flags |= PAMNS_MOUNT_PRIVATE; + } + /* * Parse namespace configuration file which lists directories to * polyinstantiate, directory where instance directories are to -- cgit v1.2.3 From cda7bd483b42a39157e69271fa2211d7e89944dc Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 13 Jun 2011 20:27:18 +0200 Subject: Test also whether the tty is in the /sys/class/tty/console/active file. --- modules/pam_securetty/pam_securetty.8.xml | 8 +++++--- modules/pam_securetty/pam_securetty.c | 33 ++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) (limited to 'modules') diff --git a/modules/pam_securetty/pam_securetty.8.xml b/modules/pam_securetty/pam_securetty.8.xml index c5d6c5fe..48215f5f 100644 --- a/modules/pam_securetty/pam_securetty.8.xml +++ b/modules/pam_securetty/pam_securetty.8.xml @@ -35,7 +35,8 @@ to make sure that /etc/securetty is a plain file and not world writable. It will also allow root logins on the tty specified with switch on the - kernel command line. + kernel command line and on ttys from the + /sys/class/tty/console/active. This module has no effect on non-root users and requires that the @@ -70,8 +71,9 @@ Do not automatically allow root logins on the kernel console - device, as specified on the kernel command line, if it is - not also specified in the /etc/securetty file. + device, as specified on the kernel command line or by the sys file, + if it is not also specified in the + /etc/securetty file. diff --git a/modules/pam_securetty/pam_securetty.c b/modules/pam_securetty/pam_securetty.c index 99c6371f..4e97ef59 100644 --- a/modules/pam_securetty/pam_securetty.c +++ b/modules/pam_securetty/pam_securetty.c @@ -3,6 +3,7 @@ #define SECURETTY_FILE "/etc/securetty" #define TTY_PREFIX "/dev/" #define CMDLINE_FILE "/proc/cmdline" +#define CONSOLEACTIVE_FILE "/sys/class/tty/console/active" /* * by Elliot Lee , Red Hat Software. @@ -169,7 +170,7 @@ securetty_perform_check (pam_handle_t *pamh, int ctrl, if (p > line && p[-1] != ' ') continue; - /* Ist this our console? */ + /* Is this our console? */ if (strncmp(p + 8, uttyname, strlen(uttyname))) continue; @@ -182,6 +183,36 @@ securetty_perform_check (pam_handle_t *pamh, int ctrl, } } } + if (retval && !(ctrl & PAM_NOCONSOLE_ARG)) { + FILE *consoleactivefile; + + /* Allow access from the active console */ + consoleactivefile = fopen(CONSOLEACTIVE_FILE, "r"); + + if (consoleactivefile != NULL) { + char line[LINE_MAX], *p, *n; + + line[0] = 0; + p = fgets(line, sizeof(line), consoleactivefile); + fclose(consoleactivefile); + + if (p) { + /* remove the newline character at end */ + if (line[strlen(line)-1] == '\n') + line[strlen(line)-1] = 0; + + for (n = p; n != NULL; p = n+1) { + if ((n = strchr(p, ' ')) != NULL) + *n = '\0'; + + if (strcmp(p, uttyname) == 0) { + retval = 0; + break; + } + } + } + } + } if (retval) { pam_syslog(pamh, LOG_WARNING, "access denied: tty '%s' is not secure !", -- cgit v1.2.3 From 0fda81ee5bdc656554d55fb8d6f40c39bae3a3bf Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Tue, 14 Jun 2011 15:28:05 +0200 Subject: 2011-06-14 Thorsten Kukuk * configure.in: Check for libtirpc bye default. * libpam/Makefile.am: Add support for libtirpc. * modules/pam_access/Makefile.am: Likewise. * modules/pam_unix/Makefile.am: Likewise. * modules/pam_unix/pam_unix_passwd.c: Change ifdefs for new libtirpc support. * modules/pam_unix/yppasswd_xdr.c: Only compile if we have rpc/rpc.h. --- modules/pam_access/Makefile.am | 4 ++-- modules/pam_unix/Makefile.am | 5 ++-- modules/pam_unix/pam_unix_passwd.c | 48 ++++++++++++++++++++++++-------------- modules/pam_unix/yppasswd_xdr.c | 4 ++++ 4 files changed, 39 insertions(+), 22 deletions(-) (limited to 'modules') diff --git a/modules/pam_access/Makefile.am b/modules/pam_access/Makefile.am index b4fea7df..89222b56 100644 --- a/modules/pam_access/Makefile.am +++ b/modules/pam_access/Makefile.am @@ -15,14 +15,14 @@ securelibdir = $(SECUREDIR) secureconfdir = $(SCONFIGDIR) AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ - -DPAM_ACCESS_CONFIG=\"$(SCONFIGDIR)/access.conf\" + -DPAM_ACCESS_CONFIG=\"$(SCONFIGDIR)/access.conf\" $(NIS_CFLAGS) AM_LDFLAGS = -no-undefined -avoid-version -module if HAVE_VERSIONING AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map endif securelib_LTLIBRARIES = pam_access.la -pam_access_la_LIBADD = -L$(top_builddir)/libpam -lpam @LIBNSL@ +pam_access_la_LIBADD = -L$(top_builddir)/libpam -lpam $(NIS_LIBS) secureconf_DATA = access.conf diff --git a/modules/pam_unix/Makefile.am b/modules/pam_unix/Makefile.am index 44b37e94..ba77d39f 100644 --- a/modules/pam_unix/Makefile.am +++ b/modules/pam_unix/Makefile.am @@ -18,7 +18,8 @@ secureconfdir = $(SCONFIGDIR) AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ -DCHKPWD_HELPER=\"$(sbindir)/unix_chkpwd\" \ - -DUPDATE_HELPER=\"$(sbindir)/unix_update\" + -DUPDATE_HELPER=\"$(sbindir)/unix_update\" \ + $(NIS_CFLAGS) if HAVE_LIBSELINUX AM_CFLAGS += -D"WITH_SELINUX" @@ -28,7 +29,7 @@ pam_unix_la_LDFLAGS = -no-undefined -avoid-version -module if HAVE_VERSIONING pam_unix_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map endif -pam_unix_la_LIBADD = @LIBNSL@ -L$(top_builddir)/libpam -lpam \ +pam_unix_la_LIBADD = $(NIS_LIBS) -L$(top_builddir)/libpam -lpam \ @LIBCRYPT@ @LIBSELINUX@ securelib_LTLIBRARIES = pam_unix.la diff --git a/modules/pam_unix/pam_unix_passwd.c b/modules/pam_unix/pam_unix_passwd.c index 320bc547..631df318 100644 --- a/modules/pam_unix/pam_unix_passwd.c +++ b/modules/pam_unix/pam_unix_passwd.c @@ -54,13 +54,6 @@ #include #include #include -#include -#ifdef HAVE_RPCSVC_YP_PROT_H -#include -#endif -#ifdef HAVE_RPCSVC_YPCLNT_H -#include -#endif #include #include @@ -76,16 +69,33 @@ #include #include -#include "yppasswd.h" #include "md5.h" #include "support.h" #include "passverify.h" #include "bigcrypt.h" -#if !((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)) +#if (HAVE_YP_GET_DEFAULT_DOMAIN || HAVE_GETDOMAINNAME) && HAVE_YP_MASTER +# define HAVE_NIS +#endif + +#ifdef HAVE_NIS +# include + +# if HAVE_RPCSVC_YP_PROT_H +# include +# endif + +# if HAVE_RPCSVC_YPCLNT_H +# include +# endif + +# include "yppasswd.h" + +# if !HAVE_DECL_GETRPCPORT extern int getrpcport(const char *host, unsigned long prognum, unsigned long versnum, unsigned int proto); -#endif /* GNU libc 2.1 */ +# endif /* GNU libc 2.1 */ +#endif /* How it works: @@ -102,9 +112,9 @@ extern int getrpcport(const char *host, unsigned long prognum, #define MAX_PASSWD_TRIES 3 +#ifdef HAVE_NIS static char *getNISserver(pam_handle_t *pamh, unsigned int ctrl) { -#if (defined(HAVE_YP_GET_DEFAULT_DOMAIN) || defined(HAVE_GETDOMAINNAME)) && defined(HAVE_YP_MASTER) char *master; char *domainname; int port, err; @@ -151,14 +161,8 @@ static char *getNISserver(pam_handle_t *pamh, unsigned int ctrl) master, port); } return master; -#else - if (on(UNIX_DEBUG, ctrl)) { - pam_syslog(pamh, LOG_DEBUG, "getNISserver: No NIS support available"); - } - - return NULL; -#endif } +#endif #ifdef WITH_SELINUX @@ -326,6 +330,7 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, } if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) { +#ifdef HAVE_NIS if ((master=getNISserver(pamh, ctrl)) != NULL) { struct timeval timeout; struct yppasswd yppwd; @@ -391,6 +396,13 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, } else { retval = PAM_TRY_AGAIN; } +#else + if (on(UNIX_DEBUG, ctrl)) { + pam_syslog(pamh, LOG_DEBUG, "No NIS support available"); + } + + retval = PAM_TRY_AGAIN; +#endif } if (_unix_comesfromsource(pamh, forwho, 1, 0)) { diff --git a/modules/pam_unix/yppasswd_xdr.c b/modules/pam_unix/yppasswd_xdr.c index 0b95b82b..f2b86a56 100644 --- a/modules/pam_unix/yppasswd_xdr.c +++ b/modules/pam_unix/yppasswd_xdr.c @@ -12,6 +12,8 @@ #include "config.h" +#ifdef HAVE_RPC_RPC_H + #include #include "yppasswd.h" @@ -34,3 +36,5 @@ xdr_yppasswd(XDR * xdrs, yppasswd * objp) return xdr_string(xdrs, &objp->oldpass, ~0) && xdr_xpasswd(xdrs, &objp->newpw); } + +#endif -- cgit v1.2.3 From 62748f7df90225dc0635944ef59e6e4754c302c0 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 15 Jun 2011 18:48:12 +0200 Subject: Avoid leaking memory and dir handle on realloc failure. --- modules/pam_sepermit/pam_sepermit.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'modules') diff --git a/modules/pam_sepermit/pam_sepermit.c b/modules/pam_sepermit/pam_sepermit.c index 8b2360b5..4879b685 100644 --- a/modules/pam_sepermit/pam_sepermit.c +++ b/modules/pam_sepermit/pam_sepermit.c @@ -117,6 +117,7 @@ check_running (pam_handle_t *pamh, uid_t uid, int killall, int debug) max_pids = 256; pid_table = malloc(max_pids * sizeof (pid_t)); if (!pid_table) { + (void)closedir(dir); pam_syslog(pamh, LOG_CRIT, "Memory allocation error"); return -1; } @@ -126,10 +127,15 @@ check_running (pam_handle_t *pamh, uid_t uid, int killall, int debug) continue; if (pids == max_pids) { - if (!(pid_table = realloc(pid_table, 2*pids*sizeof(pid_t)))) { + pid_t *npt; + + if (!(npt = realloc(pid_table, 2*pids*sizeof(pid_t)))) { + free(pid_table); + (void)closedir(dir); pam_syslog(pamh, LOG_CRIT, "Memory allocation error"); return -1; } + pid_table = npt; max_pids *= 2; } pid_table[pids++] = pid; @@ -175,8 +181,8 @@ sepermit_unlock(pam_handle_t *pamh, void *plockfd, int error_status UNUSED) while(check_running(pamh, lockfd->uid, 1, lockfd->debug) > 0) continue; - fcntl(lockfd->fd, F_SETLK, &fl); - close(lockfd->fd); + (void)fcntl(lockfd->fd, F_SETLK, &fl); + (void)close(lockfd->fd); free(lockfd); } -- cgit v1.2.3 From ff7c230341fc4bd2266b9ddaf39d83683f12c040 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 15 Jun 2011 20:48:59 +0200 Subject: Cleanups of pam_pwhistory code. Make opasswd entry parsing more robust. * modules/pam_pwhistory/opasswd.c (check_old_password): Do not needlessly call strdupa(). (save_old_password): Avoid memleaks in error paths. Avoid memleak of buf. Make the opasswd entry parsing more robust. * modules/pam_pwhistory/pam_pwhistory.8.xml: Document the special meaning of remember=0. --- modules/pam_pwhistory/opasswd.c | 57 ++++++++++++++++++------------- modules/pam_pwhistory/pam_pwhistory.8.xml | 4 ++- 2 files changed, 36 insertions(+), 25 deletions(-) (limited to 'modules') diff --git a/modules/pam_pwhistory/opasswd.c b/modules/pam_pwhistory/opasswd.c index f045555f..738483ac 100644 --- a/modules/pam_pwhistory/opasswd.c +++ b/modules/pam_pwhistory/opasswd.c @@ -181,15 +181,13 @@ check_old_password (pam_handle_t *pamh, const char *user, fclose (oldpf); - if (found) + if (found && entry.old_passwords) { const char delimiters[] = ","; char *running; char *oldpass; - running = strdupa (entry.old_passwords); - if (running == NULL) - return PAM_BUF_ERR; + running = entry.old_passwords; do { oldpass = strsep (&running, delimiters); @@ -311,8 +309,12 @@ save_old_password (pam_handle_t *pamh, const char *user, uid_t uid, buflen = DEFAULT_BUFLEN; buf = malloc (buflen); if (buf == NULL) - return PAM_BUF_ERR; - + { + fclose (oldpf); + fclose (newpf); + retval = PAM_BUF_ERR; + goto error_opasswd; + } } buf[0] = '\0'; fgets (buf, buflen - 1, oldpf); @@ -322,7 +324,12 @@ save_old_password (pam_handle_t *pamh, const char *user, uid_t uid, cp = buf; save = strdup (buf); /* Copy to write the original data back. */ if (save == NULL) - return PAM_BUF_ERR; + { + fclose (oldpf); + fclose (newpf); + retval = PAM_BUF_ERR; + goto error_opasswd; + } if (n < 1) break; @@ -351,31 +358,30 @@ save_old_password (pam_handle_t *pamh, const char *user, uid_t uid, found = 1; /* Don't save the current password twice */ - if (entry.old_passwords) + if (entry.old_passwords && entry.old_passwords[0] != '\0') { - /* there is only one password */ - if (strcmp (entry.old_passwords, oldpass) == 0) - goto write_old_data; - else + char *last = entry.old_passwords; + + cp = entry.old_passwords; + entry.count = 1; /* Don't believe the count */ + while ((cp = strchr (cp, ',')) != NULL) { - /* check last entry */ - cp = strstr (entry.old_passwords, oldpass); - - if (cp && strcmp (cp, oldpass) == 0) - { /* the end is the same, check that there - is a "," before. */ - --cp; - if (*cp == ',') - goto write_old_data; - } + entry.count++; + last = ++cp; } + + /* compare the last password */ + if (strcmp (last, oldpass) == 0) + goto write_old_data; } + else + entry.count = 0; /* increase count. */ entry.count++; /* check that we don't remember to many passwords. */ - while (entry.count > howmany) + while (entry.count > howmany && entry.count > 1) { char *p = strpbrk (entry.old_passwords, ","); if (p != NULL) @@ -383,12 +389,13 @@ save_old_password (pam_handle_t *pamh, const char *user, uid_t uid, entry.count--; } - if (entry.old_passwords == NULL) + if (entry.count == 1) { if (asprintf (&out, "%s:%s:%d:%s\n", entry.user, entry.uid, entry.count, oldpass) < 0) { + free (save); retval = PAM_AUTHTOK_ERR; fclose (oldpf); fclose (newpf); @@ -401,6 +408,7 @@ save_old_password (pam_handle_t *pamh, const char *user, uid_t uid, entry.user, entry.uid, entry.count, entry.old_passwords, oldpass) < 0) { + free (save); retval = PAM_AUTHTOK_ERR; fclose (oldpf); fclose (newpf); @@ -493,6 +501,7 @@ save_old_password (pam_handle_t *pamh, const char *user, uid_t uid, rename (opasswd_tmp, OLD_PASSWORDS_FILE); error_opasswd: unlink (opasswd_tmp); + free (buf); return retval; } diff --git a/modules/pam_pwhistory/pam_pwhistory.8.xml b/modules/pam_pwhistory/pam_pwhistory.8.xml index 7696353f..9e1056b2 100644 --- a/modules/pam_pwhistory/pam_pwhistory.8.xml +++ b/modules/pam_pwhistory/pam_pwhistory.8.xml @@ -105,7 +105,9 @@ The last N passwords for each user are saved in /etc/security/opasswd. - The default is 10. + The default is 10. Value of + 0 makes the module to keep the existing + contents of the opasswd file unchanged. -- cgit v1.2.3 From 53d6722ab192193c77d187645a31949d3de65f2b Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 15 Jun 2011 20:55:30 +0200 Subject: Do not crash when remember, minlen, or rounds options are used with wrong module type. --- modules/pam_unix/support.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'modules') diff --git a/modules/pam_unix/support.c b/modules/pam_unix/support.c index 0b8d4d64..cc350e58 100644 --- a/modules/pam_unix/support.c +++ b/modules/pam_unix/support.c @@ -83,7 +83,7 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int *rounds, } /* now parse the arguments to this module */ - while (argc-- > 0) { + for (; argc-- > 0; ++argv) { int j; D(("pam_unix arg: %s", *argv)); @@ -99,24 +99,37 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int *rounds, pam_syslog(pamh, LOG_ERR, "unrecognized option [%s]", *argv); } else { - ctrl &= unix_args[j].mask; /* for turning things off */ - ctrl |= unix_args[j].flag; /* for turning things on */ - /* special cases */ - if (remember != NULL && j == UNIX_REMEMBER_PASSWD) { + if (j == UNIX_REMEMBER_PASSWD) { + if (remember == NULL) { + pam_syslog(pamh, LOG_ERR, + "option remember not allowed for this module type"); + continue; + } *remember = strtol(*argv + 9, NULL, 10); if ((*remember == INT_MIN) || (*remember == INT_MAX)) *remember = -1; if (*remember > 400) *remember = 400; - } else if (pass_min_len && j == UNIX_MIN_PASS_LEN) { + } else if (j == UNIX_MIN_PASS_LEN) { + if (pass_min_len == NULL) { + pam_syslog(pamh, LOG_ERR, + "option minlen not allowed for this module type"); + continue; + } *pass_min_len = atoi(*argv + 7); - } - if (rounds != NULL && j == UNIX_ALGO_ROUNDS) + } else if (j == UNIX_ALGO_ROUNDS) { + if (rounds == NULL) { + pam_syslog(pamh, LOG_ERR, + "option rounds not allowed for this module type"); + continue; + } *rounds = strtol(*argv + 7, NULL, 10); - } + } - ++argv; /* step to next argument */ + ctrl &= unix_args[j].mask; /* for turning things off */ + ctrl |= unix_args[j].flag; /* for turning things on */ + } } if (UNIX_DES_CRYPT(ctrl) @@ -132,7 +145,7 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int *rounds, } /* Set default rounds for blowfish */ - if (on(UNIX_BLOWFISH_PASS, ctrl) && off(UNIX_ALGO_ROUNDS, ctrl)) { + if (on(UNIX_BLOWFISH_PASS, ctrl) && off(UNIX_ALGO_ROUNDS, ctrl) && rounds != NULL) { *rounds = 5; set(UNIX_ALGO_ROUNDS, ctrl); } -- cgit v1.2.3 From 2daaafacf771746a11849ada2166f8ac2bab1348 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 15 Jun 2011 20:58:32 +0200 Subject: Avoid memleaks and fd leak in error paths. --- modules/pam_timestamp/pam_timestamp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'modules') diff --git a/modules/pam_timestamp/pam_timestamp.c b/modules/pam_timestamp/pam_timestamp.c index 7bcf3d12..51937333 100644 --- a/modules/pam_timestamp/pam_timestamp.c +++ b/modules/pam_timestamp/pam_timestamp.c @@ -483,6 +483,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) pam_syslog(pamh, LOG_NOTICE, "timestamp file `%s' is " "corrupted", path); close(fd); + free(mac); free(message); return PAM_AUTH_ERR; } @@ -636,6 +637,8 @@ pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, int argc, const char * "error setting ownership of `%s': %m", path); } + close(fd); + free(text); return PAM_SESSION_ERR; } -- cgit v1.2.3 From 50e4a02c87e91807db381cf308fdbf993a82105c Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 15 Jun 2011 20:59:53 +0200 Subject: Initialize the fake_item from item. --- modules/pam_access/pam_access.c | 1 + 1 file changed, 1 insertion(+) (limited to 'modules') diff --git a/modules/pam_access/pam_access.c b/modules/pam_access/pam_access.c index daee47da..0eb1e8c6 100644 --- a/modules/pam_access/pam_access.c +++ b/modules/pam_access/pam_access.c @@ -525,6 +525,7 @@ user_match (pam_handle_t *pamh, char *tok, struct login_info *item) /* split user@host pattern */ if (item->hostname == NULL) return NO; + memcpy (&fake_item, item, sizeof(fake_item)); fake_item.from = item->hostname; *at = 0; return (user_match (pamh, tok, item) && -- cgit v1.2.3 From 792d7c1b1e5b751d9738da214361e5ae826aa973 Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Tue, 21 Jun 2011 11:05:31 +0200 Subject: 2011-06-21 Thorsten Kukuk * modules/pam_limits/pam_limits.c: Add set_all option, read limits from PID one if no limit is specified and set_all is set. * modules/pam_limits/pam_limits.8.xml: Document set_all option. Based on Patch by Kees Cook. --- modules/pam_limits/pam_limits.8.xml | 15 ++++ modules/pam_limits/pam_limits.c | 162 ++++++++++++++++++++++++++++++++++-- 2 files changed, 172 insertions(+), 5 deletions(-) (limited to 'modules') diff --git a/modules/pam_limits/pam_limits.8.xml b/modules/pam_limits/pam_limits.8.xml index 7b944f9e..663c0e7b 100644 --- a/modules/pam_limits/pam_limits.8.xml +++ b/modules/pam_limits/pam_limits.8.xml @@ -28,6 +28,9 @@ debug + + set_all + utmp_early @@ -88,6 +91,18 @@ + + + + + + + Set the limits for which no value is specified in the + configuration file to the one from the process with the + PID 1. + + + diff --git a/modules/pam_limits/pam_limits.c b/modules/pam_limits/pam_limits.c index 88146523..c1810e07 100644 --- a/modules/pam_limits/pam_limits.c +++ b/modules/pam_limits/pam_limits.c @@ -51,9 +51,10 @@ #define LIMITS_DEF_USER 0 /* limit was set by an user entry */ #define LIMITS_DEF_GROUP 1 /* limit was set by a group entry */ #define LIMITS_DEF_ALLGROUP 2 /* limit was set by a group entry */ -#define LIMITS_DEF_ALL 3 /* limit was set by an default entry */ -#define LIMITS_DEF_DEFAULT 4 /* limit was set by an default entry */ -#define LIMITS_DEF_NONE 5 /* this limit was not set yet */ +#define LIMITS_DEF_ALL 3 /* limit was set by an all entry */ +#define LIMITS_DEF_DEFAULT 4 /* limit was set by a default entry */ +#define LIMITS_DEF_KERNEL 5 /* limit was set from /proc/1/limits */ +#define LIMITS_DEF_NONE 6 /* this limit was not set yet */ #define LIMIT_RANGE_ERR -1 /* error in specified uid/gid range */ #define LIMIT_RANGE_NONE 0 /* no range specified */ @@ -67,6 +68,7 @@ static const char *limits_def_names[] = { "ALLGROUP", "ALL", "DEFAULT", + "KERNEL", "NONE", NULL }; @@ -111,6 +113,7 @@ struct pam_limit_s { #define PAM_DEBUG_ARG 0x0001 #define PAM_UTMP_EARLY 0x0004 #define PAM_NO_AUDIT 0x0008 +#define PAM_SET_ALL 0x0010 /* Limits from globbed files. */ #define LIMITS_CONF_GLOB LIMITS_FILE_DIR @@ -136,6 +139,8 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv, ctrl |= PAM_UTMP_EARLY; } else if (!strcmp(*argv,"noaudit")) { ctrl |= PAM_NO_AUDIT; + } else if (!strcmp(*argv,"set_all")) { + ctrl |= PAM_SET_ALL; } else { pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv); } @@ -292,7 +297,140 @@ check_logins (pam_handle_t *pamh, const char *name, int limit, int ctrl, return 0; } -static int init_limits(struct pam_limit_s *pl) +static const char *lnames[RLIM_NLIMITS] = { + [RLIMIT_CPU] = "Max cpu time", + [RLIMIT_FSIZE] = "Max file size", + [RLIMIT_DATA] = "Max data size", + [RLIMIT_STACK] = "Max stack size", + [RLIMIT_CORE] = "Max core file size", + [RLIMIT_RSS] = "Max resident set", + [RLIMIT_NPROC] = "Max processes", + [RLIMIT_NOFILE] = "Max open files", + [RLIMIT_MEMLOCK] = "Max locked memory", +#ifdef RLIMIT_AS + [RLIMIT_AS] = "Max address space", +#endif +#ifdef RLIMIT_LOCKS + [RLIMIT_LOCKS] = "Max file locks", +#endif +#ifdef RLIMIT_SIGPENDING + [RLIMIT_SIGPENDING] = "Max pending signals", +#endif +#ifdef RLIMIT_MSGQUEUE + [RLIMIT_MSGQUEUE] = "Max msgqueue size", +#endif +#ifdef RLIMIT_NICE + [RLIMIT_NICE] = "Max nice priority", +#endif +#ifdef RLIMIT_RTPRIO + [RLIMIT_RTPRIO] = "Max realtime priority", +#endif +#ifdef RLIMIT_RTTIME + [RLIMIT_RTTIME] = "Max realtime timeout", +#endif +}; + +static int str2rlimit(char *name) { + int i; + if (!name || *name == '\0') + return -1; + for(i = 0; i < RLIM_NLIMITS; i++) { + if (strcmp(name, lnames[i]) == 0) return i; + } + return -1; +} + +static rlim_t str2rlim_t(char *value) { + unsigned long long rlimit = 0; + + if (!value) return (rlim_t)rlimit; + if (strcmp(value, "unlimited") == 0) { + return RLIM_INFINITY; + } + rlimit = strtoull(value, NULL, 10); + return (rlim_t)rlimit; +} + +#define LIMITS_SKIP_WHITESPACE { \ + /* step backwards over spaces */ \ + pos--; \ + while (pos && line[pos] == ' ') pos--; \ + if (!pos) continue; \ + line[pos+1] = '\0'; \ +} +#define LIMITS_MARK_ITEM(item) { \ + /* step backwards over non-spaces */ \ + pos--; \ + while (pos && line[pos] != ' ') pos--; \ + if (!pos) continue; \ + item = line + pos + 1; \ +} + +static void parse_kernel_limits(pam_handle_t *pamh, struct pam_limit_s *pl, int ctrl) +{ + int i, maxlen = 0; + FILE *limitsfile; + const char *proclimits = "/proc/1/limits"; + char line[256]; + char *units, *hard, *soft, *name; + + if (!(limitsfile = fopen(proclimits, "r"))) { + pam_syslog(pamh, LOG_WARNING, "Could not read %s (%s), using PAM defaults", proclimits, strerror(errno)); + return; + } + + while (fgets(line, 256, limitsfile)) { + int pos = strlen(line); + if (pos < 2) continue; + + /* drop trailing newline */ + if (line[pos-1] == '\n') { + pos--; + line[pos] = '\0'; + } + + /* determine formatting boundry of limits report */ + if (!maxlen && strncmp(line, "Limit", 5) == 0) { + maxlen = pos; + continue; + } + + if (pos == maxlen) { + /* step backwards over "Units" name */ + LIMITS_SKIP_WHITESPACE; + LIMITS_MARK_ITEM(units); + } + else { + units = ""; + } + + /* step backwards over "Hard Limit" value */ + LIMITS_SKIP_WHITESPACE; + LIMITS_MARK_ITEM(hard); + + /* step backwards over "Soft Limit" value */ + LIMITS_SKIP_WHITESPACE; + LIMITS_MARK_ITEM(soft); + + /* step backwards over name of limit */ + LIMITS_SKIP_WHITESPACE; + name = line; + + i = str2rlimit(name); + if (i < 0 || i >= RLIM_NLIMITS) { + if (ctrl & PAM_DEBUG_ARG) + pam_syslog(pamh, LOG_DEBUG, "Unknown kernel rlimit '%s' ignored", name); + continue; + } + pl->limits[i].limit.rlim_cur = str2rlim_t(soft); + pl->limits[i].limit.rlim_max = str2rlim_t(hard); + pl->limits[i].src_soft = LIMITS_DEF_KERNEL; + pl->limits[i].src_hard = LIMITS_DEF_KERNEL; + } + fclose(limitsfile); +} + +static int init_limits(pam_handle_t *pamh, struct pam_limit_s *pl, int ctrl) { int i; int retval = PAM_SUCCESS; @@ -313,6 +451,20 @@ static int init_limits(struct pam_limit_s *pl) } } +#ifdef __linux__ + if (ctrl & PAM_SET_ALL) { + parse_kernel_limits(pamh, pl, ctrl); + + for(i = 0; i < RLIM_NLIMITS; i++) { + if (pl->limits[i].supported && + (pl->limits[i].src_soft == LIMITS_DEF_NONE || + pl->limits[i].src_hard == LIMITS_DEF_NONE)) { + pam_syslog(pamh, LOG_WARNING, "Did not find kernel RLIMIT for %s, using PAM default", rlimit2str(i)); + } + } + } +#endif + errno = 0; pl->priority = getpriority (PRIO_PROCESS, 0); if (pl->priority == -1 && errno != 0) @@ -873,7 +1025,7 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, return PAM_USER_UNKNOWN; } - retval = init_limits(pl); + retval = init_limits(pamh, pl, ctrl); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_WARNING, "cannot initialize"); return PAM_ABORT; -- cgit v1.2.3 From 01e04364faedc820de207bd3c8ecd0becf0e9fa3 Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Fri, 24 Jun 2011 12:45:27 +0200 Subject: Fix order of libraries --- modules/pam_unix/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'modules') diff --git a/modules/pam_unix/Makefile.am b/modules/pam_unix/Makefile.am index ba77d39f..ea5a7318 100644 --- a/modules/pam_unix/Makefile.am +++ b/modules/pam_unix/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2006, 2009 Thorsten Kukuk +# Copyright (c) 2005, 2006, 2009, 2011 Thorsten Kukuk # CLEANFILES = *~ @@ -29,8 +29,8 @@ pam_unix_la_LDFLAGS = -no-undefined -avoid-version -module if HAVE_VERSIONING pam_unix_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map endif -pam_unix_la_LIBADD = $(NIS_LIBS) -L$(top_builddir)/libpam -lpam \ - @LIBCRYPT@ @LIBSELINUX@ +pam_unix_la_LIBADD = -L$(top_builddir)/libpam -lpam \ + @LIBCRYPT@ @LIBSELINUX@ $(NIS_LIBS) securelib_LTLIBRARIES = pam_unix.la -- cgit v1.2.3 From ca6fbe92205fe5b4acf2e92e4c2bf73327b26780 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 23 Aug 2011 12:42:32 +0200 Subject: Fix missing dereference. --- modules/pam_env/pam_env.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'modules') diff --git a/modules/pam_env/pam_env.c b/modules/pam_env/pam_env.c index 865fbafe..1ec01ca5 100644 --- a/modules/pam_env/pam_env.c +++ b/modules/pam_env/pam_env.c @@ -99,7 +99,7 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv, if (!strcmp(*argv,"debug")) ctrl |= PAM_DEBUG_ARG; else if (!strncmp(*argv,"conffile=",9)) { - if (*argv+9 == '\0') { + if ((*argv)[9] == '\0') { pam_syslog(pamh, LOG_ERR, "conffile= specification missing argument - ignored"); } else { @@ -107,7 +107,7 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv, D(("new Configuration File: %s", *conffile)); } } else if (!strncmp(*argv,"envfile=",8)) { - if (*argv+8 == '\0') { + if ((*argv)[8] == '\0') { pam_syslog (pamh, LOG_ERR, "envfile= specification missing argument - ignored"); } else { @@ -115,7 +115,7 @@ _pam_parse (const pam_handle_t *pamh, int argc, const char **argv, D(("new Env File: %s", *envfile)); } } else if (!strncmp(*argv,"user_envfile=",13)) { - if (*argv+13 == '\0') { + if ((*argv)[13] == '\0') { pam_syslog (pamh, LOG_ERR, "user_envfile= specification missing argument - ignored"); } else { -- cgit v1.2.3 From 61f4f06abc9b8fcb3c478fa430b52499fd2ca300 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 25 Aug 2011 15:48:51 +0200 Subject: Fix the split on @ in the user field. (Red Hat Bug #732081) --- modules/pam_access/pam_access.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/pam_access/pam_access.c b/modules/pam_access/pam_access.c index 0eb1e8c6..472116c3 100644 --- a/modules/pam_access/pam_access.c +++ b/modules/pam_access/pam_access.c @@ -521,7 +521,10 @@ user_match (pam_handle_t *pamh, char *tok, struct login_info *item) * name of the user's primary group. */ - if (tok[0] != '@' && (at = strchr(tok + 1, '@')) != 0) { + /* Try to split on a pattern (@*[^@]+)(@+.*) */ + for (at = tok; *at == '@'; ++at); + + if ((at = strchr(at, '@')) != NULL) { /* split user@host pattern */ if (item->hostname == NULL) return NO; -- cgit v1.2.3 From 3d8a20af1f5f32ad7e4abf26057e8ef2193bc190 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 25 Aug 2011 16:02:42 +0200 Subject: Correct the FSF address. --- modules/pam_loginuid/pam_loginuid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c index 4fa486c7..06479973 100644 --- a/modules/pam_loginuid/pam_loginuid.c +++ b/modules/pam_loginuid/pam_loginuid.c @@ -14,7 +14,8 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500 + * Boston, MA 02110-1335 USA * * Authors: * Steve Grubb -- cgit v1.2.3 From 6eaacb1584c11373d96313dd17f72ab89cf5654d Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 10 Oct 2011 14:02:10 +0200 Subject: Add hostname resolution cache. --- modules/pam_access/pam_access.c | 54 ++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 19 deletions(-) (limited to 'modules') diff --git a/modules/pam_access/pam_access.c b/modules/pam_access/pam_access.c index 472116c3..35b7d058 100644 --- a/modules/pam_access/pam_access.c +++ b/modules/pam_access/pam_access.c @@ -106,6 +106,8 @@ struct login_info { const char *fs; /* field separator */ const char *sep; /* list-element separator */ int from_remote_host; /* If PAM_RHOST was used for from */ + struct addrinfo *res; /* Cached DNS resolution of from */ + int gai_rv; /* Cached retval of getaddrinfo */ }; /* Parse module config arguments */ @@ -168,7 +170,7 @@ static int user_match (pam_handle_t *, char *, struct login_info *); static int group_match (pam_handle_t *, const char *, const char *, int); static int from_match (pam_handle_t *, char *, struct login_info *); static int string_match (pam_handle_t *, const char *, const char *, int); -static int network_netmask_match (pam_handle_t *, const char *, const char *, int); +static int network_netmask_match (pam_handle_t *, const char *, const char *, struct login_info *); /* isipaddr - find out if string provided is an IP address or not */ @@ -530,9 +532,16 @@ user_match (pam_handle_t *pamh, char *tok, struct login_info *item) return NO; memcpy (&fake_item, item, sizeof(fake_item)); fake_item.from = item->hostname; + fake_item.gai_rv = 0; + fake_item.res = NULL; + fake_item.from_remote_host = 1; /* hostname should be resolvable */ *at = 0; - return (user_match (pamh, tok, item) && - from_match (pamh, at + 1, &fake_item)); + if (!user_match (pamh, tok, item)) + return NO; + rv = from_match (pamh, at + 1, &fake_item); + if (fake_item.gai_rv == 0 && fake_item.res) + freeaddrinfo(fake_item.res); + return rv; } else if (tok[0] == '@') { /* netgroup */ const char *hostname = NULL; if (tok[1] == '@') { /* add hostname to netgroup match */ @@ -616,22 +625,24 @@ from_match (pam_handle_t *pamh UNUSED, char *tok, struct login_info *item) if ((str_len = strlen(string)) > (tok_len = strlen(tok)) && strcasecmp(tok, string + str_len - tok_len) == 0) return (YES); - } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no PAM_RHOSTS */ - if (item->from_remote_host == 0) + } else if (item->from_remote_host == 0) { /* local: no PAM_RHOSTS */ + if (strcasecmp(tok, "LOCAL") == 0) return (YES); } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { - struct addrinfo *res; struct addrinfo hint; memset (&hint, '\0', sizeof (hint)); hint.ai_flags = AI_CANONNAME; hint.ai_family = AF_INET; - if (getaddrinfo (string, NULL, &hint, &res) != 0) + if (item->gai_rv != 0) + return NO; + else if (!item->res && + (item->gai_rv = getaddrinfo (string, NULL, &hint, &item->res)) != 0) return NO; else { - struct addrinfo *runp = res; + struct addrinfo *runp = item->res; while (runp != NULL) { @@ -647,17 +658,15 @@ from_match (pam_handle_t *pamh UNUSED, char *tok, struct login_info *item) if (strncmp(tok, buf, tok_len) == 0) { - freeaddrinfo (res); return YES; } } runp = runp->ai_next; } - freeaddrinfo (res); } } else { /* Assume network/netmask with a IP of a host. */ - if (network_netmask_match(pamh, tok, string, item->debug)) + if (network_netmask_match(pamh, tok, string, item)) return YES; } @@ -700,13 +709,13 @@ string_match (pam_handle_t *pamh, const char *tok, const char *string, */ static int network_netmask_match (pam_handle_t *pamh, - const char *tok, const char *string, int debug) + const char *tok, const char *string, struct login_info *item) { char *netmask_ptr; char netmask_string[MAXHOSTNAMELEN + 1]; int addr_type; - if (debug) + if (item->debug) pam_syslog (pamh, LOG_DEBUG, "network_netmask_match: tok=%s, item=%s", tok, string); /* OK, check if tok is of type addr/mask */ @@ -751,18 +760,20 @@ network_netmask_match (pam_handle_t *pamh, if (isipaddr(string, NULL, NULL) != YES) { /* Assume network/netmask with a name of a host. */ - struct addrinfo *res; struct addrinfo hint; memset (&hint, '\0', sizeof (hint)); hint.ai_flags = AI_CANONNAME; hint.ai_family = AF_UNSPEC; - if (getaddrinfo (string, NULL, &hint, &res) != 0) + if (item->gai_rv != 0) + return NO; + else if (!item->res && + (item->gai_rv = getaddrinfo (string, NULL, &hint, &item->res)) != 0) return NO; else { - struct addrinfo *runp = res; + struct addrinfo *runp = item->res; while (runp != NULL) { @@ -776,12 +787,10 @@ network_netmask_match (pam_handle_t *pamh, if (are_addresses_equal(buf, tok, netmask_ptr)) { - freeaddrinfo (res); return YES; } runp = runp->ai_next; } - freeaddrinfo (res); } } else @@ -803,6 +812,7 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, const char *from; struct passwd *user_pw; char hostname[MAXHOSTNAMELEN + 1]; + int rv; /* set username */ @@ -819,6 +829,7 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, /* * Bundle up the arguments to avoid unnecessary clumsiness later on. */ + memset(&loginfo, '\0', sizeof(loginfo)); loginfo.user = user_pw; loginfo.config_file = PAM_ACCESS_CONFIG; @@ -889,7 +900,12 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, loginfo.hostname = NULL; } - if (login_access(pamh, &loginfo)) { + rv = login_access(pamh, &loginfo); + + if (loginfo.gai_rv == 0 && loginfo.res) + freeaddrinfo(loginfo.res); + + if (rv) { return (PAM_SUCCESS); } else { pam_syslog(pamh, LOG_ERR, -- cgit v1.2.3 From c5cbe7a04f82ac89372dd2765979aac66188dca1 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 10 Oct 2011 14:05:03 +0200 Subject: If getdomainname() fails or domainname not set use NULL as domain in innetgr(). --- modules/pam_access/pam_access.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'modules') diff --git a/modules/pam_access/pam_access.c b/modules/pam_access/pam_access.c index 35b7d058..2669a5ec 100644 --- a/modules/pam_access/pam_access.c +++ b/modules/pam_access/pam_access.c @@ -478,12 +478,10 @@ netgroup_match (pam_handle_t *pamh, const char *netgroup, if (getdomainname (domainname_res, sizeof (domainname_res)) == 0) { - if (strcmp (domainname_res, "(none)") == 0) + if (domainname_res[0] != '\0' && strcmp (domainname_res, "(none)") != 0) { - /* If domainname is not set, some systems will return "(none)" */ - domainname_res[0] = '\0'; - } - mydomain = domainname_res; + mydomain = domainname_res; + } } #endif -- cgit v1.2.3 From caf5e7f61c8d9288daa49b4f61962e6b1239121d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 14 Oct 2011 19:32:25 +0000 Subject: pam_env: correctly count leading whitespace when parsing environment file * modules/pam_env/pam_env.c (_assemble_line): Correctly count leading whitespace. Fixes CVE-2011-3148. Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/pam/+bug/874469 --- modules/pam_env/pam_env.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/pam_env/pam_env.c b/modules/pam_env/pam_env.c index 1ec01ca5..b7cd387f 100644 --- a/modules/pam_env/pam_env.c +++ b/modules/pam_env/pam_env.c @@ -290,6 +290,7 @@ static int _assemble_line(FILE *f, char *buffer, int buf_len) char *p = buffer; char *s, *os; int used = 0; + int whitespace; /* loop broken with a 'break' when a non-'\\n' ended line is read */ @@ -312,8 +313,10 @@ static int _assemble_line(FILE *f, char *buffer, int buf_len) /* skip leading spaces --- line may be blank */ - s = p + strspn(p, " \n\t"); + whitespace = strspn(p, " \n\t"); + s = p + whitespace; if (*s && (*s != '#')) { + used += whitespace; os = s; /* -- cgit v1.2.3 From 109823cb621c900c07c4b6cdc99070d354d19444 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 14 Oct 2011 19:47:23 +0000 Subject: pam_env: abort when encountering an overflowed environment variable expansion * modules/pam_env/pam_env.c (_expand_arg): Abort when encountering an overflowed environment variable expansion. Fixes CVE-2011-3149. Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/pam/+bug/874565 --- modules/pam_env/pam_env.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'modules') diff --git a/modules/pam_env/pam_env.c b/modules/pam_env/pam_env.c index b7cd387f..e04f5b53 100644 --- a/modules/pam_env/pam_env.c +++ b/modules/pam_env/pam_env.c @@ -570,6 +570,7 @@ static int _expand_arg(pam_handle_t *pamh, char **value) D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); pam_syslog (pamh, LOG_ERR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); + return PAM_BUF_ERR; } continue; } @@ -631,6 +632,7 @@ static int _expand_arg(pam_handle_t *pamh, char **value) D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); pam_syslog (pamh, LOG_ERR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); + return PAM_BUF_ERR; } } } /* if ('{' != *orig++) */ @@ -642,6 +644,7 @@ static int _expand_arg(pam_handle_t *pamh, char **value) D(("Variable buffer overflow: <%s> + <%s>", tmp, tmpptr)); pam_syslog(pamh, LOG_ERR, "Variable buffer overflow: <%s> + <%s>", tmp, tmpptr); + return PAM_BUF_ERR; } } } /* for (;*orig;) */ -- cgit v1.2.3 From fc772e7236a7aea9c9c26b0be2ee6f3ed8ae444a Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Tue, 25 Oct 2011 14:24:50 +0200 Subject: 2011-10-25 Thorsten Kukuk * release version 1.1.5 * configure.in: Bump version number. * modules/pam_tally2/pam_tally2.8.xml: Remove never used option "no_lock_time". --- modules/pam_tally2/pam_tally2.8.xml | 12 ---------- modules/pam_xauth/pam_xauth.c | 45 ++++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 30 deletions(-) (limited to 'modules') diff --git a/modules/pam_tally2/pam_tally2.8.xml b/modules/pam_tally2/pam_tally2.8.xml index 4ad529fd..5fecea24 100644 --- a/modules/pam_tally2/pam_tally2.8.xml +++ b/modules/pam_tally2/pam_tally2.8.xml @@ -236,17 +236,6 @@ - - - - - - - Do not use the .fail_locktime field in - /var/log/faillog for this user. - - - @@ -446,4 +435,3 @@ session optional pam_mail.so standard - diff --git a/modules/pam_xauth/pam_xauth.c b/modules/pam_xauth/pam_xauth.c index a64ae89f..88624b1c 100644 --- a/modules/pam_xauth/pam_xauth.c +++ b/modules/pam_xauth/pam_xauth.c @@ -459,24 +459,33 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, goto cleanup; } - /* Check that both users are amenable to this. By default, this - * boils down to this policy: - * export(ruser=root): only if is listed in .xauth/export - * export(ruser=*) if is listed in .xauth/export, or - * if .xauth/export does not exist - * import(user=*): if is listed in .xauth/import, or - * if .xauth/import does not exist */ - i = (getuid() != 0 || tpwd->pw_uid == 0) ? PAM_SUCCESS : PAM_PERM_DENIED; - i = check_acl(pamh, "export", rpwd->pw_name, user, i, debug); - if (i != PAM_SUCCESS) { - retval = PAM_SESSION_ERR; - goto cleanup; - } - i = PAM_SUCCESS; - i = check_acl(pamh, "import", user, rpwd->pw_name, i, debug); - if (i != PAM_SUCCESS) { - retval = PAM_SESSION_ERR; - goto cleanup; + + /* If current user and the target user are the same, don't + check the ACL list, but forward X11 */ + if (strcmp (rpwd->pw_name, tpwd->pw_name) != 0) { + + /* Check that both users are amenable to this. By default, this + * boils down to this policy: + * export(ruser=root): only if is listed in .xauth/export + * export(ruser=*) if is listed in .xauth/export, or + * if .xauth/export does not exist + * import(user=*): if is listed in .xauth/import, or + * if .xauth/import does not exist */ + i = (getuid() != 0 || tpwd->pw_uid == 0) ? PAM_SUCCESS : PAM_PERM_DENIED; + i = check_acl(pamh, "export", rpwd->pw_name, user, i, debug); + if (i != PAM_SUCCESS) { + retval = PAM_SESSION_ERR; + goto cleanup; + } + i = PAM_SUCCESS; + i = check_acl(pamh, "import", user, rpwd->pw_name, i, debug); + if (i != PAM_SUCCESS) { + retval = PAM_SESSION_ERR; + goto cleanup; + } + } else { + if (debug) + pam_syslog (pamh, LOG_DEBUG, "current and target user are the same, forward X11"); } /* Figure out where the source user's .Xauthority file is. */ -- cgit v1.2.3