10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52554Ssemery * Common Development and Distribution License (the "License").
62554Ssemery * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
2211778SWill.Fiveash@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <kadm5/admin.h>
270Sstevel@tonic-gate #include <krb5.h>
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <security/pam_appl.h>
300Sstevel@tonic-gate #include <security/pam_modules.h>
310Sstevel@tonic-gate #include <security/pam_impl.h>
320Sstevel@tonic-gate #include <syslog.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <pwd.h>
380Sstevel@tonic-gate #include <libintl.h>
390Sstevel@tonic-gate #include <netdb.h>
400Sstevel@tonic-gate #include "utils.h"
410Sstevel@tonic-gate #include "krb5_repository.h"
420Sstevel@tonic-gate
4311778SWill.Fiveash@Sun.COM extern int attempt_krb5_auth(pam_handle_t *, krb5_module_data_t *, char *,
4411778SWill.Fiveash@Sun.COM char **, boolean_t);
452941Ssemery extern int krb5_verifypw(char *, char *, int);
460Sstevel@tonic-gate
470Sstevel@tonic-gate static void display_msg(pam_handle_t *, int, char *);
480Sstevel@tonic-gate static void display_msgs(pam_handle_t *, int, int,
490Sstevel@tonic-gate char msgs[][PAM_MAX_MSG_SIZE]);
500Sstevel@tonic-gate static int krb5_changepw(pam_handle_t *, char *, char *, char *, int);
510Sstevel@tonic-gate
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate * set_ccname()
540Sstevel@tonic-gate *
550Sstevel@tonic-gate * set KRB5CCNAME shell var
560Sstevel@tonic-gate */
570Sstevel@tonic-gate static void
set_ccname(pam_handle_t * pamh,krb5_module_data_t * kmd,int login_result,int debug)580Sstevel@tonic-gate set_ccname(
590Sstevel@tonic-gate pam_handle_t *pamh,
600Sstevel@tonic-gate krb5_module_data_t *kmd,
610Sstevel@tonic-gate int login_result,
620Sstevel@tonic-gate int debug)
630Sstevel@tonic-gate {
640Sstevel@tonic-gate int result;
650Sstevel@tonic-gate
660Sstevel@tonic-gate if (debug)
673391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
680Sstevel@tonic-gate "PAM-KRB5 (password): password: finalize"
690Sstevel@tonic-gate " ccname env, login_result =%d, env ='%s'",
700Sstevel@tonic-gate login_result, kmd->env ? kmd->env : "<null>");
710Sstevel@tonic-gate
720Sstevel@tonic-gate if (kmd->env) {
730Sstevel@tonic-gate
740Sstevel@tonic-gate if (login_result == PAM_SUCCESS) {
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate * Put ccname into the pamh so that login
770Sstevel@tonic-gate * apps can pick this up when they run
780Sstevel@tonic-gate * pam_getenvlist().
790Sstevel@tonic-gate */
800Sstevel@tonic-gate if ((result = pam_putenv(pamh, kmd->env))
810Sstevel@tonic-gate != PAM_SUCCESS) {
820Sstevel@tonic-gate /* should not happen but... */
833391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
84*11780SWill.Fiveash@Sun.COM "PAM-KRB5 (password):"
85*11780SWill.Fiveash@Sun.COM " pam_putenv failed: result: %d",
860Sstevel@tonic-gate result);
870Sstevel@tonic-gate goto cleanupccname;
880Sstevel@tonic-gate }
890Sstevel@tonic-gate } else {
900Sstevel@tonic-gate cleanupccname:
910Sstevel@tonic-gate /* for lack of a Solaris unputenv() */
920Sstevel@tonic-gate krb5_unsetenv(KRB5_ENV_CCNAME);
930Sstevel@tonic-gate free(kmd->env);
940Sstevel@tonic-gate kmd->env = NULL;
950Sstevel@tonic-gate }
960Sstevel@tonic-gate }
970Sstevel@tonic-gate }
980Sstevel@tonic-gate
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate * get_set_creds()
1010Sstevel@tonic-gate *
1020Sstevel@tonic-gate * do a krb5 login to get and set krb5 creds (needed after a pw change
1030Sstevel@tonic-gate * on pw expire on login)
1040Sstevel@tonic-gate */
1050Sstevel@tonic-gate static void
get_set_creds(pam_handle_t * pamh,krb5_module_data_t * kmd,char * user,char * newpass,int debug)1060Sstevel@tonic-gate get_set_creds(
1070Sstevel@tonic-gate pam_handle_t *pamh,
1080Sstevel@tonic-gate krb5_module_data_t *kmd,
1090Sstevel@tonic-gate char *user,
1100Sstevel@tonic-gate char *newpass,
1110Sstevel@tonic-gate int debug)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate int login_result;
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate if (!kmd || kmd->age_status != PAM_NEW_AUTHTOK_REQD)
1160Sstevel@tonic-gate return;
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate /*
1190Sstevel@tonic-gate * if pw has expired, get/set krb5 creds ala auth mod
1200Sstevel@tonic-gate *
1210Sstevel@tonic-gate * pwchange verified user sufficiently, so don't request strict
1220Sstevel@tonic-gate * tgt verification (will cause rcache perm issues possibly anyways)
1230Sstevel@tonic-gate */
12411778SWill.Fiveash@Sun.COM login_result = attempt_krb5_auth(pamh, kmd, user, &newpass, 0);
1250Sstevel@tonic-gate if (debug)
1263391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
1270Sstevel@tonic-gate "PAM-KRB5 (password): get_set_creds: login_result= %d",
1280Sstevel@tonic-gate login_result);
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate * the krb5 login should not fail, but if so,
1310Sstevel@tonic-gate * warn the user they have to kinit(1)
1320Sstevel@tonic-gate */
1330Sstevel@tonic-gate if (login_result != PAM_SUCCESS) {
1340Sstevel@tonic-gate display_msg(pamh, PAM_TEXT_INFO,
135*11780SWill.Fiveash@Sun.COM dgettext(TEXT_DOMAIN,
136*11780SWill.Fiveash@Sun.COM "Warning: "
137*11780SWill.Fiveash@Sun.COM "Could not cache Kerberos"
138*11780SWill.Fiveash@Sun.COM " credentials, please run "
139*11780SWill.Fiveash@Sun.COM "kinit(1) or re-login\n"));
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate set_ccname(pamh, kmd, login_result, debug);
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate /*
1440Sstevel@tonic-gate * This is the PAM Kerberos Password Change module
1450Sstevel@tonic-gate *
1460Sstevel@tonic-gate */
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char ** argv)1490Sstevel@tonic-gate pam_sm_chauthtok(
1500Sstevel@tonic-gate pam_handle_t *pamh,
1510Sstevel@tonic-gate int flags,
1520Sstevel@tonic-gate int argc,
1530Sstevel@tonic-gate const char **argv)
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate char *user;
1572941Ssemery int err, result = PAM_AUTHTOK_ERR;
1582941Ssemery char *newpass = NULL;
1590Sstevel@tonic-gate char *oldpass = NULL;
1600Sstevel@tonic-gate int i;
1610Sstevel@tonic-gate int debug = 0;
1620Sstevel@tonic-gate uid_t pw_uid;
1630Sstevel@tonic-gate krb5_module_data_t *kmd = NULL;
1640Sstevel@tonic-gate pam_repository_t *rep_data = NULL;
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate for (i = 0; i < argc; i++) {
1670Sstevel@tonic-gate if (strcmp(argv[i], "debug") == 0)
1680Sstevel@tonic-gate debug = 1;
1690Sstevel@tonic-gate else
1703391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
171*11780SWill.Fiveash@Sun.COM "PAM-KRB5 (password): illegal option %s",
1720Sstevel@tonic-gate argv[i]);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate if (debug)
1763391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
1770Sstevel@tonic-gate "PAM-KRB5 (password): start: flags = %x",
1780Sstevel@tonic-gate flags);
1790Sstevel@tonic-gate
1802941Ssemery (void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data);
1812941Ssemery
1820Sstevel@tonic-gate if (rep_data != NULL) {
1830Sstevel@tonic-gate if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
1840Sstevel@tonic-gate if (debug)
1853391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
186*11780SWill.Fiveash@Sun.COM "PAM-KRB5 (auth): wrong"
187*11780SWill.Fiveash@Sun.COM "repository found (%s), returning "
188*11780SWill.Fiveash@Sun.COM "PAM_IGNORE", rep_data->type);
1890Sstevel@tonic-gate return (PAM_IGNORE);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate if (flags & PAM_PRELIM_CHECK) {
1940Sstevel@tonic-gate /* Nothing to do here */
1950Sstevel@tonic-gate if (debug)
1963391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
1970Sstevel@tonic-gate "PAM-KRB5 (password): prelim check");
1980Sstevel@tonic-gate return (PAM_IGNORE);
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate /* make sure PAM framework is telling us to update passwords */
2020Sstevel@tonic-gate if (!(flags & PAM_UPDATE_AUTHTOK)) {
2033391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
204*11780SWill.Fiveash@Sun.COM "PAM-KRB5 (password): bad flags: %d",
205*11780SWill.Fiveash@Sun.COM flags);
2060Sstevel@tonic-gate return (PAM_SYSTEM_ERR);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate if ((err = pam_get_data(pamh, KRB5_DATA, (const void **)&kmd))
2110Sstevel@tonic-gate != PAM_SUCCESS) {
2120Sstevel@tonic-gate if (debug)
2133391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
2140Sstevel@tonic-gate "PAM-KRB5 (password): get mod data failed %d",
2150Sstevel@tonic-gate err);
2160Sstevel@tonic-gate kmd = NULL;
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate if (flags & PAM_CHANGE_EXPIRED_AUTHTOK) {
2200Sstevel@tonic-gate /* let's make sure we know the krb5 pw has expired */
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate if (debug)
2233391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
2240Sstevel@tonic-gate "PAM-KRB5 (password): kmd age status %d",
2250Sstevel@tonic-gate kmd ? kmd->age_status : -99);
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate if (!kmd || kmd->age_status != PAM_NEW_AUTHTOK_REQD)
2280Sstevel@tonic-gate return (PAM_IGNORE);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate
2312941Ssemery (void) pam_get_item(pamh, PAM_USER, (void **)&user);
2320Sstevel@tonic-gate
2333391Ssemery if (user == NULL || *user == '\0') {
2343391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
235*11780SWill.Fiveash@Sun.COM "PAM-KRB5 (password): username is empty");
2362941Ssemery return (PAM_USER_UNKNOWN);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate if (!get_pw_uid(user, &pw_uid)) {
2403391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
2412941Ssemery "PAM-KRB5 (password): can't get uid for %s", user);
2422941Ssemery return (PAM_USER_UNKNOWN);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate /*
2460Sstevel@tonic-gate * if root key exists in the keytab, it's a random key so no
2470Sstevel@tonic-gate * need to prompt for pw and we just return IGNORE
2480Sstevel@tonic-gate */
2490Sstevel@tonic-gate if ((strcmp(user, ROOT_UNAME) == 0) &&
2500Sstevel@tonic-gate key_in_keytab(user, debug)) {
2510Sstevel@tonic-gate if (debug)
2523391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
2530Sstevel@tonic-gate "PAM-KRB5 (password): "
2540Sstevel@tonic-gate "key for '%s' in keytab, returning IGNORE", user);
2550Sstevel@tonic-gate result = PAM_IGNORE;
2560Sstevel@tonic-gate goto out;
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate
2592941Ssemery (void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&newpass);
2600Sstevel@tonic-gate
26111778SWill.Fiveash@Sun.COM /*
26211778SWill.Fiveash@Sun.COM * If the preauth type done didn't use a passwd just ignore the error.
26311778SWill.Fiveash@Sun.COM */
2642941Ssemery if (newpass == NULL)
26511778SWill.Fiveash@Sun.COM if (kmd && kmd->preauth_type == KRB_PKINIT)
26611778SWill.Fiveash@Sun.COM return (PAM_IGNORE);
26711778SWill.Fiveash@Sun.COM else
26811778SWill.Fiveash@Sun.COM return (PAM_SYSTEM_ERR);
2690Sstevel@tonic-gate
2702941Ssemery (void) pam_get_item(pamh, PAM_OLDAUTHTOK, (void **)&oldpass);
2710Sstevel@tonic-gate
2722941Ssemery if (oldpass == NULL)
27311778SWill.Fiveash@Sun.COM if (kmd && kmd->preauth_type == KRB_PKINIT)
27411778SWill.Fiveash@Sun.COM return (PAM_IGNORE);
27511778SWill.Fiveash@Sun.COM else
27611778SWill.Fiveash@Sun.COM return (PAM_SYSTEM_ERR);
2770Sstevel@tonic-gate
2782941Ssemery result = krb5_verifypw(user, oldpass, debug);
2792941Ssemery if (debug)
2803391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
281*11780SWill.Fiveash@Sun.COM "PAM-KRB5 (password): verifypw %d", result);
2820Sstevel@tonic-gate
2832941Ssemery /*
2842941Ssemery * If it's a bad password or general failure, we are done.
2852941Ssemery */
2862941Ssemery if (result != 0) {
28711778SWill.Fiveash@Sun.COM /*
28811778SWill.Fiveash@Sun.COM * if the preauth type done didn't use a passwd just ignore the
28911778SWill.Fiveash@Sun.COM * error.
29011778SWill.Fiveash@Sun.COM */
29111778SWill.Fiveash@Sun.COM if (kmd && kmd->preauth_type == KRB_PKINIT)
29211778SWill.Fiveash@Sun.COM return (PAM_IGNORE);
29311778SWill.Fiveash@Sun.COM
2942941Ssemery if (result == 2)
2952941Ssemery display_msg(pamh, PAM_ERROR_MSG, dgettext(TEXT_DOMAIN,
296*11780SWill.Fiveash@Sun.COM "Old Kerberos password incorrect\n"));
2972941Ssemery return (PAM_AUTHTOK_ERR);
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate
30011778SWill.Fiveash@Sun.COM /*
30111778SWill.Fiveash@Sun.COM * If the old password verifies try to change it regardless of the
30211778SWill.Fiveash@Sun.COM * preauth type and do not ignore the error.
30311778SWill.Fiveash@Sun.COM */
3040Sstevel@tonic-gate result = krb5_changepw(pamh, user, oldpass, newpass, debug);
3050Sstevel@tonic-gate if (result == PAM_SUCCESS) {
3062941Ssemery display_msg(pamh, PAM_TEXT_INFO, dgettext(TEXT_DOMAIN,
3072941Ssemery "Kerberos password successfully changed\n"));
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate get_set_creds(pamh, kmd, user, newpass, debug);
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate out:
3130Sstevel@tonic-gate if (debug)
3143391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
315*11780SWill.Fiveash@Sun.COM "PAM-KRB5 (password): out: returns %d",
3160Sstevel@tonic-gate result);
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate return (result);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate int
krb5_verifypw(char * princ_str,char * old_password,int debug)3220Sstevel@tonic-gate krb5_verifypw(
3230Sstevel@tonic-gate char *princ_str,
3240Sstevel@tonic-gate char *old_password,
3250Sstevel@tonic-gate int debug)
3260Sstevel@tonic-gate {
3270Sstevel@tonic-gate kadm5_ret_t code;
3280Sstevel@tonic-gate krb5_principal princ = 0;
3290Sstevel@tonic-gate char admin_realm[1024];
3300Sstevel@tonic-gate char kprinc[2*MAXHOSTNAMELEN];
3310Sstevel@tonic-gate char *cpw_service;
3320Sstevel@tonic-gate void *server_handle;
3330Sstevel@tonic-gate krb5_context context;
3340Sstevel@tonic-gate kadm5_config_params params;
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate (void) memset((char *)¶ms, 0, sizeof (params));
3370Sstevel@tonic-gate
3388991SPeter.Shoults@Sun.COM if (code = krb5_init_secure_context(&context)) {
3390Sstevel@tonic-gate return (6);
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate if ((code = get_kmd_kuser(context, (const char *)princ_str, kprinc,
343*11780SWill.Fiveash@Sun.COM 2*MAXHOSTNAMELEN)) != 0) {
3440Sstevel@tonic-gate return (code);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate /* Need to get a krb5_principal struct */
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate code = krb5_parse_name(context, kprinc, &princ);
3500Sstevel@tonic-gate
3512941Ssemery if (code != 0)
3522941Ssemery return (6);
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate if (strlen(old_password) == 0) {
3550Sstevel@tonic-gate krb5_free_principal(context, princ);
3560Sstevel@tonic-gate return (5);
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate (void) strlcpy(admin_realm,
360*11780SWill.Fiveash@Sun.COM krb5_princ_realm(context, princ)->data,
361*11780SWill.Fiveash@Sun.COM sizeof (admin_realm));
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate params.mask |= KADM5_CONFIG_REALM;
3640Sstevel@tonic-gate params.realm = admin_realm;
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) {
3683391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
369*11780SWill.Fiveash@Sun.COM "PAM-KRB5 (password): unable to get host based "
370*11780SWill.Fiveash@Sun.COM "service name for realm %s\n",
371*11780SWill.Fiveash@Sun.COM admin_realm);
3722941Ssemery krb5_free_principal(context, princ);
3730Sstevel@tonic-gate return (3);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate code = kadm5_init_with_password(kprinc, old_password, cpw_service,
377*11780SWill.Fiveash@Sun.COM ¶ms, KADM5_STRUCT_VERSION,
378*11780SWill.Fiveash@Sun.COM KADM5_API_VERSION_2, NULL,
379*11780SWill.Fiveash@Sun.COM &server_handle);
3800Sstevel@tonic-gate if (code != 0) {
3810Sstevel@tonic-gate if (debug)
3823391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
3830Sstevel@tonic-gate "PAM-KRB5: krb5_verifypw: init_with_pw"
3840Sstevel@tonic-gate " failed: (%s)", error_message(code));
3850Sstevel@tonic-gate krb5_free_principal(context, princ);
3860Sstevel@tonic-gate return ((code == KADM5_BAD_PASSWORD) ? 2 : 3);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate krb5_free_principal(context, princ);
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate (void) kadm5_destroy(server_handle);
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate return (0);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate /*
3970Sstevel@tonic-gate * Function: krb5_changepw
3980Sstevel@tonic-gate *
3990Sstevel@tonic-gate * Purpose: Initialize and call lower level routines to change a password
4000Sstevel@tonic-gate *
4010Sstevel@tonic-gate * Arguments:
4020Sstevel@tonic-gate *
4030Sstevel@tonic-gate * princ_str principal name to use, optional
4040Sstevel@tonic-gate * old_password old password
4050Sstevel@tonic-gate * new_password new password
4060Sstevel@tonic-gate *
4070Sstevel@tonic-gate * Returns:
4080Sstevel@tonic-gate * exit status of PAM_SUCCESS for success
4092941Ssemery * else returns PAM failure
4100Sstevel@tonic-gate *
4110Sstevel@tonic-gate * Requires:
4120Sstevel@tonic-gate * Passwords cannot be more than 255 characters long.
4130Sstevel@tonic-gate *
4140Sstevel@tonic-gate * Modifies:
4150Sstevel@tonic-gate *
4160Sstevel@tonic-gate * Changes the principal's password.
4170Sstevel@tonic-gate *
4180Sstevel@tonic-gate */
4190Sstevel@tonic-gate static int
krb5_changepw(pam_handle_t * pamh,char * princ_str,char * old_password,char * new_password,int debug)4200Sstevel@tonic-gate krb5_changepw(
4210Sstevel@tonic-gate pam_handle_t *pamh,
4220Sstevel@tonic-gate char *princ_str,
4230Sstevel@tonic-gate char *old_password,
4240Sstevel@tonic-gate char *new_password,
4250Sstevel@tonic-gate int debug)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate kadm5_ret_t code;
4280Sstevel@tonic-gate krb5_principal princ = 0;
4290Sstevel@tonic-gate char msg_ret[1024], admin_realm[1024];
4300Sstevel@tonic-gate char kprinc[2*MAXHOSTNAMELEN];
4310Sstevel@tonic-gate char *cpw_service;
4320Sstevel@tonic-gate void *server_handle;
4330Sstevel@tonic-gate krb5_context context;
4340Sstevel@tonic-gate kadm5_config_params params;
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate (void) memset((char *)¶ms, 0, sizeof (params));
4370Sstevel@tonic-gate
4388991SPeter.Shoults@Sun.COM if (krb5_init_secure_context(&context) != 0)
4392941Ssemery return (PAM_SYSTEM_ERR);
4400Sstevel@tonic-gate
4410Sstevel@tonic-gate if ((code = get_kmd_kuser(context, (const char *)princ_str, kprinc,
442*11780SWill.Fiveash@Sun.COM 2*MAXHOSTNAMELEN)) != 0) {
4430Sstevel@tonic-gate return (code);
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate /* Need to get a krb5_principal struct */
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate code = krb5_parse_name(context, kprinc, &princ);
4492941Ssemery if (code != 0)
4502941Ssemery return (PAM_SYSTEM_ERR);
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate if (strlen(old_password) == 0) {
4530Sstevel@tonic-gate krb5_free_principal(context, princ);
4542941Ssemery return (PAM_AUTHTOK_ERR);
4550Sstevel@tonic-gate }
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate (void) snprintf(admin_realm, sizeof (admin_realm), "%s",
458*11780SWill.Fiveash@Sun.COM krb5_princ_realm(context, princ)->data);
4590Sstevel@tonic-gate params.mask |= KADM5_CONFIG_REALM;
4600Sstevel@tonic-gate params.realm = admin_realm;
4610Sstevel@tonic-gate
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) {
4643391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
465*11780SWill.Fiveash@Sun.COM "PAM-KRB5 (password):unable to get host based "
466*11780SWill.Fiveash@Sun.COM "service name for realm %s\n",
467*11780SWill.Fiveash@Sun.COM admin_realm);
4682941Ssemery return (PAM_SYSTEM_ERR);
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate code = kadm5_init_with_password(kprinc, old_password, cpw_service,
472*11780SWill.Fiveash@Sun.COM ¶ms, KADM5_STRUCT_VERSION,
473*11780SWill.Fiveash@Sun.COM KADM5_API_VERSION_2, NULL,
474*11780SWill.Fiveash@Sun.COM &server_handle);
4750Sstevel@tonic-gate free(cpw_service);
4760Sstevel@tonic-gate if (code != 0) {
4770Sstevel@tonic-gate if (debug)
4783391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
4790Sstevel@tonic-gate "PAM-KRB5 (password): changepw: "
4800Sstevel@tonic-gate "init_with_pw failed: (%s)", error_message(code));
4810Sstevel@tonic-gate krb5_free_principal(context, princ);
4822941Ssemery return ((code == KADM5_BAD_PASSWORD) ?
483*11780SWill.Fiveash@Sun.COM PAM_AUTHTOK_ERR : PAM_SYSTEM_ERR);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate code = kadm5_chpass_principal_util(server_handle, princ,
487*11780SWill.Fiveash@Sun.COM new_password,
488*11780SWill.Fiveash@Sun.COM NULL /* don't need pw back */,
489*11780SWill.Fiveash@Sun.COM msg_ret,
490*11780SWill.Fiveash@Sun.COM sizeof (msg_ret));
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate if (code) {
4930Sstevel@tonic-gate char msgs[2][PAM_MAX_MSG_SIZE];
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate (void) snprintf(msgs[0], PAM_MAX_MSG_SIZE, "%s",
496*11780SWill.Fiveash@Sun.COM dgettext(TEXT_DOMAIN,
497*11780SWill.Fiveash@Sun.COM "Kerberos password not changed: "));
4980Sstevel@tonic-gate (void) snprintf(msgs[1], PAM_MAX_MSG_SIZE, "%s", msg_ret);
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate display_msgs(pamh, PAM_ERROR_MSG, 2, msgs);
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate krb5_free_principal(context, princ);
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate (void) kadm5_destroy(server_handle);
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate if (debug)
5083391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
5090Sstevel@tonic-gate "PAM-KRB5 (password): changepw: end %d", code);
5100Sstevel@tonic-gate
5112941Ssemery if (code != 0)
5122941Ssemery return (PAM_AUTHTOK_ERR);
5130Sstevel@tonic-gate
5142941Ssemery return (PAM_SUCCESS);
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate static void
display_msgs(pam_handle_t * pamh,int msg_style,int nmsg,char msgs[][PAM_MAX_MSG_SIZE])5180Sstevel@tonic-gate display_msgs(pam_handle_t *pamh,
5190Sstevel@tonic-gate int msg_style, int nmsg, char msgs[][PAM_MAX_MSG_SIZE])
5200Sstevel@tonic-gate {
5210Sstevel@tonic-gate (void) __pam_display_msg(pamh, msg_style, nmsg, msgs, NULL);
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate static void
display_msg(pam_handle_t * pamh,int msg_style,char * msg)5260Sstevel@tonic-gate display_msg(pam_handle_t *pamh, int msg_style, char *msg)
5270Sstevel@tonic-gate {
5280Sstevel@tonic-gate char pam_msg[1][PAM_MAX_MSG_SIZE];
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate (void) snprintf(pam_msg[0], PAM_MAX_MSG_SIZE, "%s", msg);
5310Sstevel@tonic-gate display_msgs(pamh, msg_style, 1, pam_msg);
5320Sstevel@tonic-gate }
533