From 45cdd2489e68465c2d2202370c350069d2a391b8 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Wed, 20 Nov 2013 09:43:50 +0100 Subject: If the correct loginuid is set already, skip writing it. modules/pam_loginuid/pam_loginuid.c (set_loginuid): Read the current loginuid and skip writing if already correctly set. --- modules/pam_loginuid/pam_loginuid.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'modules/pam_loginuid') diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c index 06479973..a903845c 100644 --- a/modules/pam_loginuid/pam_loginuid.c +++ b/modules/pam_loginuid/pam_loginuid.c @@ -52,10 +52,10 @@ static int set_loginuid(pam_handle_t *pamh, uid_t uid) { int fd, count, rc = 0; - char loginuid[24]; + char loginuid[24], buf[24]; count = snprintf(loginuid, sizeof(loginuid), "%lu", (unsigned long)uid); - fd = open("/proc/self/loginuid", O_NOFOLLOW|O_WRONLY|O_TRUNC); + fd = open("/proc/self/loginuid", O_NOFOLLOW|O_RDWR); if (fd < 0) { if (errno != ENOENT) { rc = 1; @@ -64,8 +64,13 @@ static int set_loginuid(pam_handle_t *pamh, uid_t uid) } return rc; } - if (pam_modutil_write(fd, loginuid, count) != count) + if (pam_modutil_read(fd, buf, sizeof(buf)) == count && + memcmp(buf, loginuid, count) == 0) + goto done; /* already correct */ + if (lseek(fd, 0, SEEK_SET) == -1 || (ftruncate(fd, 0) == -1 || + pam_modutil_write(fd, loginuid, count) != count)) rc = 1; + done: close(fd); return rc; } -- cgit v1.2.3 From 5825450540e6620ac331c64345b42fdcbb1d6e87 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Wed, 8 Jan 2014 15:53:30 -0800 Subject: pam_loginuid: return PAM_IGNORE when /proc/self/loginuid does not exist When /proc/self/loginuid does not exist, return PAM_IGNORE instead of PAM_SUCCESS, so that we can distinguish between "loginuid set successfully" and "loginuid not set, but this is expected". Suggested by Steve Langasek. * modules/pam_loginuid/pam_loginuid.c (set_loginuid): Change return code semantics: return PAM_SUCCESS on success, PAM_IGNORE when loginuid does not exist, PAM_SESSION_ERR in case of any other error. (_pam_loginuid): Forward the PAM error code returned by set_loginuid. --- modules/pam_loginuid/pam_loginuid.c | 43 ++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 15 deletions(-) (limited to 'modules/pam_loginuid') diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c index a903845c..96f8ffa5 100644 --- a/modules/pam_loginuid/pam_loginuid.c +++ b/modules/pam_loginuid/pam_loginuid.c @@ -47,29 +47,35 @@ /* * This function writes the loginuid to the /proc system. It returns - * 0 on success and 1 on failure. + * PAM_SUCCESS on success, + * PAM_IGNORE when /proc/self/loginuid does not exist, + * PAM_SESSION_ERR in case of any other error. */ static int set_loginuid(pam_handle_t *pamh, uid_t uid) { - int fd, count, rc = 0; + int fd, count, rc = PAM_SESSION_ERR; char loginuid[24], buf[24]; count = snprintf(loginuid, sizeof(loginuid), "%lu", (unsigned long)uid); fd = open("/proc/self/loginuid", O_NOFOLLOW|O_RDWR); if (fd < 0) { - if (errno != ENOENT) { - rc = 1; + if (errno == ENOENT) { + rc = PAM_IGNORE; + } else { pam_syslog(pamh, LOG_ERR, "Cannot open /proc/self/loginuid: %m"); } return rc; } + if (pam_modutil_read(fd, buf, sizeof(buf)) == count && - memcmp(buf, loginuid, count) == 0) + memcmp(buf, loginuid, count) == 0) { + rc = PAM_SUCCESS; goto done; /* already correct */ - if (lseek(fd, 0, SEEK_SET) == -1 || (ftruncate(fd, 0) == -1 || - pam_modutil_write(fd, loginuid, count) != count)) - rc = 1; + } + if (lseek(fd, 0, SEEK_SET) == 0 && ftruncate(fd, 0) == 0 && + pam_modutil_write(fd, loginuid, count) == count) + rc = PAM_SUCCESS; done: close(fd); return rc; @@ -170,6 +176,7 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED, { const char *user = NULL; struct passwd *pwd; + int ret; #ifdef HAVE_LIBAUDIT int require_auditd = 0; #endif @@ -188,9 +195,14 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED, return PAM_SESSION_ERR; } - if (set_loginuid(pamh, pwd->pw_uid)) { - pam_syslog(pamh, LOG_ERR, "set_loginuid failed\n"); - return PAM_SESSION_ERR; + ret = set_loginuid(pamh, pwd->pw_uid); + switch (ret) { + case PAM_SUCCESS: + case PAM_IGNORE: + break; + default: + pam_syslog(pamh, LOG_ERR, "set_loginuid failed"); + return ret; } #ifdef HAVE_LIBAUDIT @@ -200,11 +212,12 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED, argv++; } - if (require_auditd) - return check_auditd(); - else + if (require_auditd) { + int rc = check_auditd(); + return rc != PAM_SUCCESS ? rc : ret; + } else #endif - return PAM_SUCCESS; + return ret; } /* -- cgit v1.2.3 From 24f3a88e7de52fbfcb7b8a1ebdae0cdbef420edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 7 Jan 2014 16:12:03 -0800 Subject: pam_loginuid: Ignore failure in user namespaces When running pam_loginuid in a container using the user namespaces, even uid 0 isn't allowed to set the loginuid property. This change catches the EACCES from opening loginuid, checks if the user is in the host namespace (by comparing the uid_map with the host's one) and only if that's the case, sets rc to 1. Should uid_map not exist or be unreadable for some reason, it'll be assumed that the process is running on the host's namespace. The initial reason behind this change was failure to ssh into an unprivileged container (using a 3.13 kernel and current LXC) when using a standard pam profile for sshd (which requires success from pam_loginuid). I believe this solution doesn't have any drawback and will allow people to use unprivileged containers normally. An alternative would be to have all distros set pam_loginuid as optional but that'd be bad for any of the other potential failure case which people may care about. There has also been some discussions to get some of the audit features tied with the user namespaces but currently none of that has been merged upstream and the currently proposed implementation doesn't cover loginuid (nor is it clear how this should even work when loginuid is set as immutable after initial write). Signed-off-by: Steve Langasek Signed-off-by: Dmitry V. Levin --- modules/pam_loginuid/pam_loginuid.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'modules/pam_loginuid') diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c index 96f8ffa5..54ae6f07 100644 --- a/modules/pam_loginuid/pam_loginuid.c +++ b/modules/pam_loginuid/pam_loginuid.c @@ -55,13 +55,26 @@ static int set_loginuid(pam_handle_t *pamh, uid_t uid) { int fd, count, rc = PAM_SESSION_ERR; char loginuid[24], buf[24]; + static const char host_uid_map[] = " 0 0 4294967295\n"; + char uid_map[sizeof(host_uid_map)]; count = snprintf(loginuid, sizeof(loginuid), "%lu", (unsigned long)uid); fd = open("/proc/self/loginuid", O_NOFOLLOW|O_RDWR); if (fd < 0) { if (errno == ENOENT) { rc = PAM_IGNORE; - } else { + } else if (errno == EACCES) { + fd = open("/proc/self/uid_map", O_RDONLY); + if (fd >= 0) { + count = pam_modutil_read(fd, uid_map, sizeof(uid_map)); + if (strncmp(uid_map, host_uid_map, count) != 0) + rc = PAM_IGNORE; + close(fd); + } + if (rc != PAM_IGNORE) + errno = EACCES; + } + if (rc != PAM_IGNORE) { pam_syslog(pamh, LOG_ERR, "Cannot open /proc/self/loginuid: %m"); } -- cgit v1.2.3 From 2e62d5aea3f5ac267cfa54f0ea1f8c07ac85a95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Fri, 17 Jan 2014 18:24:16 -0500 Subject: pam_loginuid: Always return PAM_IGNORE in userns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous patch to support user namespaces works fine with containers that are started from a desktop/terminal session but fails when dealing with containers that were started from a remote session such as ssh. I haven't looked at the exact reason for that in the kernel but on the userspace side of things, the difference is that containers started from an ssh session will happily let pam open /proc/self/loginuid read-write, will let it read its content but will then fail with EPERM when trying to write to it. So to make the userns support bullet proof, this commit moves the userns check earlier in the function (which means a small performance impact as it'll now happen everytime on kernels that have userns support) and will set rc = PAM_IGNORE instead of rc = PAM_ERROR. The rest of the code is still executed in the event that PAM is run on a future kernel where we have some kind of audit namespace that includes a working loginuid. Signed-off-by: Stéphane Graber Signed-off-by: Steve Langasek Signed-off-by: Dmitry V. Levin --- modules/pam_loginuid/pam_loginuid.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'modules/pam_loginuid') diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c index 54ae6f07..d2584228 100644 --- a/modules/pam_loginuid/pam_loginuid.c +++ b/modules/pam_loginuid/pam_loginuid.c @@ -58,21 +58,22 @@ static int set_loginuid(pam_handle_t *pamh, uid_t uid) static const char host_uid_map[] = " 0 0 4294967295\n"; char uid_map[sizeof(host_uid_map)]; + /* loginuid in user namespaces currently isn't writable and in some + case, not even readable, so consider any failure as ignorable (but try + anyway, in case we hit a kernel which supports it). */ + fd = open("/proc/self/uid_map", O_RDONLY); + if (fd >= 0) { + count = pam_modutil_read(fd, uid_map, sizeof(uid_map)); + if (strncmp(uid_map, host_uid_map, count) != 0) + rc = PAM_IGNORE; + close(fd); + } + count = snprintf(loginuid, sizeof(loginuid), "%lu", (unsigned long)uid); fd = open("/proc/self/loginuid", O_NOFOLLOW|O_RDWR); if (fd < 0) { if (errno == ENOENT) { rc = PAM_IGNORE; - } else if (errno == EACCES) { - fd = open("/proc/self/uid_map", O_RDONLY); - if (fd >= 0) { - count = pam_modutil_read(fd, uid_map, sizeof(uid_map)); - if (strncmp(uid_map, host_uid_map, count) != 0) - rc = PAM_IGNORE; - close(fd); - } - if (rc != PAM_IGNORE) - errno = EACCES; } if (rc != PAM_IGNORE) { pam_syslog(pamh, LOG_ERR, -- cgit v1.2.3 From c15791289bbf1a4cef0898dc09a12fde16e53d67 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Sun, 19 Jan 2014 14:02:53 +0000 Subject: pam_loginuid: cleanup loginuid buffer initialization * modules/pam_loginuid/pam_loginuid.c (set_loginuid): Move loginuid buffer initialization closer to its first use. --- modules/pam_loginuid/pam_loginuid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/pam_loginuid') diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c index d2584228..c476f7b6 100644 --- a/modules/pam_loginuid/pam_loginuid.c +++ b/modules/pam_loginuid/pam_loginuid.c @@ -69,7 +69,6 @@ static int set_loginuid(pam_handle_t *pamh, uid_t uid) close(fd); } - count = snprintf(loginuid, sizeof(loginuid), "%lu", (unsigned long)uid); fd = open("/proc/self/loginuid", O_NOFOLLOW|O_RDWR); if (fd < 0) { if (errno == ENOENT) { @@ -82,6 +81,7 @@ static int set_loginuid(pam_handle_t *pamh, uid_t uid) return rc; } + count = snprintf(loginuid, sizeof(loginuid), "%lu", (unsigned long)uid); if (pam_modutil_read(fd, buf, sizeof(buf)) == count && memcmp(buf, loginuid, count) == 0) { rc = PAM_SUCCESS; -- cgit v1.2.3 From 256b50e1fce2f785f1032a1949dd2d1dbc17e250 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Sun, 19 Jan 2014 14:12:59 +0000 Subject: pam_loginuid: log significant loginuid write errors * modules/pam_loginuid/pam_loginuid.c (set_loginuid): Log those errors during /proc/self/loginuid update that are not ignored. --- modules/pam_loginuid/pam_loginuid.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'modules/pam_loginuid') diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c index c476f7b6..73c42f9c 100644 --- a/modules/pam_loginuid/pam_loginuid.c +++ b/modules/pam_loginuid/pam_loginuid.c @@ -75,8 +75,8 @@ static int set_loginuid(pam_handle_t *pamh, uid_t uid) rc = PAM_IGNORE; } if (rc != PAM_IGNORE) { - pam_syslog(pamh, LOG_ERR, - "Cannot open /proc/self/loginuid: %m"); + pam_syslog(pamh, LOG_ERR, "Cannot open %s: %m", + "/proc/self/loginuid"); } return rc; } @@ -88,8 +88,14 @@ static int set_loginuid(pam_handle_t *pamh, uid_t uid) goto done; /* already correct */ } if (lseek(fd, 0, SEEK_SET) == 0 && ftruncate(fd, 0) == 0 && - pam_modutil_write(fd, loginuid, count) == count) + pam_modutil_write(fd, loginuid, count) == count) { rc = PAM_SUCCESS; + } else { + if (rc != PAM_IGNORE) { + pam_syslog(pamh, LOG_ERR, "Error writing %s: %m", + "/proc/self/loginuid"); + } + } done: close(fd); return rc; -- cgit v1.2.3 From c83b2564e1b4ddeaa82573fae68aa89413ec4f74 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 22 May 2014 11:25:13 +0200 Subject: pam_loginuid: Document other possible return values. modules/pam_loginuid/pam_loginuid.8.xml: Document the possible return values. --- modules/pam_loginuid/pam_loginuid.8.xml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'modules/pam_loginuid') diff --git a/modules/pam_loginuid/pam_loginuid.8.xml b/modules/pam_loginuid/pam_loginuid.8.xml index d16e2b2d..9686ddb2 100644 --- a/modules/pam_loginuid/pam_loginuid.8.xml +++ b/modules/pam_loginuid/pam_loginuid.8.xml @@ -68,15 +68,30 @@ RETURN VALUES + + PAM_SUCCESS + + + The loginuid value is set and auditd is running if check requested. + + + + + PAM_IGNORE + + + The /proc/self/loginuid file is not present on the system. + + + PAM_SESSION_ERR - An error occurred during session management. + Any other error prevented setting loginuid or auditd is not running. - -- cgit v1.2.3 From 78b16874b1348ae63785bbbdee9c624989aaf5c0 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 22 May 2014 11:33:21 +0200 Subject: pam_loginuid: Document one more possible case of PAM_IGNORE return. modules/pam_loginuid/pam_loginuid.8.xml: Document one more possible case of PAM_IGNORE return value. --- modules/pam_loginuid/pam_loginuid.8.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'modules/pam_loginuid') diff --git a/modules/pam_loginuid/pam_loginuid.8.xml b/modules/pam_loginuid/pam_loginuid.8.xml index 9686ddb2..9513b0e4 100644 --- a/modules/pam_loginuid/pam_loginuid.8.xml +++ b/modules/pam_loginuid/pam_loginuid.8.xml @@ -80,7 +80,9 @@ PAM_IGNORE - The /proc/self/loginuid file is not present on the system. + The /proc/self/loginuid file is not present on the system or the + login process runs inside uid namespace and kernel does not support + overwriting loginuid. -- cgit v1.2.3 From d766637071ab5bb835ea8fc4379d77f5449e249f Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 24 Sep 2015 13:21:40 +0200 Subject: pam_loginuid: Add syslog message if required auditd is not detected. * modules/pam_loginuid/pam_loginuid.c (_pam_loginuid): Add syslog message if required auditd is not detected. --- modules/pam_loginuid/pam_loginuid.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'modules/pam_loginuid') diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c index 73c42f9c..9a1589e5 100644 --- a/modules/pam_loginuid/pam_loginuid.c +++ b/modules/pam_loginuid/pam_loginuid.c @@ -234,6 +234,8 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED, if (require_auditd) { int rc = check_auditd(); + if (rc != PAM_SUCCESS) + pam_syslog(pamh, LOG_ERR, "required running auditd not detected"); return rc != PAM_SUCCESS ? rc : ret; } else #endif -- cgit v1.2.3 From a684595c0bbd88df71285f43fb27630e3829121e Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Tue, 29 Mar 2016 14:14:03 +0200 Subject: Remove "--enable-static-modules" option and support from Linux-PAM. It was never official supported and was broken since years. * configure.ac: Remove --enable-static-modules option. * doc/man/pam_sm_acct_mgmt.3.xml: Remove PAM_EXTERN. * doc/man/pam_sm_authenticate.3.xml: Likewise. * doc/man/pam_sm_chauthtok.3.xml: Likewise. * doc/man/pam_sm_close_session.3.xml: Likewise. * doc/man/pam_sm_open_session.3.xml: Likewise. * doc/man/pam_sm_setcred.3.xml: Likewise. * libpam/Makefile.am: Remove STATIC_MODULES cases. * libpam/include/security/pam_modules.h: Remove PAM_STATIC parts. * libpam/pam_dynamic.c: Likewise. * libpam/pam_handlers.c: Likewise. * libpam/pam_private.h: Likewise. * libpam/pam_static.c: Remove file. * libpam/pam_static_modules.h: Remove header file. * modules/pam_access/pam_access.c: Remove PAM_EXTERN and PAM_STATIC parts. * modules/pam_cracklib/pam_cracklib.c: Likewise. * modules/pam_debug/pam_debug.c: Likewise. * modules/pam_deny/pam_deny.c: Likewise. * modules/pam_echo/pam_echo.c: Likewise. * modules/pam_env/pam_env.c: Likewise. * modules/pam_exec/pam_exec.c: Likewise. * modules/pam_faildelay/pam_faildelay.c: Likewise. * modules/pam_filter/pam_filter.c: Likewise. * modules/pam_ftp/pam_ftp.c: Likewise. * modules/pam_group/pam_group.c: Likewise. * modules/pam_issue/pam_issue.c: Likewise. * modules/pam_keyinit/pam_keyinit.c: Likewise. * modules/pam_lastlog/pam_lastlog.c: Likewise. * modules/pam_limits/pam_limits.c: Likewise. * modules/pam_listfile/pam_listfile.c: Likewise. * modules/pam_localuser/pam_localuser.c: Likewise. * modules/pam_loginuid/pam_loginuid.c: Likewise. * modules/pam_mail/pam_mail.c: Likewise. * modules/pam_mkhomedir/pam_mkhomedir.c: Likewise. * modules/pam_motd/pam_motd.c: Likewise. * modules/pam_namespace/pam_namespace.c: Likewise. * modules/pam_nologin/pam_nologin.c: Likewise. * modules/pam_permit/pam_permit.c: Likewise. * modules/pam_pwhistory/pam_pwhistory.c: Likewise. * modules/pam_rhosts/pam_rhosts.c: Likewise. * modules/pam_rootok/pam_rootok.c: Likewise. * modules/pam_securetty/pam_securetty.c: Likewise. * modules/pam_selinux/pam_selinux.c: Likewise. * modules/pam_sepermit/pam_sepermit.c: Likewise. * modules/pam_shells/pam_shells.c: Likewise. * modules/pam_stress/pam_stress.c: Likewise. * modules/pam_succeed_if/pam_succeed_if.c: Likewise. * modules/pam_tally/pam_tally.c: Likewise. * modules/pam_tally2/pam_tally2.c: Likewise. * modules/pam_time/pam_time.c: Likewise. * modules/pam_timestamp/pam_timestamp.c: Likewise. * modules/pam_tty_audit/pam_tty_audit.c: Likewise. * modules/pam_umask/pam_umask.c: Likewise. * modules/pam_userdb/pam_userdb.c: Likewise. * modules/pam_warn/pam_warn.c: Likewise. * modules/pam_wheel/pam_wheel.c: Likewise. * modules/pam_xauth/pam_xauth.c: Likewise. * modules/pam_unix/Makefile.am: Remove STATIC_MODULES part. * modules/pam_unix/pam_unix_acct.c: Remove PAM_STATIC part. * modules/pam_unix/pam_unix_auth.c: Likewise. * modules/pam_unix/pam_unix_passwd.c: Likewise. * modules/pam_unix/pam_unix_sess.c: Likewise. * modules/pam_unix/pam_unix_static.c: Removed. * modules/pam_unix/pam_unix_static.h: Removed. * po/POTFILES.in: Remove removed files. * tests/tst-dlopen.c: Remove PAM_STATIC part. --- modules/pam_loginuid/pam_loginuid.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'modules/pam_loginuid') diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c index 9a1589e5..96bfd98e 100644 --- a/modules/pam_loginuid/pam_loginuid.c +++ b/modules/pam_loginuid/pam_loginuid.c @@ -247,34 +247,21 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED, * * This is here for vsftpd which doesn't seem to run the session stack */ -PAM_EXTERN int +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { return _pam_loginuid(pamh, flags, argc, argv); } -PAM_EXTERN int +int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { return _pam_loginuid(pamh, flags, argc, argv); } -PAM_EXTERN int +int pam_sm_close_session(pam_handle_t *pamh UNUSED, int flags UNUSED, int argc UNUSED, const char **argv UNUSED) { return PAM_SUCCESS; } - -/* static module data */ -#ifdef PAM_STATIC -struct pam_module _pam_loginuid_modstruct = { - "pam_loginuid", - NULL, - NULL, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - NULL -}; -#endif -- cgit v1.2.3