/*
* 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
* 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
*/
/*
*/
#include <libzfs.h>
#include <libzfs_impl.h>
#include <sys/zfs_ioctl.h>
#include <libgen.h>
#include <nss_dbdefs.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <errno.h>
#include <strings.h>
#include <libintl.h>
#include <fcntl.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <security/pam_impl.h>
/*ARGSUSED*/
int
{
return (PAM_IGNORE);
}
/*PRINTFLIKE3*/
static void
{
}
static void
{
char *passphrase;
zfs_get_name(zhp));
&passphrase) != PAM_SUCCESS)
return;
}
static int
{
int ret;
char *nvbuf;
zc.zc_perm_action = 0;
return (ret);
}
static void
{
int err;
return;
}
} else {
}
}
/*
* zfs_key - pam_sm_setcred
*
* Entry flags = PAM_ESTABLISH_CRED, load key
* PAM_DELETE_CRED, unload key
* PAM_REINITIALIZE_CRED NOOP
* PAM_REFRESH_CRED NOOP
* PAM_SILENT, print no messages to user.
*
* Returns PAM_SUCCESS, if all successful.
* PAM_CRED_ERR, if unable to set credentials.
* PAM_USER_UNKNOWN, if PAM_USER not set, or unable to find
* user in databases.
* user's audit state.
*/
int
{
int i;
int err = 0;
char *user;
int keystatus;
char *authtok;
for (i = 0; i < argc; i++) {
"pam_zfs_key invalid configuration 'homes='"
" can not be empty"));
return (PAM_SERVICE_ERR);
}
(void) strlcpy(encryption,
} else {
"pam_zfs_key unknown option '%s'"), argv[i]);
return (PAM_SERVICE_ERR);
}
}
if (debug)
"pam_zfs_key: pam_sm_setcred(flags = %x, argc= %d)",
"pam_zfs_key: USER NULL or empty!\n");
return (PAM_USER_UNKNOWN);
}
/* validate flags */
case 0:
/* set default flag */
break;
case PAM_REFRESH_CRED:
return (PAM_IGNORE);
case PAM_REINITIALIZE_CRED:
case PAM_ESTABLISH_CRED:
case PAM_DELETE_CRED:
break;
default:
"pam_zfs_key: invalid flags %x", flags);
return (PAM_SYSTEM_ERR);
}
g_zfs = libzfs_init();
return (PAM_IGNORE);
if (!nowarn) {
"Creating home directory with encryption=%s.\n"
"Your login password will be used as the "
"wrapping key."), encryption);
}
(void) nvlist_add_string(props,
encryption, &crypt);
if (crypt != ZIO_CRYPT_OFF) {
(void) nvlist_add_string(props,
"passphrase,prompt");
}
if (err != 0) {
if (!nowarn)
"creating home directory failed: %s"),
return (PAM_CRED_ERR);
}
err = -1;
goto out;
}
if (err != 0) {
goto out;
}
if (err != 0) {
goto out;
}
if (err != 0) {
goto out;
}
goto out;
}
/*
* Checking keystatus of none means we don't need to
* check the value of the encryption property since
* datasets with encryption=off always have an undefined
* keystatus.
*/
if (keystatus == ZFS_CRYPT_KEY_NONE) {
ret = PAM_IGNORE;
goto out;
}
if (propsrctype != ZPROP_SRC_LOCAL ||
"home dir %s for %s has incompatible keysource %s",
ret = PAM_IGNORE;
goto out;
}
if (keystatus == ZFS_CRYPT_KEY_UNAVAILABLE &&
!(flags & PAM_DELETE_CRED)) {
/*
* First try an unmount of pw_dir if it is autofs
* in case automounter already attempted to
* mount up the pw_dir.
*/
"pam_zfs_key strdup failed: %m"));
ret = PAM_BUF_ERR;
goto out;
} else {
}
}
if (!nowarn) {
"ZFS Key load failed for %s: %s"),
}
ret = PAM_CRED_ERR;
if (!nowarn) {
"ZFS Key load failed for %s: %s"),
}
}
}
} else if (keystatus == ZFS_CRYPT_KEY_AVAILABLE &&
!(flags & PAM_DELETE_CRED)) {
ret = PAM_IGNORE;
goto out;
} else if (keystatus == ZFS_CRYPT_KEY_AVAILABLE &&
(flags & PAM_DELETE_CRED)) {
/*
* Don't fail on the unmount just in case the module
* isn't running with all privs. If this is
* the automount point it will just end up stale and timeout,
* if the underlying real home dir does end up unmounted.
*/
(void) chdir("/");
}
if (!nowarn) {
"ZFS Key unload for %s failed: %s "),
}
}
/* Try again to remove the possibly automounted dir */
}
}
out:
ret = PAM_CRED_ERR;
}
return (ret);
}
int
{
int err;
char *user;
int keystatus;
int i;
for (i = 0; i < argc; i++) {
}
}
if ((flags & PAM_PRELIM_CHECK) != 0)
return (PAM_IGNORE);
if ((flags & PAM_UPDATE_AUTHTOK) == 0)
return (PAM_SYSTEM_ERR);
"pam_zfs_key: USER NULL or empty!\n");
return (PAM_USER_UNKNOWN);
}
g_zfs = libzfs_init();
return (PAM_IGNORE);
}
if (propsrctype != ZPROP_SRC_LOCAL ||
ret = PAM_IGNORE;
goto out;
}
/*
* Checking keystatus for undefined means we don't need to
* check the value of the encryption property since
* datasets with encryption=off always have an undefined
* keystatus.
*/
if (keystatus == ZFS_CRYPT_KEY_NONE) {
ret = PAM_IGNORE;
goto out;
}
if (keystatus == ZFS_CRYPT_KEY_UNAVAILABLE) {
if (oldauthtok == NULL) {
if (!nowarn)
" for %s: old passphrase required"),
dataset);
goto out;
}
if (err != 0) {
if (err != 0) {
if (!nowarn) {
"ZFS Key load failed for %s: %s"),
}
goto out;
}
}
}
/*
* Temporarily switch over euid to ruid so that the kernel
* side of ZFS checks the 'keychange' delgation of the real user
* changing their password and it isn't bypassed because
* passwd(1) is setuid.
*/
goto out;
}
goto out;
}
if (err != 0) {
if (!nowarn) {
"ZFS Key change failed for %s: %s"), dataset,
}
} else if (!nowarn) {
"ZFS Key change for %s successful"), dataset);
}
out:
return (ret);
}