diff options
Diffstat (limited to 'modules/pam_xauth/pam_xauth.c')
-rw-r--r-- | modules/pam_xauth/pam_xauth.c | 155 |
1 files changed, 85 insertions, 70 deletions
diff --git a/modules/pam_xauth/pam_xauth.c b/modules/pam_xauth/pam_xauth.c index 07ece647..a64ae89f 100644 --- a/modules/pam_xauth/pam_xauth.c +++ b/modules/pam_xauth/pam_xauth.c @@ -35,8 +35,10 @@ #include "config.h" #include <sys/types.h> -#include <sys/fsuid.h> #include <sys/wait.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> #include <errno.h> #include <fnmatch.h> #include <grp.h> @@ -232,9 +234,11 @@ check_acl(pam_handle_t *pamh, { char path[PATH_MAX]; struct passwd *pwd; - FILE *fp; - int i, save_errno; - uid_t euid; + FILE *fp = NULL; + int i, fd = -1, save_errno; + struct stat st; + PAM_MODUTIL_DEF_PRIVS(privs); + /* Check this user's <sense> file. */ pwd = pam_modutil_getpwnam(pamh, this_user); if (pwd == NULL) { @@ -250,12 +254,33 @@ check_acl(pam_handle_t *pamh, "name of user's home directory is too long"); return PAM_SESSION_ERR; } - euid = geteuid(); - setfsuid(pwd->pw_uid); - fp = fopen(path, "r"); + if (pam_modutil_drop_priv(pamh, &privs, pwd)) + return PAM_SESSION_ERR; + if (!stat(path, &st)) { + if (!S_ISREG(st.st_mode)) + errno = EINVAL; + else + fd = open(path, O_RDONLY | O_NOCTTY); + } save_errno = errno; - setfsuid(euid); - if (fp != NULL) { + if (pam_modutil_regain_priv(pamh, &privs)) { + if (fd >= 0) + close(fd); + return PAM_SESSION_ERR; + } + if (fd >= 0) { + if (!fstat(fd, &st)) { + if (!S_ISREG(st.st_mode)) + errno = EINVAL; + else + fp = fdopen(fd, "r"); + } + if (!fp) { + save_errno = errno; + close(fd); + } + } + if (fp) { char buf[LINE_MAX], *tmp; /* Scan the file for a list of specs of users to "trust". */ while (fgets(buf, sizeof(buf), fp) != NULL) { @@ -324,7 +349,7 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, struct passwd *tpwd, *rpwd; int fd, i, debug = 0; int retval = PAM_SUCCESS; - uid_t systemuser = 499, targetuser = 0, euid; + uid_t systemuser = 499, targetuser = 0; /* Parse arguments. We don't understand many, so no sense in breaking * this into a separate function. */ @@ -486,10 +511,11 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, getuid(), getgid(), xauth, "-f", cookiefile, "nlist", display, NULL) == 0) { - int save_errno; #ifdef WITH_SELINUX security_context_t context = NULL; #endif + PAM_MODUTIL_DEF_PRIVS(privs); + /* Check that we got a cookie. If not, we get creative. */ if (((cookie == NULL) || (strlen(cookie) == 0)) && ((strncmp(display, "localhost:", 10) == 0) || @@ -572,9 +598,10 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, } /* Generate a new file to hold the data. */ - euid = geteuid(); - setfsuid(tpwd->pw_uid); - + if (pam_modutil_drop_priv(pamh, &privs, tpwd)) { + retval = PAM_SESSION_ERR; + goto cleanup; + } #ifdef WITH_SELINUX if (is_selinux_enabled() > 0) { struct selabel_handle *ctx = selabel_open(SELABEL_CTX_FILE, NULL, 0); @@ -592,33 +619,24 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, } } } +#endif /* WITH_SELINUX */ fd = mkstemp(xauthority + sizeof(XAUTHENV)); - save_errno = errno; + if (fd < 0) + pam_syslog(pamh, LOG_ERR, + "error creating temporary file `%s': %m", + xauthority + sizeof(XAUTHENV)); +#ifdef WITH_SELINUX if (context != NULL) { free(context); setfscreatecon(NULL); } -#else - fd = mkstemp(xauthority + sizeof(XAUTHENV)); - save_errno = errno; -#endif - - setfsuid(euid); - if (fd == -1) { - errno = save_errno; - pam_syslog(pamh, LOG_ERR, - "error creating temporary file `%s': %m", - xauthority + sizeof(XAUTHENV)); +#endif /* WITH_SELINUX */ + if (fd >= 0) + close(fd); + if (pam_modutil_regain_priv(pamh, &privs) || fd < 0) { retval = PAM_SESSION_ERR; goto cleanup; } - /* Set permissions on the new file and dispose of the - * descriptor. */ - setfsuid(tpwd->pw_uid); - if (fchown(fd, tpwd->pw_uid, tpwd->pw_gid) < 0) - pam_syslog (pamh, LOG_ERR, "fchown: %m"); - setfsuid(euid); - close(fd); /* Get a copy of the filename to save as a data item for * removal at session-close time. */ @@ -712,59 +730,56 @@ int pam_sm_close_session (pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { - void *cookiefile; int i, debug = 0; - const char* user; + const char *user; + const void *data; + const char *cookiefile; struct passwd *tpwd; - uid_t unlinkuid, euid; - unlinkuid = euid = geteuid (); - - if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS) - pam_syslog(pamh, LOG_ERR, "error determining target user's name"); - else { - tpwd = pam_modutil_getpwnam(pamh, user); - if (!tpwd) - pam_syslog(pamh, LOG_ERR, "error determining target user's UID"); - else - unlinkuid = tpwd->pw_uid; - } + PAM_MODUTIL_DEF_PRIVS(privs); - /* Parse arguments. We don't understand many, so no sense in breaking - * this into a separate function. */ + /* Try to retrieve the name of a file we created when + * the session was opened. */ + if (pam_get_data(pamh, DATANAME, &data) != PAM_SUCCESS) + return PAM_SUCCESS; + cookiefile = data; + + /* Parse arguments. We don't understand many, so + * no sense in breaking this into a separate function. */ for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) { debug = 1; continue; } - if (strncmp(argv[i], "xauthpath=", 10) == 0) { + if (strncmp(argv[i], "xauthpath=", 10) == 0) continue; - } - if (strncmp(argv[i], "systemuser=", 11) == 0) { + if (strncmp(argv[i], "systemuser=", 11) == 0) continue; - } - if (strncmp(argv[i], "targetuser=", 11) == 0) { + if (strncmp(argv[i], "targetuser=", 11) == 0) continue; - } pam_syslog(pamh, LOG_WARNING, "unrecognized option `%s'", argv[i]); } - /* Try to retrieve the name of a file we created when the session was - * opened. */ - if (pam_get_data(pamh, DATANAME, (const void**) &cookiefile) == PAM_SUCCESS) { - /* We'll only try to remove the file once. */ - if (strlen((char*)cookiefile) > 0) { - if (debug) { - pam_syslog(pamh, LOG_DEBUG, "removing `%s'", - (char*)cookiefile); - } - /* NFS with root_squash requires non-root user */ - setfsuid (unlinkuid); - unlink((char*)cookiefile); - setfsuid (euid); - *((char*)cookiefile) = '\0'; - } + if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS) { + pam_syslog(pamh, LOG_ERR, + "error determining target user's name"); + return PAM_SESSION_ERR; + } + if (!(tpwd = pam_modutil_getpwnam(pamh, user))) { + pam_syslog(pamh, LOG_ERR, + "error determining target user's UID"); + return PAM_SESSION_ERR; } + + if (debug) + pam_syslog(pamh, LOG_DEBUG, "removing `%s'", cookiefile); + if (pam_modutil_drop_priv(pamh, &privs, tpwd)) + return PAM_SESSION_ERR; + if (unlink(cookiefile) == -1 && errno != ENOENT) + pam_syslog(pamh, LOG_WARNING, "Couldn't remove `%s': %m", cookiefile); + if (pam_modutil_regain_priv(pamh, &privs)) + return PAM_SESSION_ERR; + return PAM_SUCCESS; } |