Blame pam_cifscreds.c

Packit 5f9837
/*
Packit 5f9837
 * Copyright (C) 2013 Orion Poplawski <orion@cora.nwra.com>
Packit 5f9837
 *
Packit 5f9837
 * based on gkr-pam-module.c, Copyright (C) 2007 Stef Walter
Packit 5f9837
 *
Packit 5f9837
 * This program is free software; you can redistribute it and/or modify
Packit 5f9837
 * it under the terms of the GNU General Public License as published by
Packit 5f9837
 * the Free Software Foundation; either version 3 of the License, or
Packit 5f9837
 * (at your option) any later version.
Packit 5f9837
 *
Packit 5f9837
 * This program is distributed in the hope that it will be useful,
Packit 5f9837
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5f9837
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 5f9837
 * GNU General Public License for more details.
Packit 5f9837
 *
Packit 5f9837
 * You should have received a copy of the GNU General Public License
Packit 5f9837
 * along with this program; if not, write to the Free Software
Packit 5f9837
 */
Packit 5f9837
Packit 5f9837
#ifdef HAVE_CONFIG_H
Packit 5f9837
#include "config.h"
Packit 5f9837
#endif /* HAVE_CONFIG_H */
Packit 5f9837
Packit 5f9837
#include <assert.h>
Packit 5f9837
#include <errno.h>
Packit 5f9837
#include <stdio.h>
Packit 5f9837
#include <stdlib.h>
Packit 5f9837
#include <string.h>
Packit 5f9837
#include <syslog.h>
Packit 5f9837
#include <sys/types.h>
Packit 5f9837
/*
Packit 5f9837
#include <signal.h>
Packit 5f9837
#include <unistd.h>
Packit 5f9837
#include <sys/wait.h>
Packit 5f9837
*/
Packit 5f9837
Packit 5f9837
#include <keyutils.h>
Packit 5f9837
Packit 5f9837
#include <security/pam_appl.h>
Packit 5f9837
#include <security/pam_modules.h>
Packit 5f9837
#include <security/pam_ext.h>
Packit 5f9837
Packit 5f9837
#include "cifskey.h"
Packit 5f9837
#include "mount.h"
Packit 5f9837
#include "resolve_host.h"
Packit 5f9837
#include "util.h"
Packit 5f9837
Packit 5f9837
/**
Packit 5f9837
 * Flags that can be passed to the PAM module
Packit 5f9837
 */
Packit 5f9837
enum {
Packit 5f9837
	ARG_DOMAIN	   = 1 << 0,	/** Set domain password */
Packit 5f9837
	ARG_DEBUG	   = 1 << 1	/** Print debug messages */
Packit 5f9837
};
Packit 5f9837
Packit 5f9837
/**
Packit 5f9837
 * Parse the arguments passed to the PAM module.
Packit 5f9837
 *
Packit 5f9837
 * @param ph PAM handle
Packit 5f9837
 * @param argc number of arguments
Packit 5f9837
 * @param argv array of arguments
Packit 5f9837
 * @param kwalletopener kwalletopener argument, path to the kwalletopener binary
Packit 5f9837
 * @return ORed flags that have been parsed
Packit 5f9837
 */
