Blame src/clients/ksu/pam.c

rpm-build 1a6e45
/*
rpm-build 1a6e45
 * src/clients/ksu/pam.c
rpm-build 1a6e45
 *
rpm-build 1a6e45
 * Copyright 2007,2009,2010 Red Hat, Inc.
rpm-build 1a6e45
 *
rpm-build 1a6e45
 * All Rights Reserved.
rpm-build 1a6e45
 *
rpm-build 1a6e45
 * Redistribution and use in source and binary forms, with or without
rpm-build 1a6e45
 * modification, are permitted provided that the following conditions are met:
rpm-build 1a6e45
 *
rpm-build 1a6e45
 *  Redistributions of source code must retain the above copyright notice, this
rpm-build 1a6e45
 *  list of conditions and the following disclaimer.
rpm-build 1a6e45
 *
rpm-build 1a6e45
 *  Redistributions in binary form must reproduce the above copyright notice,
rpm-build 1a6e45
 *  this list of conditions and the following disclaimer in the documentation
rpm-build 1a6e45
 *  and/or other materials provided with the distribution.
rpm-build 1a6e45
 *
rpm-build 1a6e45
 *  Neither the name of Red Hat, Inc. nor the names of its contributors may be
rpm-build 1a6e45
 *  used to endorse or promote products derived from this software without
rpm-build 1a6e45
 *  specific prior written permission.
rpm-build 1a6e45
 *
rpm-build 1a6e45
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
rpm-build 1a6e45
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
rpm-build 1a6e45
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
rpm-build 1a6e45
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
rpm-build 1a6e45
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
rpm-build 1a6e45
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
rpm-build 1a6e45
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
rpm-build 1a6e45
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
rpm-build 1a6e45
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
rpm-build 1a6e45
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
rpm-build 1a6e45
 * POSSIBILITY OF SUCH DAMAGE.
rpm-build 1a6e45
 * 
rpm-build 1a6e45
 * Convenience wrappers for using PAM.
rpm-build 1a6e45
 */
rpm-build 1a6e45
rpm-build 1a6e45
#include "autoconf.h"
rpm-build 1a6e45
#ifdef USE_PAM
rpm-build 1a6e45
#include <sys/types.h>
rpm-build 1a6e45
#include <stdio.h>
rpm-build 1a6e45
#include <stdlib.h>
rpm-build 1a6e45
#include <string.h>
rpm-build 1a6e45
#include <unistd.h>
rpm-build 1a6e45
#include "k5-int.h"
rpm-build 1a6e45
#include "pam.h"
rpm-build 1a6e45
rpm-build 1a6e45
#ifndef MAXPWSIZE
rpm-build 1a6e45
#define MAXPWSIZE 128
rpm-build 1a6e45
#endif
rpm-build 1a6e45
rpm-build 1a6e45
static int appl_pam_started;
rpm-build 1a6e45
static pid_t appl_pam_starter = -1;
rpm-build 1a6e45
static int appl_pam_session_opened;
rpm-build 1a6e45
static int appl_pam_creds_initialized;
rpm-build 1a6e45
static int appl_pam_pwchange_required;
rpm-build 1a6e45
static pam_handle_t *appl_pamh;
rpm-build 1a6e45
static struct pam_conv appl_pam_conv;
rpm-build 1a6e45
static char *appl_pam_user;
rpm-build 1a6e45
struct appl_pam_non_interactive_args {
rpm-build 1a6e45
	const char *user;
rpm-build 1a6e45
	const char *password;
rpm-build 1a6e45
};
rpm-build 1a6e45
rpm-build 1a6e45
int
rpm-build 1a6e45
appl_pam_enabled(krb5_context context, const char *section)
rpm-build 1a6e45
{
rpm-build 1a6e45
	int enabled = 1;
rpm-build 1a6e45
	if ((context != NULL) && (context->profile != NULL)) {
rpm-build 1a6e45
		if (profile_get_boolean(context->profile,
rpm-build 1a6e45
					section,
rpm-build 1a6e45
					USE_PAM_CONFIGURATION_KEYWORD,
rpm-build 1a6e45
					NULL,
rpm-build 1a6e45
					enabled, &enabled) != 0) {
rpm-build 1a6e45
			enabled = 1;
rpm-build 1a6e45
		}
rpm-build 1a6e45
	}
rpm-build 1a6e45
	return enabled;
rpm-build 1a6e45
}
rpm-build 1a6e45
rpm-build 1a6e45
void
rpm-build 1a6e45
appl_pam_cleanup(void)
rpm-build 1a6e45
{
rpm-build 1a6e45
	if (getpid() != appl_pam_starter) {
rpm-build 1a6e45
		return;
rpm-build 1a6e45
	}
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
	printf("Called to clean up PAM.\n");
rpm-build 1a6e45
#endif
rpm-build 1a6e45
	if (appl_pam_creds_initialized) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
		printf("Deleting PAM credentials.\n");
rpm-build 1a6e45
#endif
rpm-build 1a6e45
		pam_setcred(appl_pamh, PAM_DELETE_CRED);
rpm-build 1a6e45
		appl_pam_creds_initialized = 0;
rpm-build 1a6e45
	}
