/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident "@(#)pam_xauth_cred.c	1.3"

/*
 * pam_xauth_cred.c - pass on the X11 cookie when we su
 *
 * Compile:
 *
 *	cc pam_xauth_cred.c -o pam_xauth_cred.so.1 -Kpic -G
 *
 * Install:
 *
 *	cp pam_xauth_cred.so.1 /usr/lib/security
 *	chmod 644 /usr/lib/security/pam_xauth_cred.so.1
 *	ln -s pam_xauth_cred.so.1 /usr/lib/security/pam_xauth_cred.so
 *
 *      Add the following lines to /etc/pam.conf:
 *	su      auth requisite          pam_authtok_get.so.1
 *	su      auth required           pam_dhkeys.so.1
 *	su      auth required           pam_unix_cred.so.1
 *	su      auth sufficient         pam_krb5.so.1
 *	su      auth required           pam_unix_auth.so.1
 *	su      auth optional           /usr/local/lib/pam_xauth_cred.so.1
 *
 * Darren Moffat
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>
#include <security/pam_appl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <wait.h>

#define XAUTH	"/usr/openwin/bin/xauth"

const char *XAUTHORITY = "XAUTHORITY";
const char *DISPLAY = "DISPLAY";

char DISPLAY_NOT_SET[] = { "$DISPLAY not set no cookie will be passed" };

int
pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
	return (PAM_IGNORE);
}
 
int
pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
	char *display;
	char *cmd_argv[7];
	char tmpfl[BUFSIZ];
	char tmpfd;
	char *username = NULL;
	char pwd_buf[BUFSIZ];
	struct passwd pwd;
	pid_t child;
	char *xauth_env, *display_env;
	int trusted = 0;

	if (getenv(DISPLAY) == NULL) {
		return (PAM_IGNORE);
	}
 	display = strdup(getenv(DISPLAY));

	(void) pam_get_item(pamh, PAM_USER,(void**)&username);

	if (getpwnam_r(username, &pwd, pwd_buf, sizeof(pwd_buf)) == NULL) {
		return (PAM_USER_UNKNOWN);
	}

	(void) tmpnam(tmpfl);

	tmpfd = open(tmpfl, O_RDWR | O_CREAT | O_EXCL | 
	    O_NOFOLLOW | O_NOLINKS | O_NONBLOCK, S_IRUSR | S_IWUSR);
	if (tmpfd == -1) {
		return (PAM_SYSTEM_ERR);
	}

	if (fchown(tmpfd, getuid(), getgid()) == -1)  {
		return (PAM_SYSTEM_ERR);
	}

	cmd_argv[0] = "xauth";
	cmd_argv[1] = "-f";
	cmd_argv[2] = strdup(tmpfl);
	cmd_argv[3] = "generate";
	cmd_argv[4] = strdup(display);
	cmd_argv[5] = ".";
	if (trusted)
		cmd_argv[6] = "trusted";
	else
		cmd_argv[6] = "untrusted";
	cmd_argv[7] = NULL;

	child = fork();
	if (child < 0) {
		return (PAM_SERVICE_ERR);
	} else if (child == 0) {
		if (execv(XAUTH, cmd_argv) < 0) {
			return (PAM_SERVICE_ERR);
		}
	} else {
		child = waitpid(child, NULL, 0);
		if (child < 0)
			return (PAM_SERVICE_ERR);
	}

	fprintf(stderr, "setting DISPLAY\n");
	display_env = malloc(strlen(display) + strlen(DISPLAY) + 2);
	sprintf(display_env, "%s=%s", DISPLAY, display);
	(void) pam_putenv(pamh, display_env);

	fprintf(stderr, "setting XAUTHORITY\n");
	xauth_env = malloc(strlen(tmpfl) + strlen(XAUTHORITY) + 2);
	sprintf(xauth_env, "%s=%s", XAUTHORITY, tmpfl);
	(void) pam_putenv(pamh, xauth_env);

	if (fchown(tmpfd, pwd.pw_uid, pwd.pw_gid) == -1)  {
		return (PAM_SYSTEM_ERR);
	}

	(void) close(tmpfd);

        return (PAM_SUCCESS);
}
