From 2ff0080fce12aa9593fddcb94f87db2973205468 Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Thu, 23 Sep 2004 15:41:58 +0000 Subject: Relevant BUGIDs: Purpose of commit: Commit summary: --------------- new feature: Add pam_xauth (Bug 436440) --- modules/Simple.Rules | 12 + modules/pam_xauth/Makefile | 12 + modules/pam_xauth/README | 41 +++ modules/pam_xauth/pam_xauth.8 | 82 ++++++ modules/pam_xauth/pam_xauth.c | 621 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 768 insertions(+) create mode 100644 modules/pam_xauth/Makefile create mode 100644 modules/pam_xauth/README create mode 100644 modules/pam_xauth/pam_xauth.8 create mode 100644 modules/pam_xauth/pam_xauth.c diff --git a/modules/Simple.Rules b/modules/Simple.Rules index bb16e48d..97f419a8 100644 --- a/modules/Simple.Rules +++ b/modules/Simple.Rules @@ -76,6 +76,18 @@ install: all $(MKDIR) $(FAKEROOT)$(SECUREDIR) ifdef DYNAMIC $(INSTALL) -m $(SHLIBMODE) $(LIBSHARED) $(FAKEROOT)$(SECUREDIR) +endif +ifdef MAN3 + test -d $(FAKEROOT)$(mandir)/man3 || $(MKDIR) $(FAKEROOT)$(mandir)/man3 + $(INSTALL) -m $(MANMODE) $(MAN3) $(FAKEROOT)$(mandir)/man3/ +endif +ifdef MAN5 + test -d $(FAKEROOT)$(mandir)/man5 || $(MKDIR) $(FAKEROOT)$(mandir)/man5 + $(INSTALL) -m $(MANMODE) $(MAN5) $(FAKEROOT)$(mandir)/man5/ +endif +ifdef MAN8 + test -d $(FAKEROOT)$(mandir)/man8 || $(MKDIR) $(FAKEROOT)$(mandir)/man8 + $(INSTALL) -m $(MANMODE) $(MAN8) $(FAKEROOT)$(mandir)/man8/ endif $(MODULE_SIMPLE_INSTALL) diff --git a/modules/pam_xauth/Makefile b/modules/pam_xauth/Makefile new file mode 100644 index 00000000..385466a2 --- /dev/null +++ b/modules/pam_xauth/Makefile @@ -0,0 +1,12 @@ +# +# This Makefile controls a build process of $(TITLE) module for +# Linux-PAM. You should not modify this Makefile (unless you know +# what you are doing!). +# + +include ../../Make.Rules + +TITLE=pam_xauth +MAN8=pam_xauth.8 + +include ../Simple.Rules diff --git a/modules/pam_xauth/README b/modules/pam_xauth/README new file mode 100644 index 00000000..dd65292f --- /dev/null +++ b/modules/pam_xauth/README @@ -0,0 +1,41 @@ +pam_xauth: + Forward xauth cookies from user to user, normally used by su, sudo, or + userhelper. + + Primitive access control is provided by ~/.xauth/export in the invoking + user's home directory and ~/.xauth/import in the target user's home + directory. + + If a user has a ~/.xauth/import file, the user will only receive cookies + from users listed in the file. If there is no ~/.xauth/import file, + the user will accept cookies from any other user. + + If a user has a .xauth/export file, the user will only forward cookies + to users listed in the file. If there is no ~/.xauth/export file, and + the invoking user is not "root", the user will forward cookies to + any other user. If there is no ~/.xauth/export file, and the invoking + user is "root", the user will NOT forward cookies to other users. + + Both the import and export files support wildcards (such as "*"). Both + the import and export files can be empty, signifying that no users are + allowed. + +RECOGNIZED ARGUMENTS: + debug write debugging messages to syslog + xauthpath= the path to the xauth program, by default + /usr/X11R6/bin/xauth + systemuser= highest user id assigned to system users, defaults + to 499 (pam_xauth will refuse to forward creds to + target users with id equal to or below this number, + except for root and possibly another specified user) + targetuser= a target user id which is excepted from the systemuser + checks + + +MODULE SERVICES PROVIDED: + session open session copies xauth cookie to new user + close session deletes copied xauth cookie + +AUTHOR: + Nalin Dahyabhai , based on original version by + Michael K. Johnson diff --git a/modules/pam_xauth/pam_xauth.8 b/modules/pam_xauth/pam_xauth.8 new file mode 100644 index 00000000..9acb7249 --- /dev/null +++ b/modules/pam_xauth/pam_xauth.8 @@ -0,0 +1,82 @@ +.\" Copyright 2001,2003 Red Hat, Inc. +.\" Written by Nalin Dahyabhai , based on the original +.\" version by Michael K. Johnson +.TH pam_xauth 8 2003/7/24 "Red Hat Linux" "System Administrator's Manual" +.SH NAME +pam_xauth \- forward xauth keys between users +.SH SYNOPSIS +.B session optional /lib/security/pam_xauth.so \fIarguments\fP +.SH DESCRIPTION +pam_xauth.so is designed to forward xauth keys (sometimes referred +to as "cookies") between users. + +Without pam_xauth, when xauth is enabled and a user uses the \fBsu\fP command +to assume another user's priviledges, that user is no longer able to access +the original user's X display because the new user does not have the key +needed to access the display. pam_xauth solves the problem by forwarding the +key from the user running su (the source user) to the user whose +identity the source user is assuming (the target user) when the session +is created, and destroying the key when the session is torn down. + +This means, for example, that when you run \fBsu\fP from an xterm sesssion, +you will be able to run X programs without explicitly dealing with the +xauth command or ~/.Xauthority files. + +pam_xauth will only forward keys if xauth can list a key connected +to the $DISPLAY environment variable. + +Primitive access control is provided by \fB~/.xauth/export\fP in the invoking +user's home directory and \fB~/.xauth/import\fP in the target user's home +directory. + +If a user has a \fB~/.xauth/import\fP file, the user will only receive cookies +from users listed in the file. If there is no \fB~/.xauth/import\fP file, +the user will accept cookies from any other user. + +If a user has a \fB.xauth/export\fP file, the user will only forward cookies +to users listed in the file. If there is no \fB~/.xauth/export\fP file, and +the invoking user is not \fBroot\fP, the user will forward cookies to +any other user. If there is no \fB~/.xauth/export\fP file, and the invoking +user is \fBroot\fP, the user will \fInot\fP forward cookies to other users. + +Both the import and export files support wildcards (such as \fI*\fP). Both +the import and export files can be empty, signifying that no users are allowed. + +.SH ARGUMENTS +.IP debug +Turns on debugging messages sent to syslog. +.IP xauthpath=\fI/usr/X11R6/bin/xauth\fP +Specify the path the xauth program (the default is /usr/X11R6/bin/xauth). +.IP systemuser=\fInumber\fP +Specify the highest UID which will be assumed to belong to a "system" user. +pam_xauth will refuse to forward credentials to users with UID less than or +equal to this number, except for root and the "targetuser", if specified. +.IP targetuser=\fInumber\fP +Specify a single target UID which is exempt from the systemuser check. +.SH "IMPLEMENTATION DETAILS" +pam_xauth will work \fIonly\fP if it is used from a setuid application +in which the getuid() call returns the id of the user running the +application, and for which PAM can supply the name of the account that +the user is attempting to assume. The typical application of this +type is \fBsu\fP. The application must call both pam_open_session() and +pam_close_session() with the ruid set to the uid of the calling user +and the euid set to root, and must have provided as the PAM_USER item +the name of the target user. + +pam_xauth calls \fBxauth\fP as the source user to extract the key for +$DISPLAY, then calls xauth as the target user to merge the key +into the a temporary database and later remove the database. + +pam_xauth cannot be told not to remove the keys when the session +is closed. +.SH "SEE ALSO" +\fI/usr/share/doc/pam*/html/index.html\fP +.SH FILES +\fI~/.xauth/import\fP +\fI~/.xauth/export\fP +.SH BUGS +Let's hope not, but if you find any, please report them via the "Bug Track" +link at http://bugzilla.redhat.com/bugzilla/ +.SH AUTHOR +Nalin Dahyabhai , based on original version by +Michael K. Johnson diff --git a/modules/pam_xauth/pam_xauth.c b/modules/pam_xauth/pam_xauth.c new file mode 100644 index 00000000..58dd059a --- /dev/null +++ b/modules/pam_xauth/pam_xauth.c @@ -0,0 +1,621 @@ +/* + * Copyright 2001-2003 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ident "$Id$" + +#include "../../_pam_aconf.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DATANAME "pam_xauth_cookie_file" +#define XAUTHBIN "/usr/X11R6/bin/xauth" +#define XAUTHENV "XAUTHORITY" +#define HOMEENV "HOME" +#define XAUTHDEF ".Xauthority" +#define XAUTHTMP ".xauthXXXXXX" + +/* Run a given command (with a NULL-terminated argument list), feeding it the + * given input on stdin, and storing any output it generates. */ +static int +run_coprocess(const char *input, char **output, + uid_t uid, gid_t gid, const char *command, ...) +{ + int ipipe[2], opipe[2], i; + char buf[LINE_MAX]; + pid_t child; + char *buffer = NULL; + size_t buffer_size = 0; + va_list ap; + + *output = NULL; + + /* Create stdio pipery. */ + if (pipe(ipipe) == -1) { + return -1; + } + if (pipe(opipe) == -1) { + close(ipipe[0]); + close(ipipe[1]); + return -1; + } + + /* Fork off a child. */ + child = fork(); + if (child == -1) { + close(ipipe[0]); + close(ipipe[1]); + close(opipe[0]); + close(opipe[1]); + return -1; + } + + if (child == 0) { + /* We're the child. */ + char *args[10]; + const char *tmp; + /* Drop privileges. */ + setgid(gid); + setgroups(0, NULL); + setuid(uid); + /* Initialize the argument list. */ + memset(args, 0, sizeof(args)); + /* Set the pipe descriptors up as stdin and stdout, and close + * everything else, including the original values for the + * descriptors. */ + dup2(ipipe[0], STDIN_FILENO); + dup2(opipe[1], STDOUT_FILENO); + for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) { + if ((i != STDIN_FILENO) && (i != STDOUT_FILENO)) { + close(i); + } + } + /* Convert the varargs list into a regular array of strings. */ + va_start(ap, command); + args[0] = strdup(command); + for (i = 1; i < ((sizeof(args) / sizeof(args[0])) - 1); i++) { + tmp = va_arg(ap, const char*); + if (tmp == NULL) { + break; + } + args[i] = strdup(tmp); + } + /* Run the command. */ + execvp(command, args); + /* Never reached. */ + exit(1); + } + + /* We're the parent, so close the other ends of the pipes. */ + close(ipipe[0]); + close(opipe[1]); + /* Send input to the process (if we have any), then send an EOF. */ + if (input) { + (void)_pammodutil_write(ipipe[1], input, strlen(input)); + } + close(ipipe[1]); + + /* Read data output until we run out of stuff to read. */ + i = _pammodutil_read(opipe[0], buf, sizeof(buf)); + while ((i != 0) && (i != -1)) { + char *tmp; + /* Resize the buffer to hold the data. */ + tmp = realloc(buffer, buffer_size + i + 1); + if (tmp == NULL) { + /* Uh-oh, bail. */ + if (buffer != NULL) { + free(buffer); + } + close(opipe[0]); + waitpid(child, NULL, 0); + return -1; + } + /* Save the new buffer location, copy the newly-read data into + * the buffer, and make sure the result will be + * nul-terminated. */ + buffer = tmp; + memcpy(buffer + buffer_size, buf, i); + buffer[buffer_size + i] = '\0'; + buffer_size += i; + /* Try to read again. */ + i = _pammodutil_read(opipe[0], buf, sizeof(buf)); + } + /* No more data. Clean up and return data. */ + close(opipe[0]); + *output = buffer; + waitpid(child, NULL, 0); + return 0; +} + +/* Free a data item. */ +static void +cleanup(pam_handle_t *pamh, void *data, int err) +{ + free(data); +} + +/* Check if we want to allow export to the other user, or import from the + * other user. */ +static int +check_acl(pam_handle_t *pamh, + const char *sense, const char *this_user, const char *other_user, + int noent_code, int debug) +{ + char path[PATH_MAX]; + struct passwd *pwd; + FILE *fp; + int i; + uid_t euid; + /* Check this user's file. */ + pwd = _pammodutil_getpwnam(pamh, this_user); + if (pwd == NULL) { + syslog(LOG_ERR, "pam_xauth: error determining " + "home directory for '%s'", this_user); + return PAM_SESSION_ERR; + } + /* Figure out what that file is really named. */ + i = snprintf(path, sizeof(path), "%s/.xauth/%s", pwd->pw_dir, sense); + if ((i >= sizeof(path)) || (i < 0)) { + syslog(LOG_ERR, "pam_xauth: name of user's home directory " + "is too long"); + return PAM_SESSION_ERR; + } + euid = geteuid(); + setfsuid(pwd->pw_uid); + fp = fopen(path, "r"); + setfsuid(euid); + if (fp != NULL) { + char buf[LINE_MAX], *tmp; + /* Scan the file for a list of specs of users to "trust". */ + while (fgets(buf, sizeof(buf), fp) != NULL) { + tmp = memchr(buf, '\r', sizeof(buf)); + if (tmp != NULL) { + *tmp = '\0'; + } + tmp = memchr(buf, '\n', sizeof(buf)); + if (tmp != NULL) { + *tmp = '\0'; + } + if (fnmatch(buf, other_user, 0) == 0) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: %s %s " + "allowed by %s", + other_user, sense, path); + } + fclose(fp); + return PAM_SUCCESS; + } + } + /* If there's no match in the file, we fail. */ + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: %s not listed in %s", + other_user, path); + } + fclose(fp); + return PAM_PERM_DENIED; + } else { + /* Default to okay if the file doesn't exist. */ + switch (errno) { + case ENOENT: + if (noent_code == PAM_SUCCESS) { + if (debug) { + syslog(LOG_DEBUG, "%s does not exist, " + "ignoring", path); + } + } else { + if (debug) { + syslog(LOG_DEBUG, "%s does not exist, " + "failing", path); + } + } + return noent_code; + default: + if (debug) { + syslog(LOG_ERR, "%s opening %s", + strerror(errno), path); + } + return PAM_PERM_DENIED; + } + } +} + +int +pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + char xauthpath[] = XAUTHBIN; + char *cookiefile = NULL, *xauthority = NULL, + *cookie = NULL, *display = NULL, *tmp = NULL; + const char *user, *xauth = xauthpath; + struct passwd *tpwd, *rpwd; + int fd, i, debug = 0; + uid_t systemuser = 499, targetuser = 0, euid; + + /* 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) { + xauth = argv[i] + 10; + continue; + } + if (strncmp(argv[i], "targetuser=", 11) == 0) { + long l = strtol(argv[i] + 11, &tmp, 10); + if ((strlen(argv[i] + 11) > 0) && (*tmp == '\0')) { + targetuser = l; + } else { + syslog(LOG_WARNING, "pam_xauth: invalid value " + "for targetuser (`%s')", argv[i] + 11); + } + continue; + } + if (strncmp(argv[i], "systemuser=", 11) == 0) { + long l = strtol(argv[i] + 11, &tmp, 10); + if ((strlen(argv[i] + 11) > 0) && (*tmp == '\0')) { + systemuser = l; + } else { + syslog(LOG_WARNING, "pam_xauth: invalid value " + "for systemuser (`%s')", argv[i] + 11); + } + continue; + } + syslog(LOG_WARNING, "pam_xauth: unrecognized option `%s'", + argv[i]); + } + + /* If DISPLAY isn't set, we don't really care, now do we? */ + if ((display = getenv("DISPLAY")) == NULL) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: user has no DISPLAY," + " doing nothing"); + } + return PAM_SUCCESS; + } + + /* Read the target user's name. */ + if (pam_get_item(pamh, PAM_USER, (const void**)&user) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_xauth: error determining target " + "user's name"); + return PAM_SESSION_ERR; + } + rpwd = _pammodutil_getpwuid(pamh, getuid()); + if (rpwd == NULL) { + syslog(LOG_ERR, "pam_xauth: error determining invoking " + "user's name"); + return PAM_SESSION_ERR; + } + + /* Get the target user's UID and primary GID, which we'll need to set + * on the xauthority file we create later on. */ + tpwd = _pammodutil_getpwnam(pamh, user); + if (tpwd == NULL) { + syslog(LOG_ERR, "pam_xauth: error determining target " + "user's UID"); + return PAM_SESSION_ERR; + } + + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: requesting user %lu/%lu, " + "target user %lu/%lu", + (unsigned long) rpwd->pw_uid, + (unsigned long) rpwd->pw_gid, + (unsigned long) tpwd->pw_uid, + (unsigned long) tpwd->pw_gid); + } + + /* If the UID is a system account (and not the superuser), forget + * about forwarding keys. */ + if ((tpwd->pw_uid != 0) && + (tpwd->pw_uid != targetuser) && + (tpwd->pw_uid <= systemuser)) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: not forwarding cookies " + "to user ID %ld", (long) tpwd->pw_uid); + } + return PAM_SESSION_ERR; + } + + /* 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) ? PAM_SUCCESS : PAM_PERM_DENIED; + i = check_acl(pamh, "export", rpwd->pw_name, user, i, debug); + if (i != PAM_SUCCESS) { + return PAM_SESSION_ERR; + } + i = PAM_SUCCESS; + i = check_acl(pamh, "import", user, rpwd->pw_name, i, debug); + if (i != PAM_SUCCESS) { + return PAM_SESSION_ERR; + } + + /* Figure out where the source user's .Xauthority file is. */ + if (getenv(XAUTHENV) != NULL) { + cookiefile = strdup(getenv(XAUTHENV)); + } else { + cookiefile = malloc(strlen(rpwd->pw_dir) + 1 + + strlen(XAUTHDEF) + 1); + if (cookiefile == NULL) { + return PAM_SESSION_ERR; + } + strcpy(cookiefile, rpwd->pw_dir); + strcat(cookiefile, "/"); + strcat(cookiefile, XAUTHDEF); + } + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: reading keys from `%s'", + cookiefile); + } + + /* Read the user's .Xauthority file. Because the current UID is + * the original user's UID, this will only fail if something has + * gone wrong, or we have no cookies. */ + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: running \"%s %s %s %s %s\" as " + "%lu/%lu", + xauth, + "-f", + cookiefile, + "nlist", + display, + (unsigned long) getuid(), + (unsigned long) getgid()); + } + if (run_coprocess(NULL, &cookie, + getuid(), getgid(), + xauth, "-f", cookiefile, "nlist", display, + NULL) == 0) { + /* Check that we got a cookie. If not, we get creative. */ + if (((cookie == NULL) || (strlen(cookie) == 0)) && + ((strncmp(display, "localhost:", 10) == 0) || + (strncmp(display, "localhost/unix:", 15) == 0))) { + char *t, *screen; + size_t tlen, slen; + /* Free the useless cookie string. */ + if (cookie != NULL) { + free(cookie); + cookie = NULL; + } + /* Allocate enough space to hold an adjusted name. */ + tlen = strlen(display) + LINE_MAX + 1; + t = malloc(tlen); + if (t != NULL) { + memset(t, 0, tlen); + if (gethostname(t, tlen - 1) != -1) { + /* Append the protocol and then the + * screen number. */ + if (strlen(t) < tlen - 6) { + strcat(t, "/unix:"); + } + screen = strchr(display, ':'); + if (screen != NULL) { + screen++; + slen = strlen(screen); + if (strlen(t) + slen < tlen) { + strcat(t, screen); + } + } + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: " + "no key for `%s', trying" + " `%s'", display, t); + } + /* Read the cookie for this display. */ + if (debug) { + syslog(LOG_DEBUG, + "pam_xauth: running " + "\"%s %s %s %s %s\" as " + "%lu/%lu", + xauth, + "-f", + cookiefile, + "nlist", + t, + (unsigned long) getuid(), + (unsigned long) getgid()); + } + run_coprocess(NULL, &cookie, + getuid(), getgid(), + xauth, "-f", cookiefile, + "nlist", t, NULL); + } + free(t); + t = NULL; + } + } + + /* Check that we got a cookie, this time for real. */ + if ((cookie == NULL) || (strlen(cookie) == 0)) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: no key"); + } + return PAM_SESSION_ERR; + } + + /* Generate the environment variable + * "XAUTHORITY=/filename". */ + xauthority = malloc(strlen(XAUTHENV) + 1 + + strlen(tpwd->pw_dir) + 1 + + strlen(XAUTHTMP) + 1); + if (xauthority == NULL) { + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: no free memory"); + } + free(cookiefile); + free(cookie); + return PAM_SESSION_ERR; + } + strcpy(xauthority, XAUTHENV); + strcat(xauthority, "="); + strcat(xauthority, tpwd->pw_dir); + strcat(xauthority, "/"); + strcat(xauthority, XAUTHTMP); + + /* Generate a new file to hold the data. */ + euid = geteuid(); + setfsuid(tpwd->pw_uid); + fd = mkstemp(xauthority + strlen(XAUTHENV) + 1); + setfsuid(euid); + if (fd == -1) { + syslog(LOG_ERR, "pam_xauth: error creating " + "temporary file `%s': %s", + xauthority + strlen(XAUTHENV) + 1, + strerror(errno)); + free(cookiefile); + free(cookie); + free(xauthority); + return PAM_SESSION_ERR; + } + /* Set permissions on the new file and dispose of the + * descriptor. */ + fchown(fd, tpwd->pw_uid, tpwd->pw_gid); + close(fd); + + /* Get a copy of the filename to save as a data item for + * removal at session-close time. */ + free(cookiefile); + cookiefile = strdup(xauthority + strlen(XAUTHENV) + 1); + + /* Save the filename. */ + if (pam_set_data(pamh, DATANAME, cookiefile, cleanup) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_xauth: error saving name of " + "temporary file `%s'", cookiefile); + unlink(cookiefile); + free(xauthority); + free(cookiefile); + free(cookie); + return PAM_SESSION_ERR; + } + + /* Unset any old XAUTHORITY variable in the environment. */ + if (getenv(XAUTHENV)) { + unsetenv(XAUTHENV); + } + + /* Set the new variable in the environment. */ + pam_putenv(pamh, xauthority); + putenv(xauthority); /* The environment owns this string now. */ + + /* Merge the cookie we read before into the new file. */ + if (debug) { + syslog(LOG_DEBUG, "pam_xauth: writing key `%s' to " + "temporary file `%s'", cookie, cookiefile); + } + if (debug) { + syslog(LOG_DEBUG, + "pam_xauth: running \"%s %s %s %s %s\" as " + "%lu/%lu", + xauth, + "-f", + cookiefile, + "nmerge", + "-", + (unsigned long) tpwd->pw_uid, + (unsigned long) tpwd->pw_gid); + } + run_coprocess(cookie, &tmp, + tpwd->pw_uid, tpwd->pw_gid, + xauth, "-f", cookiefile, "nmerge", "-", NULL); + + /* We don't need to keep a copy of these around any more. */ + free(cookie); + cookie = NULL; + } + return PAM_SUCCESS; +} + +int +pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + void *cookiefile; + int i, debug = 0; + + /* 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) { + continue; + } + if (strncmp(argv[i], "systemuser=", 11) == 0) { + continue; + } + if (strncmp(argv[i], "targetuser=", 11) == 0) { + continue; + } + syslog(LOG_WARNING, "pam_xauth: 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) { + syslog(LOG_DEBUG, "pam_xauth: removing `%s'", + (char*)cookiefile); + } + unlink((char*)cookiefile); + *((char*)cookiefile) = '\0'; + } + } + return PAM_SUCCESS; +} -- cgit v1.2.3