/*
* 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 <k5-int.h>
#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 "krb5_repository.h"
char **, boolean_t);
extern int krb5_verifypw(char *, char *, int);
static void display_msg(pam_handle_t *, int, char *);
static void display_msgs(pam_handle_t *, int, int,
char msgs[][PAM_MAX_MSG_SIZE]);
static int krb5_changepw(pam_handle_t *, char *, char *, char *, int);
/*
* set_ccname()
*
* set KRB5CCNAME shell var
*/
static void
int login_result,
int debug)
{
int result;
if (debug)
"PAM-KRB5 (password): password: finalize"
" ccname env, login_result =%d, env ='%s'",
if (login_result == PAM_SUCCESS) {
/*
* Put ccname into the pamh so that login
* apps can pick this up when they run
* pam_getenvlist().
*/
!= PAM_SUCCESS) {
/* should not happen but... */
"PAM-KRB5 (password):"
" pam_putenv failed: result: %d",
result);
goto cleanupccname;
}
} else {
/* for lack of a Solaris unputenv() */
}
}
}
/*
* get_set_creds()
*
* do a krb5 login to get and set krb5 creds (needed after a pw change
* on pw expire on login)
*/
static void
char *user,
char *newpass,
int debug)
{
int login_result;
return;
/*
*
* pwchange verified user sufficiently, so don't request strict
* tgt verification (will cause rcache perm issues possibly anyways)
*/
if (debug)
"PAM-KRB5 (password): get_set_creds: login_result= %d",
/*
* the krb5 login should not fail, but if so,
* warn the user they have to kinit(1)
*/
if (login_result != PAM_SUCCESS) {
"Warning: "
"Could not cache Kerberos"
" credentials, please run "
"kinit(1) or re-login\n"));
}
}
/*
* This is the PAM Kerberos Password Change module
*
*/
int
int flags,
int argc,
const char **argv)
{
char *user;
int i;
int debug = 0;
for (i = 0; i < argc; i++) {
debug = 1;
else
"PAM-KRB5 (password): illegal option %s",
argv[i]);
}
if (debug)
"PAM-KRB5 (password): start: flags = %x",
flags);
if (debug)
"PAM-KRB5 (auth): wrong"
"repository found (%s), returning "
return (PAM_IGNORE);
}
}
if (flags & PAM_PRELIM_CHECK) {
/* Nothing to do here */
if (debug)
"PAM-KRB5 (password): prelim check");
return (PAM_IGNORE);
}
/* make sure PAM framework is telling us to update passwords */
if (!(flags & PAM_UPDATE_AUTHTOK)) {
"PAM-KRB5 (password): bad flags: %d",
flags);
return (PAM_SYSTEM_ERR);
}
!= PAM_SUCCESS) {
if (debug)
"PAM-KRB5 (password): get mod data failed %d",
err);
}
if (flags & PAM_CHANGE_EXPIRED_AUTHTOK) {
/* let's make sure we know the krb5 pw has expired */
if (debug)
"PAM-KRB5 (password): kmd age status %d",
return (PAM_IGNORE);
}
"PAM-KRB5 (password): username is empty");
return (PAM_USER_UNKNOWN);
}
"PAM-KRB5 (password): can't get uid for %s", user);
return (PAM_USER_UNKNOWN);
}
/*
* if root key exists in the keytab, it's a random key so no
* need to prompt for pw and we just return IGNORE
*/
if (debug)
"PAM-KRB5 (password): "
"key for '%s' in keytab, returning IGNORE", user);
result = PAM_IGNORE;
goto out;
}
/*
* If the preauth type done didn't use a passwd just ignore the error.
*/
return (PAM_IGNORE);
else
return (PAM_SYSTEM_ERR);
return (PAM_IGNORE);
else
return (PAM_SYSTEM_ERR);
if (debug)
"PAM-KRB5 (password): verifypw %d", result);
/*
* If it's a bad password or general failure, we are done.
*/
if (result != 0) {
/*
* if the preauth type done didn't use a passwd just ignore the
* error.
*/
return (PAM_IGNORE);
if (result == 2)
"Old Kerberos password incorrect\n"));
return (PAM_AUTHTOK_ERR);
}
/*
* If the old password verifies try to change it regardless of the
* preauth type and do not ignore the error.
*/
if (result == PAM_SUCCESS) {
"Kerberos password successfully changed\n"));
}
out:
if (debug)
"PAM-KRB5 (password): out: returns %d",
result);
return (result);
}
int
char *princ_str,
char *old_password,
int debug)
{
char **cpw_services;
void *server_handle;
return (6);
}
2*MAXHOSTNAMELEN)) != 0) {
return (code);
}
/* Need to get a krb5_principal struct */
if (code != 0)
return (6);
if (strlen(old_password) == 0) {
return (5);
}
(void) strlcpy(admin_realm,
sizeof (admin_realm));
"PAM-KRB5 (password): unable to get host based "
"service name for realm %s\n",
return (3);
}
if (code != 0) {
if (debug)
"PAM-KRB5: krb5_verifypw: init_with_pw"
}
(void) kadm5_destroy(server_handle);
return (0);
}
/*
* Function: krb5_changepw
*
* Purpose: Initialize and call lower level routines to change a password
*
* Arguments:
*
* princ_str principal name to use, optional
* old_password old password
* new_password new password
*
* Returns:
* exit status of PAM_SUCCESS for success
* else returns PAM failure
*
* Requires:
* Passwords cannot be more than 255 characters long.
*
* Modifies:
*
* Changes the principal's password.
*
*/
static int
char *princ_str,
char *old_password,
char *new_password,
int debug)
{
char **cpw_services;
void *server_handle;
if (krb5_init_secure_context(&context) != 0)
return (PAM_SYSTEM_ERR);
2*MAXHOSTNAMELEN)) != 0) {
return (code);
}
/* Need to get a krb5_principal struct */
if (code != 0)
return (PAM_SYSTEM_ERR);
if (strlen(old_password) == 0) {
return (PAM_AUTHTOK_ERR);
}
"PAM-KRB5 (password):unable to get host based "
"service name for realm %s\n",
return (PAM_SYSTEM_ERR);
}
if (code != 0) {
if (debug)
"PAM-KRB5 (password): changepw: "
return ((code == KADM5_BAD_PASSWORD) ?
}
NULL /* don't need pw back */,
sizeof (msg_ret));
if (code) {
"Kerberos password not changed: "));
}
(void) kadm5_destroy(server_handle);
if (debug)
"PAM-KRB5 (password): changepw: end %d", code);
if (code != 0)
return (PAM_AUTHTOK_ERR);
return (PAM_SUCCESS);
}
static void
{
}
static void
{
}