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 *)¶ms, 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 ¶ms, 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 *)¶ms, 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 ¶ms, 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