rpm-build 1a6e45
	if (appl_pam_session_opened) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
		printf("Closing PAM session.\n");
rpm-build 1a6e45
#endif
rpm-build 1a6e45
		pam_close_session(appl_pamh, 0);
rpm-build 1a6e45
		appl_pam_session_opened = 0;
rpm-build 1a6e45
	}
rpm-build 1a6e45
	appl_pam_pwchange_required = 0;
rpm-build 1a6e45
	if (appl_pam_started) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
		printf("Shutting down PAM.\n");
rpm-build 1a6e45
#endif
rpm-build 1a6e45
		pam_end(appl_pamh, 0);
rpm-build 1a6e45
		appl_pam_started = 0;
rpm-build 1a6e45
		appl_pam_starter = -1;
rpm-build 1a6e45
		free(appl_pam_user);
rpm-build 1a6e45
		appl_pam_user = NULL;
rpm-build 1a6e45
	}
rpm-build 1a6e45
}
rpm-build 1a6e45
static int
rpm-build 1a6e45
appl_pam_interactive_converse(int num_msg, const struct pam_message **msg,
rpm-build 1a6e45
			      struct pam_response **presp, void *appdata_ptr)
rpm-build 1a6e45
{
rpm-build 1a6e45
	const struct pam_message *message;
rpm-build 1a6e45
	struct pam_response *resp;
rpm-build 1a6e45
	int i, code;
rpm-build 1a6e45
	char *pwstring, pwbuf[MAXPWSIZE];
rpm-build 1a6e45
	unsigned int pwsize;
rpm-build 1a6e45
	resp = malloc(sizeof(struct pam_response) * num_msg);
rpm-build 1a6e45
	if (resp == NULL) {
rpm-build 1a6e45
		return PAM_BUF_ERR;
rpm-build 1a6e45
	}
rpm-build 1a6e45
	memset(resp, 0, sizeof(struct pam_response) * num_msg);
rpm-build 1a6e45
	code = PAM_SUCCESS;
rpm-build 1a6e45
	for (i = 0; i < num_msg; i++) {
rpm-build 1a6e45
		message = &(msg[0][i]); /* XXX */
rpm-build 1a6e45
		message = msg[i]; /* XXX */
rpm-build 1a6e45
		pwstring = NULL;
rpm-build 1a6e45
		switch (message->msg_style) {
rpm-build 1a6e45
		case PAM_TEXT_INFO:
rpm-build 1a6e45
		case PAM_ERROR_MSG:
rpm-build 1a6e45
			printf("[%s]\n", message->msg ? message->msg : "");
rpm-build 1a6e45
			fflush(stdout);
rpm-build 1a6e45
			resp[i].resp = NULL;
rpm-build 1a6e45
			resp[i].resp_retcode = PAM_SUCCESS;
rpm-build 1a6e45
			break;
rpm-build 1a6e45
		case PAM_PROMPT_ECHO_ON:
rpm-build 1a6e45
		case PAM_PROMPT_ECHO_OFF:
rpm-build 1a6e45
			if (message->msg_style == PAM_PROMPT_ECHO_ON) {
rpm-build 1a6e45
				if (fgets(pwbuf, sizeof(pwbuf),
rpm-build 1a6e45
					  stdin) != NULL) {
rpm-build 1a6e45
					pwbuf[strcspn(pwbuf, "\r\n")] = '\0';
rpm-build 1a6e45
					pwstring = pwbuf;
rpm-build 1a6e45
				}
rpm-build 1a6e45
			} else {
rpm-build 1a6e45
				pwstring = getpass(message->msg ?
rpm-build 1a6e45
						   message->msg :
rpm-build 1a6e45
						   "");
rpm-build 1a6e45
			}
rpm-build 1a6e45
			if ((pwstring != NULL) && (pwstring[0] != '\0')) {
rpm-build 1a6e45
				pwsize = strlen(pwstring);
rpm-build 1a6e45
				resp[i].resp = malloc(pwsize + 1);
rpm-build 1a6e45
				if (resp[i].resp == NULL) {
rpm-build 1a6e45
					resp[i].resp_retcode = PAM_BUF_ERR;
rpm-build 1a6e45
				} else {
rpm-build 1a6e45
					memcpy(resp[i].resp, pwstring, pwsize);
rpm-build 1a6e45
					resp[i].resp[pwsize] = '\0';
rpm-build 1a6e45
					resp[i].resp_retcode = PAM_SUCCESS;
rpm-build 1a6e45
				}
rpm-build 1a6e45
			} else {
rpm-build 1a6e45
				resp[i].resp_retcode = PAM_CONV_ERR;
rpm-build 1a6e45
				code = PAM_CONV_ERR;
rpm-build 1a6e45
			}
rpm-build 1a6e45
			break;
rpm-build 1a6e45
		default:
rpm-build 1a6e45
			break;
rpm-build 1a6e45
		}
rpm-build 1a6e45
	}
rpm-build 1a6e45
	*presp = resp;
rpm-build 1a6e45
	return code;
rpm-build 1a6e45
}
rpm-build 1a6e45
static int
rpm-build 1a6e45
appl_pam_non_interactive_converse(int num_msg,
rpm-build 1a6e45
				  const struct pam_message **msg,
rpm-build 1a6e45
				  struct pam_response **presp,
rpm-build 1a6e45
				  void *appdata_ptr)
