/*
* 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 <krb5.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <security/pam_impl.h>
#include <syslog.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <libintl.h>
#include <netdb.h>
#include "utils.h"
#include <shadow.h>
#include "krb5_repository.h"
#define min(a, b) ((a) < (b) ? (a) : (b))
/*
* pam_sm_acct_mgmt main account managment routine.
*/
static int
char *princ_str,
int debug)
{
void *server_handle;
return (code);
}
if (code != 0) {
return (PAM_SYSTEM_ERR);
}
if (debug)
"PAM-KRB5 (acct): fetch_princ_entry: pwlen=0");
return (PAM_AUTH_ERR);
}
(void) strlcpy(admin_realm,
sizeof (admin_realm));
"PAM-KRB5 (acct): unable to get host based "
"service name for realm '%s'",
return (PAM_SYSTEM_ERR);
}
if (code != 0) {
if (debug)
"PAM-KRB5 (acct): fetch_princ_entry: "
"init_with_pw failed: code = %d", code);
return ((code == KADM5_BAD_PASSWORD) ?
}
if (debug)
"PAM-KRB5 (acct): fetch_princ_entry: "
"non-RPCSEC_GSS chpw server, can't get "
"princ entry");
(void) kadm5_destroy(server_handle);
return (PAM_SYSTEM_ERR);
}
if (code != 0) {
(void) kadm5_destroy(server_handle);
return ((code == KADM5_UNK_PRINC) ?
}
(void) kadm5_destroy(server_handle);
return (PAM_SUCCESS);
}
/*
* exp_warn
*
* Warn the user if their pw is set to expire.
*
* We first check to see if the KDC had set any account or password
* expiration information in the key expiration field. If this was
* not set then we must assume that the KDC could be broken and revert
* determine the difference between broken KDCs that do not send key-exp
* vs. principals that do not have an expiration policy. The up-shot
* is that pam_krb5 will probably not be stacked for acct mgmt if the
* environment does not have an exp policy, avoiding the second exchange
* using the kadm protocol.
*/
static int
char *user,
int debug)
{
int err;
if (debug)
"PAM-KRB5 (acct): exp_warn start: user = '%s'",
goto exit;
}
/*
* If we error out from krb5_init_secure_context, then just set error
* code, check to see about debug message and exit out of routine as the
* context could not possibly have been setup.
*/
if (debug)
"krb5_init_secure_context failed: code=%d",
code);
goto exit;
}
if (debug)
"PAM-KRB5 (acct): krb5_timeofday failed: code=%d",
code);
goto out;
}
if (kmd->expiration != 0) {
} else {
!= PAM_SUCCESS) {
if (debug)
"PAM-KRB5 (acct): exp_warn: fetch_pr failed %d",
err);
goto out;
}
else
}
if (debug)
"PAM-KRB5 (acct): exp_warn: "
now,
expiration > 0
: 0);
/* warn user if principal's pw is set to expire */
if (expiration > 0) {
if (days <= 0)
sizeof (messages[0]),
"within 24 hours.\n"));
else if (days == 1)
sizeof (messages[0]),
"in 1 day.\n"));
else
sizeof (messages[0]),
"%d days.\n"),
(int)days);
}
/* things went smooth */
err = PAM_SUCCESS;
out:
}
exit:
if (debug)
"PAM-KRB5 (acct): exp_warn end: err = %d", err);
return (err);
}
/*
* pam_krb5 acct_mgmt
*
* we do
* - check if pw expired (flag set in auth)
* - warn user if pw is set to expire
*
* notes
* - we require the auth module to have already run (sets module data)
* - we don't worry about an expired princ cuz if that's the case,
* auth would have failed
*/
int
int flags,
int argc,
const char **argv)
{
int err;
int i;
for (i = 0; i < argc; i++) {
debug = 1;
nowarn = 1;
} else {
"PAM-KRB5 (acct): illegal option %s",
argv[i]);
}
}
if (debug)
"PAM-KRB5 (acct): debug=%d, nowarn=%d",
/*
* If the repository is not ours,
* return PAM_IGNORE.
*/
if (debug)
"PAM-KRB5 (acct): wrong"
"repository found (%s), returning "
return (PAM_IGNORE);
}
}
/* get user name */
goto out;
}
/* get pam_krb5_migrate specific data */
(const void **)&userdata);
if (err != PAM_SUCCESS) {
if (debug)
"no module data for KRB5_AUTOMIGRATE_DATA");
} else {
/*
* We try and reauthenticate, since this user has a
* newly created krb5 principal via the pam_krb5_migrate
* auth module. That way, this new user will have fresh
* creds (assuming pam_sm_authenticate() succeeds).
*/
(const char **)argv);
else
if (debug)
"PAM-KRB5 (acct): PAM_USER %s"
"does not match user %s from pam_get_data()",
}
/* get krb5 module data */
!= PAM_SUCCESS) {
if (err == PAM_NO_MODULE_DATA) {
/*
* pam_auth never called (possible config
* error; no pam_krb5 auth entry in pam.conf),
*/
if (debug) {
"PAM-KRB5 (acct): no module data");
}
err = PAM_IGNORE;
goto out;
} else {
"PAM-KRB5 (acct): get module"
" data failed: err=%d",
err);
}
goto out;
}
/*
* auth mod set status to ignore, most likely cuz root key is
* in keytab, so skip other checks and return ignore
*/
if (debug)
"PAM-KRB5 (acct): kmd auth_status is IGNORE");
err = PAM_IGNORE;
goto out;
}
/*
* If there is no Kerberos related user and there is authentication
* data, this means that while the user has successfully passed
* authentication, Kerberos is not the account authority because there
* is no valid Kerberos principal. PAM_IGNORE is returned since
* Kerberos is not authoritative for this user. Other modules in the
* account stack will need to determine the success or failure for this
* user.
*/
if (debug)
"PAM-KRB5 (acct): kmd auth_status is USER UNKNOWN");
err = PAM_IGNORE;
goto out;
}
/*
* age_status will be set to PAM_NEW_AUTHTOK_REQD in pam_krb5's
*/
if (!nowarn) {
"Your Kerberos password has expired.\n"));
}
goto out;
}
/* if we fail, let it slide, it's only a warning brah */
}
/*
* If Kerberos is treated as optional in the PAM stack, it is possible
* that there is a KRB5_DATA item and a non-Kerberos account authority.
* In that case, PAM_IGNORE is returned.
*/
out:
if (debug)
return (err);
}