xref: /illumos-gate/usr/src/lib/pam_modules/krb5/krb5_password.c (revision cbea7aca3fd7787405cbdbd93752998f03dfc25f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50be37caaSsemery  * Common Development and Distribution License (the "License").
60be37caaSsemery  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2270f41fc1SWill Fiveash  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*cbea7acaSDominik Hassler  *
25*cbea7acaSDominik Hassler  * Copyright 2023 OmniOS Community Edition (OmniOSce) Association.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <kadm5/admin.h>
297c478bd9Sstevel@tonic-gate #include <krb5.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
327c478bd9Sstevel@tonic-gate #include <security/pam_modules.h>
337c478bd9Sstevel@tonic-gate #include <security/pam_impl.h>
347c478bd9Sstevel@tonic-gate #include <syslog.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <stdio.h>
377c478bd9Sstevel@tonic-gate #include <stdlib.h>
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <pwd.h>
407c478bd9Sstevel@tonic-gate #include <libintl.h>
417c478bd9Sstevel@tonic-gate #include <netdb.h>
427c478bd9Sstevel@tonic-gate #include "utils.h"
437c478bd9Sstevel@tonic-gate #include "krb5_repository.h"
447c478bd9Sstevel@tonic-gate 
45*cbea7acaSDominik Hassler extern int attempt_krb5_auth(pam_handle_t *, krb5_module_data_t *, const char *,
4670f41fc1SWill Fiveash     char **, boolean_t);
47*cbea7acaSDominik Hassler extern int krb5_verifypw(const char *, char *, int);
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate static void display_msg(pam_handle_t *, int, char *);
507c478bd9Sstevel@tonic-gate static void display_msgs(pam_handle_t *, int, int,
517c478bd9Sstevel@tonic-gate     char msgs[][PAM_MAX_MSG_SIZE]);
52*cbea7acaSDominik Hassler static int krb5_changepw(pam_handle_t *, const char *, char *, char *, int);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * set_ccname()
567c478bd9Sstevel@tonic-gate  *
577c478bd9Sstevel@tonic-gate  * set KRB5CCNAME shell var
587c478bd9Sstevel@tonic-gate  */
597c478bd9Sstevel@tonic-gate static void
set_ccname(pam_handle_t * pamh,krb5_module_data_t * kmd,int login_result,int debug)607c478bd9Sstevel@tonic-gate set_ccname(
617c478bd9Sstevel@tonic-gate 	pam_handle_t *pamh,
627c478bd9Sstevel@tonic-gate 	krb5_module_data_t *kmd,
637c478bd9Sstevel@tonic-gate 	int login_result,
647c478bd9Sstevel@tonic-gate 	int debug)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 	int result;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	if (debug)
693bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
707c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (password): password: finalize"
717c478bd9Sstevel@tonic-gate 		    " ccname env, login_result =%d, env ='%s'",
727c478bd9Sstevel@tonic-gate 		    login_result, kmd->env ? kmd->env : "<null>");
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	if (kmd->env) {
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 		if (login_result == PAM_SUCCESS) {
777c478bd9Sstevel@tonic-gate 				/*
787c478bd9Sstevel@tonic-gate 				 * Put ccname into the pamh so that login
797c478bd9Sstevel@tonic-gate 				 * apps can pick this up when they run
807c478bd9Sstevel@tonic-gate 				 * pam_getenvlist().
817c478bd9Sstevel@tonic-gate 				 */
827c478bd9Sstevel@tonic-gate 			if ((result = pam_putenv(pamh, kmd->env))
837c478bd9Sstevel@tonic-gate 			    != PAM_SUCCESS) {
847c478bd9Sstevel@tonic-gate 				/* should not happen but... */
853bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_ERR,
867c478bd9Sstevel@tonic-gate 				    "PAM-KRB5 (password):"
873bfb48feSsemery 				    " pam_putenv failed: result: %d",
887c478bd9Sstevel@tonic-gate 				    result);
897c478bd9Sstevel@tonic-gate 				goto cleanupccname;
907c478bd9Sstevel@tonic-gate 			}
917c478bd9Sstevel@tonic-gate 		} else {
927c478bd9Sstevel@tonic-gate 		cleanupccname:
937c478bd9Sstevel@tonic-gate 				/* for lack of a Solaris unputenv() */
947c478bd9Sstevel@tonic-gate 			krb5_unsetenv(KRB5_ENV_CCNAME);
957c478bd9Sstevel@tonic-gate 			free(kmd->env);
967c478bd9Sstevel@tonic-gate 			kmd->env = NULL;
977c478bd9Sstevel@tonic-gate 		}
987c478bd9Sstevel@tonic-gate 	}
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * get_set_creds()
1037c478bd9Sstevel@tonic-gate  *
1047c478bd9Sstevel@tonic-gate  * do a krb5 login to get and set krb5 creds (needed after a pw change
1057c478bd9Sstevel@tonic-gate  * on pw expire on login)
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate static void
get_set_creds(pam_handle_t * pamh,krb5_module_data_t * kmd,const char * user,char * newpass,int debug)1087c478bd9Sstevel@tonic-gate get_set_creds(
1097c478bd9Sstevel@tonic-gate 	pam_handle_t *pamh,
1107c478bd9Sstevel@tonic-gate 	krb5_module_data_t *kmd,
111*cbea7acaSDominik Hassler 	const char *user,
1127c478bd9Sstevel@tonic-gate 	char *newpass,
1137c478bd9Sstevel@tonic-gate 	int debug)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate 	int login_result;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	if (!kmd || kmd->age_status != PAM_NEW_AUTHTOK_REQD)
1187c478bd9Sstevel@tonic-gate 		return;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/*
1217c478bd9Sstevel@tonic-gate 	 * if pw has expired, get/set krb5 creds ala auth mod
1227c478bd9Sstevel@tonic-gate 	 *
1237c478bd9Sstevel@tonic-gate 	 * pwchange verified user sufficiently, so don't request strict
1247c478bd9Sstevel@tonic-gate 	 * tgt verification (will cause rcache perm issues possibly anyways)
1257c478bd9Sstevel@tonic-gate 	 */
12670f41fc1SWill Fiveash 	login_result = attempt_krb5_auth(pamh, kmd, user, &newpass, 0);
1277c478bd9Sstevel@tonic-gate 	if (debug)
1283bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
1297c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (password): get_set_creds: login_result= %d",
1307c478bd9Sstevel@tonic-gate 		    login_result);
1317c478bd9Sstevel@tonic-gate 	/*
1327c478bd9Sstevel@tonic-gate 	 * the krb5 login should not fail, but if so,
1337c478bd9Sstevel@tonic-gate 	 * warn the user they have to kinit(1)
1347c478bd9Sstevel@tonic-gate 	 */
1357c478bd9Sstevel@tonic-gate 	if (login_result != PAM_SUCCESS) {
1367c478bd9Sstevel@tonic-gate 		display_msg(pamh, PAM_TEXT_INFO,
1377c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN,
1387c478bd9Sstevel@tonic-gate 		    "Warning: "
1397c478bd9Sstevel@tonic-gate 		    "Could not cache Kerberos"
1407c478bd9Sstevel@tonic-gate 		    " credentials, please run "
1417c478bd9Sstevel@tonic-gate 		    "kinit(1) or re-login\n"));
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 	set_ccname(pamh, kmd, login_result, debug);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate  * This is the PAM Kerberos Password Change module
1477c478bd9Sstevel@tonic-gate  *
1487c478bd9Sstevel@tonic-gate  */
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char ** argv)151*cbea7acaSDominik Hassler pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 
154*cbea7acaSDominik Hassler 	const char *user;
1552278144aSsemery 	int err, result = PAM_AUTHTOK_ERR;
1562278144aSsemery 	char *newpass = NULL;
1577c478bd9Sstevel@tonic-gate 	char *oldpass = NULL;
1587c478bd9Sstevel@tonic-gate 	int i;
1597c478bd9Sstevel@tonic-gate 	int debug = 0;
1607c478bd9Sstevel@tonic-gate 	uid_t pw_uid;
1617c478bd9Sstevel@tonic-gate 	krb5_module_data_t *kmd = NULL;
162*cbea7acaSDominik Hassler 	const pam_repository_t *rep_data = NULL;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
1657c478bd9Sstevel@tonic-gate 		if (strcmp(argv[i], "debug") == 0)
1667c478bd9Sstevel@tonic-gate 			debug = 1;
1677c478bd9Sstevel@tonic-gate 		else
1683bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_ERR,
1693bfb48feSsemery 			    "PAM-KRB5 (password): illegal option %s",
1707c478bd9Sstevel@tonic-gate 			    argv[i]);
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	if (debug)
1743bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
1757c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (password): start: flags = %x",
1767c478bd9Sstevel@tonic-gate 		    flags);
1777c478bd9Sstevel@tonic-gate 
178*cbea7acaSDominik Hassler 	(void) pam_get_item(pamh, PAM_REPOSITORY, (const void **)&rep_data);
1792278144aSsemery 
1807c478bd9Sstevel@tonic-gate 	if (rep_data != NULL) {
1817c478bd9Sstevel@tonic-gate 		if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
1827c478bd9Sstevel@tonic-gate 			if (debug)
1833bfb48feSsemery 				__pam_log(LOG_AUTH | LOG_DEBUG,
1843bfb48feSsemery 				    "PAM-KRB5 (auth): wrong"
1857c478bd9Sstevel@tonic-gate 				    "repository found (%s), returning "
1867c478bd9Sstevel@tonic-gate 				    "PAM_IGNORE", rep_data->type);
1877c478bd9Sstevel@tonic-gate 			return (PAM_IGNORE);
1887c478bd9Sstevel@tonic-gate 		}
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	if (flags & PAM_PRELIM_CHECK) {
1927c478bd9Sstevel@tonic-gate 		/* Nothing to do here */
1937c478bd9Sstevel@tonic-gate 		if (debug)
1943bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
1957c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (password): prelim check");
1967c478bd9Sstevel@tonic-gate 		return (PAM_IGNORE);
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	/* make sure PAM framework is telling us to update passwords */
2007c478bd9Sstevel@tonic-gate 	if (!(flags & PAM_UPDATE_AUTHTOK)) {
2013bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
2023bfb48feSsemery 		    "PAM-KRB5 (password): bad flags: %d",
2037c478bd9Sstevel@tonic-gate 		    flags);
2047c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
2057c478bd9Sstevel@tonic-gate 	}
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	if ((err = pam_get_data(pamh, KRB5_DATA, (const void **)&kmd))
2097c478bd9Sstevel@tonic-gate 	    != PAM_SUCCESS) {
2107c478bd9Sstevel@tonic-gate 		if (debug)
2113bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
2127c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (password): get mod data failed %d",
2137c478bd9Sstevel@tonic-gate 			    err);
2147c478bd9Sstevel@tonic-gate 		kmd = NULL;
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	if (flags & PAM_CHANGE_EXPIRED_AUTHTOK) {
2187c478bd9Sstevel@tonic-gate 		/* let's make sure we know the krb5 pw has expired */
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		if (debug)
2213bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
2227c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (password): kmd age status %d",
2237c478bd9Sstevel@tonic-gate 			    kmd ? kmd->age_status : -99);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		if (!kmd || kmd->age_status != PAM_NEW_AUTHTOK_REQD)
2267c478bd9Sstevel@tonic-gate 			return (PAM_IGNORE);
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 
229*cbea7acaSDominik Hassler 	(void) pam_get_item(pamh, PAM_USER, (const void **)&user);
2307c478bd9Sstevel@tonic-gate 
2313bfb48feSsemery 	if (user == NULL || *user == '\0') {
2323bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
2333bfb48feSsemery 		    "PAM-KRB5 (password): username is empty");
2342278144aSsemery 		return (PAM_USER_UNKNOWN);
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	if (!get_pw_uid(user, &pw_uid)) {
2383bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
2392278144aSsemery 		    "PAM-KRB5 (password): can't get uid for %s", user);
2402278144aSsemery 		return (PAM_USER_UNKNOWN);
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	/*
2447c478bd9Sstevel@tonic-gate 	 * if root key exists in the keytab, it's a random key so no
2457c478bd9Sstevel@tonic-gate 	 * need to prompt for pw and we just return IGNORE
2467c478bd9Sstevel@tonic-gate 	 */
2477c478bd9Sstevel@tonic-gate 	if ((strcmp(user, ROOT_UNAME) == 0) &&
2487c478bd9Sstevel@tonic-gate 	    key_in_keytab(user, debug)) {
2497c478bd9Sstevel@tonic-gate 		if (debug)
2503bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
2517c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (password): "
2527c478bd9Sstevel@tonic-gate 			    "key for '%s' in keytab, returning IGNORE", user);
2537c478bd9Sstevel@tonic-gate 		result = PAM_IGNORE;
2547c478bd9Sstevel@tonic-gate 		goto out;
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
257*cbea7acaSDominik Hassler 	(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **)&newpass);
2587c478bd9Sstevel@tonic-gate 
25970f41fc1SWill Fiveash 	/*
26070f41fc1SWill Fiveash 	 * If the preauth type done didn't use a passwd just ignore the error.
26170f41fc1SWill Fiveash 	 */
2622278144aSsemery 	if (newpass == NULL)
26370f41fc1SWill Fiveash 		if (kmd && kmd->preauth_type == KRB_PKINIT)
26470f41fc1SWill Fiveash 			return (PAM_IGNORE);
26570f41fc1SWill Fiveash 		else
2662278144aSsemery 			return (PAM_SYSTEM_ERR);
2677c478bd9Sstevel@tonic-gate 
268*cbea7acaSDominik Hassler 	(void) pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **)&oldpass);
2697c478bd9Sstevel@tonic-gate 
2702278144aSsemery 	if (oldpass == NULL)
27170f41fc1SWill Fiveash 		if (kmd && kmd->preauth_type == KRB_PKINIT)
27270f41fc1SWill Fiveash 			return (PAM_IGNORE);
27370f41fc1SWill Fiveash 		else
2742278144aSsemery 			return (PAM_SYSTEM_ERR);
2752278144aSsemery 
2762278144aSsemery 	result = krb5_verifypw(user, oldpass, debug);
2777c478bd9Sstevel@tonic-gate 	if (debug)
2783bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
2793bfb48feSsemery 		    "PAM-KRB5 (password): verifypw %d", result);
2802278144aSsemery 
2817c478bd9Sstevel@tonic-gate 	/*
2822278144aSsemery 	 * If it's a bad password or general failure, we are done.
2837c478bd9Sstevel@tonic-gate 	 */
2842278144aSsemery 	if (result != 0) {
28570f41fc1SWill Fiveash 		/*
28670f41fc1SWill Fiveash 		 * if the preauth type done didn't use a passwd just ignore the
28770f41fc1SWill Fiveash 		 * error.
28870f41fc1SWill Fiveash 		 */
28970f41fc1SWill Fiveash 		if (kmd && kmd->preauth_type == KRB_PKINIT)
29070f41fc1SWill Fiveash 			return (PAM_IGNORE);
29170f41fc1SWill Fiveash 
2922278144aSsemery 		if (result == 2)
2932278144aSsemery 			display_msg(pamh, PAM_ERROR_MSG, dgettext(TEXT_DOMAIN,
2942278144aSsemery 			    "Old Kerberos password incorrect\n"));
2957c478bd9Sstevel@tonic-gate 		return (PAM_AUTHTOK_ERR);
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 
29870f41fc1SWill Fiveash 	/*
29970f41fc1SWill Fiveash 	 * If the old password verifies try to change it regardless of the
30070f41fc1SWill Fiveash 	 * preauth type and do not ignore the error.
30170f41fc1SWill Fiveash 	 */
3027c478bd9Sstevel@tonic-gate 	result = krb5_changepw(pamh, user, oldpass, newpass, debug);
3037c478bd9Sstevel@tonic-gate 	if (result == PAM_SUCCESS) {
3042278144aSsemery 		display_msg(pamh, PAM_TEXT_INFO, dgettext(TEXT_DOMAIN,
3052278144aSsemery 		    "Kerberos password successfully changed\n"));
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 		get_set_creds(pamh, kmd, user, newpass, debug);
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate out:
3117c478bd9Sstevel@tonic-gate 	if (debug)
3123bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
3133bfb48feSsemery 		    "PAM-KRB5 (password): out: returns %d",
3147c478bd9Sstevel@tonic-gate 		    result);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	return (result);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate int
krb5_verifypw(const char * princ_str,char * old_password,int debug)3207c478bd9Sstevel@tonic-gate krb5_verifypw(
321*cbea7acaSDominik Hassler 	const char 	*princ_str,
3227c478bd9Sstevel@tonic-gate 	char	*old_password,
3237c478bd9Sstevel@tonic-gate 	int debug)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate 	kadm5_ret_t		code;
3267c478bd9Sstevel@tonic-gate 	krb5_principal 		princ = 0;
3277c478bd9Sstevel@tonic-gate 	char 			admin_realm[1024];
3287c478bd9Sstevel@tonic-gate 	char			kprinc[2*MAXHOSTNAMELEN];
3297c478bd9Sstevel@tonic-gate 	char			*cpw_service;
3307c478bd9Sstevel@tonic-gate 	void 			*server_handle;
3317c478bd9Sstevel@tonic-gate 	krb5_context		context;
3327c478bd9Sstevel@tonic-gate 	kadm5_config_params	params;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	(void) memset((char *)&params, 0, sizeof (params));
3357c478bd9Sstevel@tonic-gate 
3368ce3ffdfSPeter Shoults 	if (code = krb5_init_secure_context(&context)) {
3377c478bd9Sstevel@tonic-gate 		return (6);
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
340*cbea7acaSDominik Hassler 	if ((code = get_kmd_kuser(context, princ_str, kprinc,
3417c478bd9Sstevel@tonic-gate 	    2*MAXHOSTNAMELEN)) != 0) {
3427c478bd9Sstevel@tonic-gate 		return (code);
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	/* Need to get a krb5_principal struct */
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	code = krb5_parse_name(context, kprinc, &princ);
3487c478bd9Sstevel@tonic-gate 
3492278144aSsemery 	if (code != 0)
3502278144aSsemery 		return (6);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	if (strlen(old_password) == 0) {
3537c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, princ);
3547c478bd9Sstevel@tonic-gate 		return (5);
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	(void) strlcpy(admin_realm,
3587c478bd9Sstevel@tonic-gate 	    krb5_princ_realm(context, princ)->data,
3597c478bd9Sstevel@tonic-gate 	    sizeof (admin_realm));
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	params.mask |= KADM5_CONFIG_REALM;
3627c478bd9Sstevel@tonic-gate 	params.realm = admin_realm;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) {
3663bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
3677c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (password): unable to get host based "
3683bfb48feSsemery 		    "service name for realm %s\n",
3697c478bd9Sstevel@tonic-gate 		    admin_realm);
3702278144aSsemery 		krb5_free_principal(context, princ);
3717c478bd9Sstevel@tonic-gate 		return (3);
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	code = kadm5_init_with_password(kprinc, old_password, cpw_service,
3757c478bd9Sstevel@tonic-gate 	    &params, KADM5_STRUCT_VERSION,
37654925bf6Swillf 	    KADM5_API_VERSION_2, NULL,
37754925bf6Swillf 	    &server_handle);
3787c478bd9Sstevel@tonic-gate 	if (code != 0) {
3797c478bd9Sstevel@tonic-gate 		if (debug)
3803bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
3817c478bd9Sstevel@tonic-gate 			    "PAM-KRB5: krb5_verifypw: init_with_pw"
3827c478bd9Sstevel@tonic-gate 			    " failed: (%s)", error_message(code));
3837c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, princ);
3847c478bd9Sstevel@tonic-gate 		return ((code == KADM5_BAD_PASSWORD) ? 2 : 3);
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	krb5_free_principal(context, princ);
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	(void) kadm5_destroy(server_handle);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	return (0);
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate  * Function: krb5_changepw
3967c478bd9Sstevel@tonic-gate  *
3977c478bd9Sstevel@tonic-gate  * Purpose: Initialize and call lower level routines to change a password
3987c478bd9Sstevel@tonic-gate  *
3997c478bd9Sstevel@tonic-gate  * Arguments:
4007c478bd9Sstevel@tonic-gate  *
4017c478bd9Sstevel@tonic-gate  *	princ_str	principal name to use, optional
4027c478bd9Sstevel@tonic-gate  *	old_password 	old password
4037c478bd9Sstevel@tonic-gate  *	new_password  	new password
4047c478bd9Sstevel@tonic-gate  *
4057c478bd9Sstevel@tonic-gate  * Returns:
4067c478bd9Sstevel@tonic-gate  *                      exit status of PAM_SUCCESS for success
4072278144aSsemery  *			else returns PAM failure
4087c478bd9Sstevel@tonic-gate  *
4097c478bd9Sstevel@tonic-gate  * Requires:
4107c478bd9Sstevel@tonic-gate  *	Passwords cannot be more than 255 characters long.
4117c478bd9Sstevel@tonic-gate  *
4127c478bd9Sstevel@tonic-gate  * Modifies:
4137c478bd9Sstevel@tonic-gate  *
4147c478bd9Sstevel@tonic-gate  * Changes the principal's password.
4157c478bd9Sstevel@tonic-gate  *
4167c478bd9Sstevel@tonic-gate  */
4177c478bd9Sstevel@tonic-gate static int
krb5_changepw(pam_handle_t * pamh,const char * princ_str,char * old_password,char * new_password,int debug)4187c478bd9Sstevel@tonic-gate krb5_changepw(
4197c478bd9Sstevel@tonic-gate 	pam_handle_t *pamh,
420*cbea7acaSDominik Hassler 	const char *princ_str,
4217c478bd9Sstevel@tonic-gate 	char *old_password,
4227c478bd9Sstevel@tonic-gate 	char *new_password,
4237c478bd9Sstevel@tonic-gate 	int debug)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate 	kadm5_ret_t		code;
4267c478bd9Sstevel@tonic-gate 	krb5_principal 		princ = 0;
4277c478bd9Sstevel@tonic-gate 	char 			msg_ret[1024], admin_realm[1024];
4287c478bd9Sstevel@tonic-gate 	char			kprinc[2*MAXHOSTNAMELEN];
4297c478bd9Sstevel@tonic-gate 	char			*cpw_service;
4307c478bd9Sstevel@tonic-gate 	void 			*server_handle;
4317c478bd9Sstevel@tonic-gate 	krb5_context		context;
4327c478bd9Sstevel@tonic-gate 	kadm5_config_params	params;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	(void) memset((char *)&params, 0, sizeof (params));
4357c478bd9Sstevel@tonic-gate 
4368ce3ffdfSPeter Shoults 	if (krb5_init_secure_context(&context) != 0)
4372278144aSsemery 		return (PAM_SYSTEM_ERR);
4387c478bd9Sstevel@tonic-gate 
439*cbea7acaSDominik Hassler 	if ((code = get_kmd_kuser(context, princ_str, kprinc,
4407c478bd9Sstevel@tonic-gate 	    2*MAXHOSTNAMELEN)) != 0) {
4417c478bd9Sstevel@tonic-gate 		return (code);
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	/* Need to get a krb5_principal struct */
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	code = krb5_parse_name(context, kprinc, &princ);
4472278144aSsemery 	if (code != 0)
4482278144aSsemery 		return (PAM_SYSTEM_ERR);
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	if (strlen(old_password) == 0) {
4517c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, princ);
4522278144aSsemery 		return (PAM_AUTHTOK_ERR);
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	(void) snprintf(admin_realm, sizeof (admin_realm), "%s",
4567c478bd9Sstevel@tonic-gate 	    krb5_princ_realm(context, princ)->data);
4577c478bd9Sstevel@tonic-gate 	params.mask |= KADM5_CONFIG_REALM;
4587c478bd9Sstevel@tonic-gate 	params.realm = admin_realm;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) {
4623bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_ERR,
4637c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (password):unable to get host based "
4643bfb48feSsemery 		    "service name for realm %s\n",
4657c478bd9Sstevel@tonic-gate 		    admin_realm);
4662278144aSsemery 		return (PAM_SYSTEM_ERR);
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	code = kadm5_init_with_password(kprinc, old_password, cpw_service,
4707c478bd9Sstevel@tonic-gate 	    &params, KADM5_STRUCT_VERSION,
47154925bf6Swillf 	    KADM5_API_VERSION_2, NULL,
47254925bf6Swillf 	    &server_handle);
4737c478bd9Sstevel@tonic-gate 	free(cpw_service);
4747c478bd9Sstevel@tonic-gate 	if (code != 0) {
4757c478bd9Sstevel@tonic-gate 		if (debug)
4763bfb48feSsemery 			__pam_log(LOG_AUTH | LOG_DEBUG,
4777c478bd9Sstevel@tonic-gate 			    "PAM-KRB5 (password): changepw: "
4787c478bd9Sstevel@tonic-gate 			    "init_with_pw failed:  (%s)", error_message(code));
4797c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, princ);
4802278144aSsemery 		return ((code == KADM5_BAD_PASSWORD) ?
4812278144aSsemery 		    PAM_AUTHTOK_ERR : PAM_SYSTEM_ERR);
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	code = kadm5_chpass_principal_util(server_handle, princ,
4857c478bd9Sstevel@tonic-gate 	    new_password,
4867c478bd9Sstevel@tonic-gate 	    NULL /* don't need pw back */,
4877c478bd9Sstevel@tonic-gate 	    msg_ret,
4887c478bd9Sstevel@tonic-gate 	    sizeof (msg_ret));
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if (code) {
4917c478bd9Sstevel@tonic-gate 		char msgs[2][PAM_MAX_MSG_SIZE];
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 		(void) snprintf(msgs[0], PAM_MAX_MSG_SIZE, "%s",
4947c478bd9Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN,
4957c478bd9Sstevel@tonic-gate 		    "Kerberos password not changed: "));
4967c478bd9Sstevel@tonic-gate 		(void) snprintf(msgs[1], PAM_MAX_MSG_SIZE, "%s", msg_ret);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 		display_msgs(pamh, PAM_ERROR_MSG, 2, msgs);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	krb5_free_principal(context, princ);
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	(void) kadm5_destroy(server_handle);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	if (debug)
5063bfb48feSsemery 		__pam_log(LOG_AUTH | LOG_DEBUG,
5077c478bd9Sstevel@tonic-gate 		    "PAM-KRB5 (password): changepw: end %d", code);
5087c478bd9Sstevel@tonic-gate 
5092278144aSsemery 	if (code != 0)
5102278144aSsemery 		return (PAM_AUTHTOK_ERR);
5112278144aSsemery 
5127c478bd9Sstevel@tonic-gate 	return (PAM_SUCCESS);
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate static void
display_msgs(pam_handle_t * pamh,int msg_style,int nmsg,char msgs[][PAM_MAX_MSG_SIZE])5167c478bd9Sstevel@tonic-gate display_msgs(pam_handle_t *pamh,
5177c478bd9Sstevel@tonic-gate 	int msg_style, int nmsg, char msgs[][PAM_MAX_MSG_SIZE])
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	(void) __pam_display_msg(pamh, msg_style, nmsg, msgs, NULL);
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate static void
display_msg(pam_handle_t * pamh,int msg_style,char * msg)5247c478bd9Sstevel@tonic-gate display_msg(pam_handle_t *pamh, int msg_style, char *msg)
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate 	char pam_msg[1][PAM_MAX_MSG_SIZE];
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	(void) snprintf(pam_msg[0], PAM_MAX_MSG_SIZE, "%s", msg);
5297c478bd9Sstevel@tonic-gate 	display_msgs(pamh, msg_style, 1, pam_msg);
5307c478bd9Sstevel@tonic-gate }
531