rpm-build 1a6e45
{
rpm-build 1a6e45
	const struct pam_message *message;
rpm-build 1a6e45
	struct pam_response *resp;
rpm-build 1a6e45
	int i, code;
rpm-build 1a6e45
	unsigned int pwsize;
rpm-build 1a6e45
	struct appl_pam_non_interactive_args *args;
rpm-build 1a6e45
	const char *pwstring;
rpm-build 1a6e45
	resp = malloc(sizeof(struct pam_response) * num_msg);
rpm-build 1a6e45
	if (resp == NULL) {
rpm-build 1a6e45
		return PAM_BUF_ERR;
rpm-build 1a6e45
	}
rpm-build 1a6e45
	args = appdata_ptr;
rpm-build 1a6e45
	memset(resp, 0, sizeof(struct pam_response) * num_msg);
rpm-build 1a6e45
	code = PAM_SUCCESS;
rpm-build 1a6e45
	for (i = 0; i < num_msg; i++) {
rpm-build 1a6e45
		message = &((*msg)[i]);
rpm-build 1a6e45
		message = msg[i];
rpm-build 1a6e45
		pwstring = NULL;
rpm-build 1a6e45
		switch (message->msg_style) {
rpm-build 1a6e45
		case PAM_TEXT_INFO:
rpm-build 1a6e45
		case PAM_ERROR_MSG:
rpm-build 1a6e45
			break;
rpm-build 1a6e45
		case PAM_PROMPT_ECHO_ON:
rpm-build 1a6e45
		case PAM_PROMPT_ECHO_OFF:
rpm-build 1a6e45
			if (message->msg_style == PAM_PROMPT_ECHO_ON) {
rpm-build 1a6e45
				/* assume "user" */
rpm-build 1a6e45
				pwstring = args->user;
rpm-build 1a6e45
			} else {
rpm-build 1a6e45
				/* assume "password" */
rpm-build 1a6e45
				pwstring = args->password;
rpm-build 1a6e45
			}
rpm-build 1a6e45
			if ((pwstring != NULL) && (pwstring[0] != '\0')) {
rpm-build 1a6e45
				pwsize = strlen(pwstring);
rpm-build 1a6e45
				resp[i].resp = malloc(pwsize + 1);
rpm-build 1a6e45
				if (resp[i].resp == NULL) {
rpm-build 1a6e45
					resp[i].resp_retcode = PAM_BUF_ERR;
rpm-build 1a6e45
				} else {
rpm-build 1a6e45
					memcpy(resp[i].resp, pwstring, pwsize);
rpm-build 1a6e45
					resp[i].resp[pwsize] = '\0';
rpm-build 1a6e45
					resp[i].resp_retcode = PAM_SUCCESS;
rpm-build 1a6e45
				}
rpm-build 1a6e45
			} else {
rpm-build 1a6e45
				resp[i].resp_retcode = PAM_CONV_ERR;
rpm-build 1a6e45
				code = PAM_CONV_ERR;
rpm-build 1a6e45
			}
rpm-build 1a6e45
			break;
rpm-build 1a6e45
		default:
rpm-build 1a6e45
			break;
rpm-build 1a6e45
		}
rpm-build 1a6e45
	}
rpm-build 1a6e45
	*presp = resp;
rpm-build 1a6e45
	return code;
rpm-build 1a6e45
}
rpm-build 1a6e45
static int
rpm-build 1a6e45
appl_pam_start(const char *service, int interactive,
rpm-build 1a6e45
	       const char *login_username,
rpm-build 1a6e45
	       const char *non_interactive_password,
rpm-build 1a6e45
	       const char *hostname,
rpm-build 1a6e45
	       const char *ruser,
rpm-build 1a6e45
	       const char *tty)