Packit 5f9837
static uint parse_args (pam_handle_t *ph, int argc, const char **argv, const char **hostdomain)
Packit 5f9837
{
Packit 5f9837
	uint args = 0;
Packit 5f9837
	const void *svc;
Packit 5f9837
	int i;
Packit 5f9837
	const char *host = NULL;
Packit 5f9837
	const char *domain = NULL;
Packit 5f9837
Packit 5f9837
	svc = NULL;
Packit 5f9837
	if (pam_get_item (ph, PAM_SERVICE, &svc) != PAM_SUCCESS) {
Packit 5f9837
		svc = NULL;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	size_t host_len = strlen("host=");
Packit 5f9837
	size_t domain_len = strlen("domain=");
Packit 5f9837
Packit 5f9837
	/* Parse the arguments */
Packit 5f9837
	for (i = 0; i < argc; i++) {
Packit 5f9837
		if (strncmp(argv[i], "host=", host_len) == 0) {
Packit 5f9837
			host = (argv[i]) + host_len;
Packit 5f9837
			if (*host == '\0') {
Packit 5f9837
				host = NULL;
Packit 5f9837
				pam_syslog(ph, LOG_ERR, ""
Packit 5f9837
					   "host= specification missing argument");
Packit 5f9837
			} else {
Packit 5f9837
				*hostdomain = host;
Packit 5f9837
			}
Packit 5f9837
		} else if (strncmp(argv[i], "domain=", domain_len) == 0) {
Packit 5f9837
			domain = (argv[i]) + domain_len;
Packit 5f9837
			if (*domain == '\0') {
Packit 5f9837
				domain = NULL;
Packit 5f9837
				pam_syslog(ph, LOG_ERR, ""
Packit 5f9837
					   "domain= specification missing argument");
Packit 5f9837
			} else {
Packit 5f9837
				*hostdomain = domain;
Packit 5f9837
				args |= ARG_DOMAIN;
Packit 5f9837
			}
Packit 5f9837
		} else if (strcmp(argv[i], "debug") == 0) {
Packit 5f9837
			args |= ARG_DEBUG;
Packit 5f9837
		} else {
Packit 5f9837
			pam_syslog(ph, LOG_ERR, "invalid option %s",
Packit 5f9837
				   argv[i]);
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (host && domain) {
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "cannot specify both host= and "
Packit 5f9837
			   "domain= arguments");
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return args;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static void
Packit 5f9837
free_password (char *password)
Packit 5f9837
{
Packit 5f9837
	volatile char *vp;
Packit 5f9837
	size_t len;
Packit 5f9837
Packit 5f9837
	if (!password) {
Packit 5f9837
		return;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* Defeats some optimizations */
Packit 5f9837
	len = strlen (password);
Packit 5f9837
	memset (password, 0xAA, len);
Packit 5f9837
	memset (password, 0xBB, len);
Packit 5f9837
Packit 5f9837
	/* Defeats others */
Packit 5f9837
	vp = (volatile char*)password;
Packit 5f9837
	while (*vp) {
Packit 5f9837
		*(vp++) = 0xAA;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	free (password);
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
static void
Packit 5f9837
cleanup_free_password (pam_handle_t *ph __attribute__((unused)), void *data,
Packit 5f9837
			int pam_end_status __attribute__((unused)))
Packit 5f9837
{
Packit 5f9837
	free_password (data);
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/**
Packit 5f9837
 * Set the cifs credentials
Packit 5f9837
 *
Packit 5f9837
 * @param ph PAM handle
Packit 5f9837
 * @param user
Packit 5f9837
 * @param password
Packit 5f9837
 * @param args ORed flags for this module
Packit 5f9837
 * @param hostdomain hostname or domainname
Packit 5f9837
 */
Packit 5f9837
static int cifscreds_pam_add(pam_handle_t *ph, const char *user, const char *password,
Packit 5f9837
			     uint args, const char *hostdomain)
Packit 5f9837
{
Packit 5f9837
	int ret = PAM_SUCCESS;
Packit 5f9837
	char addrstr[MAX_ADDR_LIST_LEN];
Packit 5f9837
	char *currentaddress, *nextaddress;
Packit 5f9837
	char keytype = ((args & ARG_DOMAIN) == ARG_DOMAIN) ? 'd' : 'a';
Packit 5f9837
Packit 5f9837
	assert(user);
Packit 5f9837
	assert(password);
Packit 5f9837
	assert(hostdomain);
Packit 5f9837
Packit 5f9837
	if (keytype == 'd') {
Packit 5f9837
		if (strpbrk(hostdomain, DOMAIN_DISALLOWED_CHARS)) {
Packit 5f9837
			pam_syslog(ph, LOG_ERR, "Domain name contains invalid characters");
Packit 5f9837
			return PAM_SERVICE_ERR;
Packit 5f9837
		}
Packit 5f9837
		strlcpy(addrstr, hostdomain, MAX_ADDR_LIST_LEN);
Packit 5f9837
	} else {
Packit 5f9837
		ret = resolve_host(hostdomain, addrstr);
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	switch (ret) {
Packit 5f9837
	case EX_USAGE:
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "Could not resolve address for %s", hostdomain);
Packit 5f9837
		return PAM_SERVICE_ERR;
Packit 5f9837
Packit 5f9837
	case EX_SYSERR:
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "Problem parsing address list");
Packit 5f9837
		return PAM_SERVICE_ERR;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (strpbrk(user, USER_DISALLOWED_CHARS)) {
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "Incorrect username");
Packit 5f9837
		return PAM_SERVICE_ERR;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* search for same credentials stashed for current host */
Packit 5f9837
	currentaddress = addrstr;
Packit 5f9837
	nextaddress = strchr(currentaddress, ',');
Packit 5f9837
	if (nextaddress)
Packit 5f9837
		*nextaddress++ = '\0';
Packit 5f9837
Packit 5f9837
	while (currentaddress) {
Packit 5f9837
		if (key_search(currentaddress, keytype) > 0) {
Packit 5f9837
			pam_syslog(ph, LOG_WARNING, "You already have stashed credentials "
Packit 5f9837
				"for %s (%s)", currentaddress, hostdomain);
Packit 5f9837
Packit 5f9837
			return PAM_SERVICE_ERR;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		switch(errno) {
Packit 5f9837
		case ENOKEY:
Packit 5f9837
			/* success */
Packit 5f9837
			break;
Packit 5f9837
		default:
Packit 5f9837
			pam_syslog(ph, LOG_ERR, "Unable to search keyring for %s (%s)",
Packit 5f9837
					currentaddress, strerror(errno));
Packit 5f9837
			return PAM_SERVICE_ERR;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		currentaddress = nextaddress;
Packit 5f9837
		if (currentaddress) {
Packit 5f9837
			*(currentaddress - 1) = ',';
Packit 5f9837
			nextaddress = strchr(currentaddress, ',');
Packit 5f9837
			if (nextaddress)
Packit 5f9837
				*nextaddress++ = '\0';
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* Set the password */
Packit 5f9837
	currentaddress = addrstr;
Packit 5f9837
	nextaddress = strchr(currentaddress, ',');
Packit 5f9837
	if (nextaddress)
Packit 5f9837
		*nextaddress++ = '\0';
Packit 5f9837
Packit 5f9837
	while (currentaddress) {
Packit 5f9837
		key_serial_t key = key_add(currentaddress, user, password, keytype);
Packit 5f9837
		if (key <= 0) {
Packit 5f9837
			pam_syslog(ph, LOG_ERR, "error: Add credential key for %s: %s",
Packit 5f9837
				currentaddress, strerror(errno));
Packit 5f9837
		} else {
Packit 5f9837
			if ((args & ARG_DEBUG) == ARG_DEBUG) {
Packit 5f9837
				pam_syslog(ph, LOG_DEBUG, "credential key for \\\\%s\\%s added",
Packit 5f9837
					   currentaddress, user);
Packit 5f9837
			}
Packit 5f9837
			if (keyctl(KEYCTL_SETPERM, key, CIFS_KEY_PERMS) < 0) {
Packit 5f9837
				pam_syslog(ph, LOG_ERR,"error: Setting permissons "
Packit 5f9837
					"on key, attempt to delete...");
Packit 5f9837
Packit 5f9837
				if (keyctl(KEYCTL_UNLINK, key, DEST_KEYRING) < 0) {
Packit 5f9837
					pam_syslog(ph, LOG_ERR, "error: Deleting key from "
Packit 5f9837
						"keyring for %s (%s)",
Packit 5f9837
						currentaddress, hostdomain);
Packit 5f9837
				}
Packit 5f9837
			}
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		currentaddress = nextaddress;
Packit 5f9837
		if (currentaddress) {
Packit 5f9837
			nextaddress = strchr(currentaddress, ',');
Packit 5f9837
			if (nextaddress)
Packit 5f9837
				*nextaddress++ = '\0';
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return PAM_SUCCESS;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/**
Packit 5f9837
 * Update the cifs credentials
Packit 5f9837
 *
Packit 5f9837
 * @param ph PAM handle
Packit 5f9837
 * @param user
Packit 5f9837
 * @param password
Packit 5f9837
 * @param args ORed flags for this module
Packit 5f9837
 * @param hostdomain hostname or domainname
Packit 5f9837
 */
Packit 5f9837
static int cifscreds_pam_update(pam_handle_t *ph, const char *user, const char *password,
Packit 5f9837
				uint args, const char *hostdomain)
Packit 5f9837
{
Packit 5f9837
	int ret = PAM_SUCCESS;
Packit 5f9837
	char addrstr[MAX_ADDR_LIST_LEN];
Packit 5f9837
	char *currentaddress, *nextaddress;
Packit 5f9837
	int id, count = 0;
Packit 5f9837
	char keytype = ((args & ARG_DOMAIN) == ARG_DOMAIN) ? 'd' : 'a';
Packit 5f9837
Packit 5f9837
	assert(user);
Packit 5f9837
	assert(password);
Packit 5f9837
	assert(hostdomain);
Packit 5f9837
Packit 5f9837
	if (keytype == 'd') {
Packit 5f9837
		if (strpbrk(hostdomain, DOMAIN_DISALLOWED_CHARS)) {
Packit 5f9837
			pam_syslog(ph, LOG_ERR, "Domain name contains invalid characters");
Packit 5f9837
			return PAM_SERVICE_ERR;
Packit 5f9837
		}
Packit 5f9837
		strlcpy(addrstr, hostdomain, MAX_ADDR_LIST_LEN);
Packit 5f9837
	} else {
Packit 5f9837
		ret = resolve_host(hostdomain, addrstr);
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	switch (ret) {
Packit 5f9837
	case EX_USAGE:
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "Could not resolve address for %s", hostdomain);
Packit 5f9837
		return PAM_SERVICE_ERR;
Packit 5f9837
Packit 5f9837
	case EX_SYSERR:
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "Problem parsing address list");
Packit 5f9837
		return PAM_SERVICE_ERR;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (strpbrk(user, USER_DISALLOWED_CHARS)) {
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "Incorrect username");
Packit 5f9837
		return PAM_SERVICE_ERR;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* search for necessary credentials stashed in session keyring */
Packit 5f9837
	currentaddress = addrstr;
Packit 5f9837
	nextaddress = strchr(currentaddress, ',');
Packit 5f9837
	if (nextaddress)
Packit 5f9837
		*nextaddress++ = '\0';
Packit 5f9837
Packit 5f9837
	while (currentaddress) {
Packit 5f9837
		if (key_search(currentaddress, keytype) > 0)
Packit 5f9837
			count++;
Packit 5f9837
Packit 5f9837
		currentaddress = nextaddress;
Packit 5f9837
		if (currentaddress) {
Packit 5f9837
			nextaddress = strchr(currentaddress, ',');
Packit 5f9837
			if (nextaddress)
Packit 5f9837
				*nextaddress++ = '\0';
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if (!count) {
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "You have no same stashed credentials for %s", hostdomain);
Packit 5f9837
		return PAM_SERVICE_ERR;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	for (id = 0; id < count; id++) {
Packit 5f9837
		key_serial_t key = key_add(currentaddress, user, password, keytype);
Packit 5f9837
		if (key <= 0) {
Packit 5f9837
			pam_syslog(ph, LOG_ERR, "error: Update credential key for %s: %s",
Packit 5f9837
				currentaddress, strerror(errno));
Packit 5f9837
		}
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return PAM_SUCCESS;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/**
Packit 5f9837
 * PAM function called during authentication.
Packit 5f9837
 *
Packit 5f9837
 * This function first tries to get a password from PAM. Afterwards two
Packit 5f9837
 * scenarios are possible:
Packit 5f9837
 *
Packit 5f9837
 * - A session is already available which usually means that the user is already
Packit 5f9837
 *	logged on and PAM has been used inside the screensaver. In that case, no need to
Packit 5f9837
 *	do anything(?).
Packit 5f9837
 *
Packit 5f9837
 * - A session is not yet available. Store the password inside PAM data so
Packit 5f9837
 *	it can be retrieved during pam_open_session to set the credentials.
Packit 5f9837
 *
Packit 5f9837
 * @param ph PAM handle
Packit 5f9837
 * @param unused unused
Packit 5f9837
 * @param argc number of arguments for this PAM module
Packit 5f9837
 * @param argv array of arguments for this PAM module
Packit 5f9837
 * @return any of the PAM return values
Packit 5f9837
 */
Packit 5f9837
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *ph, int unused __attribute__((unused)), int argc, const char **argv)
Packit 5f9837
{
Packit 5f9837
	const char *hostdomain;
Packit 5f9837
	const char *user;
Packit 5f9837
	const char *password;
Packit 5f9837
	uint args;
Packit 5f9837
	int ret;
Packit 5f9837
Packit 5f9837
	args = parse_args(ph, argc, argv, &hostdomain);
Packit 5f9837
Packit 5f9837
	/* Figure out and/or prompt for the user name */
Packit 5f9837
	ret = pam_get_user(ph, &user, NULL);
Packit 5f9837
	if (ret != PAM_SUCCESS || !user) {
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "couldn't get the user name: %s",
Packit 5f9837
			   pam_strerror(ph, ret));
Packit 5f9837
		return PAM_SERVICE_ERR;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* Lookup the password */
Packit 5f9837
	ret = pam_get_item(ph, PAM_AUTHTOK, (const void**)&password);
Packit 5f9837
	if (ret != PAM_SUCCESS || password == NULL) {
Packit 5f9837
		if (ret == PAM_SUCCESS) {
Packit 5f9837
			pam_syslog(ph, LOG_WARNING, "no password is available for user");
Packit 5f9837
		} else {
Packit 5f9837
			pam_syslog(ph, LOG_WARNING, "no password is available for user: %s",
Packit 5f9837
				   pam_strerror(ph, ret));
Packit 5f9837
		}
Packit 5f9837
		return PAM_SUCCESS;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* set password as pam data and launch during open_session. */
Packit 5f9837
	if (pam_set_data(ph, "cifscreds_password", strdup(password), cleanup_free_password) != PAM_SUCCESS) {
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "error storing password");
Packit 5f9837
		return PAM_AUTHTOK_RECOVER_ERR;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	if ((args & ARG_DEBUG) == ARG_DEBUG) {
Packit 5f9837
		pam_syslog(ph, LOG_DEBUG, "password stored");
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	return PAM_SUCCESS;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/**
Packit 5f9837
 * PAM function called during opening the session.
Packit 5f9837
 *
Packit 5f9837
 * Retrieves the password stored during authentication from PAM data, then uses
Packit 5f9837
 * it set the cifs key.
Packit 5f9837
 *
Packit 5f9837
 * @param ph PAM handle
Packit 5f9837
 * @param flags currently unused, TODO: check for silent flag
Packit 5f9837
 * @param argc number of arguments for this PAM module
Packit 5f9837
 * @param argv array of arguments for this PAM module
Packit 5f9837
 * @return any of the PAM return values
Packit 5f9837
 */
Packit 5f9837
PAM_EXTERN int pam_sm_open_session(pam_handle_t *ph, int flags __attribute__((unused)), int argc, const char **argv)
Packit 5f9837
{
Packit 5f9837
	const char *user = NULL;
Packit 5f9837
	const char *password = NULL;
Packit 5f9837
	const char *hostdomain = NULL;
Packit 5f9837
	uint args;
Packit 5f9837
	int retval;
Packit 5f9837
	key_serial_t	ses_key, uses_key;
Packit 5f9837
Packit 5f9837
	args = parse_args(ph, argc, argv, &hostdomain);
Packit 5f9837
Packit 5f9837
	/* Figure out the user name */
Packit 5f9837
	retval = pam_get_user(ph, &user, NULL);
Packit 5f9837
	if (retval != PAM_SUCCESS || !user) {
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "couldn't get the user name: %s",
Packit 5f9837
			   pam_strerror(ph, retval));
Packit 5f9837
		return PAM_SERVICE_ERR;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* retrieve the stored password */
Packit 5f9837
	if (pam_get_data(ph, "cifscreds_password", (const void**)&password) != PAM_SUCCESS) {
Packit 5f9837
		/*
Packit 5f9837
		 * No password, no worries, maybe this (PAM using) application
Packit 5f9837
		 * didn't do authentication, or is hopeless and wants to call
Packit 5f9837
		 * different PAM callbacks from different processes.
Packit 5f9837
		 *
Packit 5f9837
		 *
Packit 5f9837
		 */
Packit 5f9837
		password = NULL;
Packit 5f9837
		if ((args & ARG_DEBUG) == ARG_DEBUG) {
Packit 5f9837
			pam_syslog(ph, LOG_DEBUG, "no stored password found");
Packit 5f9837
		}
Packit 5f9837
		return PAM_SUCCESS;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* make sure we have a host or domain name */
Packit 5f9837
	if (!hostdomain) {
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "one of host= or domain= must be specified");
Packit 5f9837
		return PAM_SERVICE_ERR;
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* make sure there is a session keyring */
Packit 5f9837
	ses_key = keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
Packit 5f9837
	if (ses_key == -1) {
Packit 5f9837
		if (errno == ENOKEY)
Packit 5f9837
			pam_syslog(ph, LOG_ERR, "you have no session keyring. "
Packit 5f9837
					"Consider using pam_keyinit to "
Packit 5f9837
					"install one.");
Packit 5f9837
		else
Packit 5f9837
			pam_syslog(ph, LOG_ERR, "unable to query session "
Packit 5f9837
					"keyring: %s", strerror(errno));
Packit 5f9837
	}
Packit 5f9837
Packit 5f9837
	/* A problem querying the user-session keyring isn't fatal. */
Packit 5f9837
	uses_key = keyctl_get_keyring_ID(KEY_SPEC_USER_SESSION_KEYRING, 0);
Packit 5f9837
	if ((uses_key >= 0) && (ses_key == uses_key))
Packit 5f9837
		pam_syslog(ph, LOG_ERR, "you have no persistent session "
Packit 5f9837
				"keyring. cifscreds keys will not persist.");
Packit 5f9837
Packit 5f9837
	return cifscreds_pam_add(ph, user, password, args, hostdomain);
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/**
Packit 5f9837
 * This is called when the PAM session is closed.
Packit 5f9837
 *
Packit 5f9837
 * Currently it does nothing.  The session closing should remove the passwords
Packit 5f9837
 *
Packit 5f9837
 * @param ph PAM handle
Packit 5f9837
 * @param flags currently unused, TODO: check for silent flag
Packit 5f9837
 * @param argc number of arguments for this PAM module
Packit 5f9837
 * @param argv array of arguments for this PAM module
Packit 5f9837
 * @return PAM_SUCCESS
Packit 5f9837
 */
Packit 5f9837
PAM_EXTERN int pam_sm_close_session(pam_handle_t *ph __attribute__((unused)), int flags __attribute__((unused)), int argc __attribute__((unused)), const char **argv __attribute__((unused)))
Packit 5f9837
{
Packit 5f9837
	return PAM_SUCCESS;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/**
Packit 5f9837
 * This is called when pam_set_cred() is invoked.
Packit 5f9837
 *
Packit 5f9837
 * @param ph PAM handle
Packit 5f9837
 * @param flags currently unused, TODO: check for silent flag
Packit 5f9837
 * @param argc number of arguments for this PAM module
Packit 5f9837
 * @param argv array of arguments for this PAM module
Packit 5f9837
 * @return PAM_SUCCESS
Packit 5f9837
 */
Packit 5f9837
PAM_EXTERN int pam_sm_setcred(pam_handle_t *ph __attribute__((unused)), int flags __attribute__((unused)), int argc __attribute__((unused)), const char **argv __attribute__((unused)))
Packit 5f9837
{
Packit 5f9837
	return PAM_SUCCESS;
Packit 5f9837
}
Packit 5f9837
Packit 5f9837
/**
Packit 5f9837
 * This is called when the user's password is changed
Packit 5f9837
 *
Packit 5f9837
 * @param ph PAM handle
Packit 5f9837
 * @param flags currently unused, TODO: check for silent flag
Packit 5f9837
 * @param argc number of arguments for this PAM module
Packit 5f9837
 * @param argv array of arguments for this PAM module
Packit 5f9837
 * @return PAM_SUCCESS
Packit 5f9837
 */
Packit 5f9837
PAM_EXTERN int
Packit 5f9837
pam_sm_chauthtok (pam_handle_t *ph, int flags, int argc, const char **argv)
Packit 5f9837
{
Packit 5f9837
	const char *hostdomain = NULL;
Packit 5f9837
	const char *user = NULL;
Packit 5f9837
	const char *password = NULL;
Packit 5f9837
	uint args;
Packit 5f9837
	int ret;
Packit 5f9837
Packit 5f9837
	args = parse_args(ph, argc, argv, &hostdomain);
Packit 5f9837
Packit 5f9837
	if (flags & PAM_UPDATE_AUTHTOK) {
Packit 5f9837
		/* Figure out the user name */
Packit 5f9837
		ret = pam_get_user(ph, &user, NULL);
Packit 5f9837
		if (ret != PAM_SUCCESS) {
Packit 5f9837
			pam_syslog(ph, LOG_ERR, "couldn't get the user name: %s", pam_strerror (ph, ret));
Packit 5f9837
			return PAM_SERVICE_ERR;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		ret = pam_get_item(ph, PAM_AUTHTOK, (const void**)&password);
Packit 5f9837
		if (ret != PAM_SUCCESS || password == NULL) {
Packit 5f9837
			if (ret == PAM_SUCCESS) {
Packit 5f9837
				pam_syslog(ph, LOG_WARNING, "no password is available for user");
Packit 5f9837
			} else {
Packit 5f9837
				pam_syslog(ph, LOG_WARNING, "no password is available for user: %s", pam_strerror(ph, ret));
Packit 5f9837
			}
Packit 5f9837
			return PAM_AUTHTOK_RECOVER_ERR;
Packit 5f9837
		}
Packit 5f9837
Packit 5f9837
		return cifscreds_pam_update(ph, user, password, args, hostdomain);
Packit 5f9837
	}
Packit 5f9837
	else
Packit 5f9837
		return PAM_IGNORE;
Packit 5f9837
}