rpm-build 1a6e45
{
rpm-build 1a6e45
	static int exit_handler_registered;
rpm-build 1a6e45
	static struct appl_pam_non_interactive_args args;
rpm-build 1a6e45
	int ret = 0;
rpm-build 1a6e45
	if (appl_pam_started &&
rpm-build 1a6e45
	    (strcmp(login_username, appl_pam_user) != 0)) {
rpm-build 1a6e45
		appl_pam_cleanup();
rpm-build 1a6e45
		appl_pam_user = NULL;
rpm-build 1a6e45
	}
rpm-build 1a6e45
	if (!appl_pam_started) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
		printf("Starting PAM up (service=\"%s\",user=\"%s\").\n",
rpm-build 1a6e45
		       service, login_username);
rpm-build 1a6e45
#endif
rpm-build 1a6e45
		memset(&appl_pam_conv, 0, sizeof(appl_pam_conv));
rpm-build 1a6e45
		appl_pam_conv.conv = interactive ?
rpm-build 1a6e45
				     &appl_pam_interactive_converse :
rpm-build 1a6e45
				     &appl_pam_non_interactive_converse;
rpm-build 1a6e45
		memset(&args, 0, sizeof(args));
rpm-build 1a6e45
		args.user = strdup(login_username);
rpm-build 1a6e45
		args.password = non_interactive_password ?
rpm-build 1a6e45
				strdup(non_interactive_password) :
rpm-build 1a6e45
				NULL;
rpm-build 1a6e45
		appl_pam_conv.appdata_ptr = &arg;;
rpm-build 1a6e45
		ret = pam_start(service, login_username,
rpm-build 1a6e45
				&appl_pam_conv, &appl_pamh);
rpm-build 1a6e45
		if (ret == 0) {
rpm-build 1a6e45
			if (hostname != NULL) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
				printf("Setting PAM_RHOST to \"%s\".\n", hostname);
rpm-build 1a6e45
#endif
rpm-build 1a6e45
				pam_set_item(appl_pamh, PAM_RHOST, hostname);
rpm-build 1a6e45
			}
rpm-build 1a6e45
			if (ruser != NULL) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
				printf("Setting PAM_RUSER to \"%s\".\n", ruser);
rpm-build 1a6e45
#endif
rpm-build 1a6e45
				pam_set_item(appl_pamh, PAM_RUSER, ruser);
rpm-build 1a6e45
			}
rpm-build 1a6e45
			if (tty != NULL) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
				printf("Setting PAM_TTY to \"%s\".\n", tty);
rpm-build 1a6e45
#endif
rpm-build 1a6e45
				pam_set_item(appl_pamh, PAM_TTY, tty);
rpm-build 1a6e45
			}
rpm-build 1a6e45
			if (!exit_handler_registered &&
rpm-build 1a6e45
			    (atexit(appl_pam_cleanup) != 0)) {
rpm-build 1a6e45
				pam_end(appl_pamh, 0);
rpm-build 1a6e45
				appl_pamh = NULL;
rpm-build 1a6e45
				ret = -1;
rpm-build 1a6e45
			} else {
rpm-build 1a6e45
				appl_pam_started = 1;
rpm-build 1a6e45
				appl_pam_starter = getpid();
rpm-build 1a6e45
				appl_pam_user = strdup(login_username);
rpm-build 1a6e45
				exit_handler_registered = 1;
rpm-build 1a6e45
			}
rpm-build 1a6e45
		}
rpm-build 1a6e45
	}
rpm-build 1a6e45
	return ret;
rpm-build 1a6e45
}
rpm-build 1a6e45
int
rpm-build 1a6e45
appl_pam_acct_mgmt(const char *service, int interactive,
rpm-build 1a6e45
		   const char *login_username,
rpm-build 1a6e45
		   const char *non_interactive_password,
rpm-build 1a6e45
		   const char *hostname,
rpm-build 1a6e45
		   const char *ruser,
rpm-build 1a6e45
		   const char *tty)
rpm-build 1a6e45
{
rpm-build 1a6e45
	int ret;
rpm-build 1a6e45
	appl_pam_pwchange_required = 0;
rpm-build 1a6e45
	ret = appl_pam_start(service, interactive, login_username,
rpm-build 1a6e45
			     non_interactive_password, hostname, ruser, tty);
rpm-build 1a6e45
	if (ret == 0) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
		printf("Calling pam_acct_mgmt().\n");
rpm-build 1a6e45
#endif
rpm-build 1a6e45
		ret = pam_acct_mgmt(appl_pamh, 0);
rpm-build 1a6e45
		switch (ret) {
rpm-build 1a6e45
		case PAM_IGNORE:
rpm-build 1a6e45
			ret = 0;
rpm-build 1a6e45
			break;
rpm-build 1a6e45
		case PAM_NEW_AUTHTOK_REQD:
rpm-build 1a6e45
			appl_pam_pwchange_required = 1;
rpm-build 1a6e45
			ret = 0;
rpm-build 1a6e45
			break;
rpm-build 1a6e45
		default:
rpm-build 1a6e45
			break;
rpm-build 1a6e45
		}
rpm-build 1a6e45
	}
rpm-build 1a6e45
	return ret;
rpm-build 1a6e45
}
rpm-build 1a6e45
int
rpm-build 1a6e45
appl_pam_requires_chauthtok(void)
rpm-build 1a6e45
{
rpm-build 1a6e45
	return appl_pam_pwchange_required;
rpm-build 1a6e45
}
rpm-build 1a6e45
int
rpm-build 1a6e45
appl_pam_session_open(void)
rpm-build 1a6e45
{
rpm-build 1a6e45
	int ret = 0;
rpm-build 1a6e45
	if (appl_pam_started) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
		printf("Opening PAM session.\n");
rpm-build 1a6e45
#endif
rpm-build 1a6e45
		ret = pam_open_session(appl_pamh, 0);
rpm-build 1a6e45
		if (ret == 0) {
rpm-build 1a6e45
			appl_pam_session_opened = 1;
rpm-build 1a6e45
		}
rpm-build 1a6e45
	}
rpm-build 1a6e45
	return ret;
rpm-build 1a6e45
}
rpm-build 1a6e45
int
rpm-build 1a6e45
appl_pam_setenv(void)
rpm-build 1a6e45
{
rpm-build 1a6e45
	int ret = 0;
rpm-build 1a6e45
#ifdef HAVE_PAM_GETENVLIST
rpm-build 1a6e45
#ifdef HAVE_PUTENV
rpm-build 1a6e45
	int i;
rpm-build 1a6e45
	char **list;
rpm-build 1a6e45
	if (appl_pam_started) {
rpm-build 1a6e45
		list = pam_getenvlist(appl_pamh);
rpm-build 1a6e45
		for (i = 0; ((list != NULL) && (list[i] != NULL)); i++) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
			printf("Setting \"%s\" in environment.\n", list[i]);
rpm-build 1a6e45
#endif
rpm-build 1a6e45
			putenv(list[i]);
rpm-build 1a6e45
		}
rpm-build 1a6e45
	}
rpm-build 1a6e45
#endif
rpm-build 1a6e45
#endif
rpm-build 1a6e45
	return ret;
rpm-build 1a6e45
}
rpm-build 1a6e45
int
rpm-build 1a6e45
appl_pam_cred_init(void)
rpm-build 1a6e45
{
rpm-build 1a6e45
	int ret = 0;
rpm-build 1a6e45
	if (appl_pam_started) {
rpm-build 1a6e45
#ifdef DEBUG
rpm-build 1a6e45
		printf("Initializing PAM credentials.\n");
rpm-build 1a6e45
#endif
rpm-build 1a6e45
		ret = pam_setcred(appl_pamh, PAM_ESTABLISH_CRED);
rpm-build 1a6e45
		if (ret == 0) {
rpm-build 1a6e45
			appl_pam_creds_initialized = 1;
rpm-build 1a6e45
		}
rpm-build 1a6e45
	}
rpm-build 1a6e45
	return ret;
rpm-build 1a6e45
}
rpm-build 1a6e45
#endif