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
53391Ssemery * Common Development and Distribution License (the "License").
63391Ssemery * 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 */
2111411SSurya.Prakki@Sun.COM
220Sstevel@tonic-gate /*
23*11780SWill.Fiveash@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include <libintl.h>
280Sstevel@tonic-gate #include <security/pam_appl.h>
290Sstevel@tonic-gate #include <security/pam_modules.h>
300Sstevel@tonic-gate #include <string.h>
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <pwd.h>
350Sstevel@tonic-gate #include <syslog.h>
360Sstevel@tonic-gate #include <libintl.h>
376924Sps57422 #include <k5-int.h>
380Sstevel@tonic-gate #include <netdb.h>
390Sstevel@tonic-gate #include <unistd.h>
400Sstevel@tonic-gate #include <sys/stat.h>
410Sstevel@tonic-gate #include <fcntl.h>
42781Sgtb #include <errno.h>
430Sstevel@tonic-gate #include <com_err.h>
440Sstevel@tonic-gate
450Sstevel@tonic-gate #include "utils.h"
460Sstevel@tonic-gate #include "krb5_repository.h"
470Sstevel@tonic-gate
480Sstevel@tonic-gate #define PAMTXD "SUNW_OST_SYSOSPAM"
490Sstevel@tonic-gate #define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */
500Sstevel@tonic-gate
510Sstevel@tonic-gate extern void krb5_cleanup(pam_handle_t *, void *, int);
520Sstevel@tonic-gate
530Sstevel@tonic-gate static int attempt_refresh_cred(krb5_module_data_t *, char *, int);
540Sstevel@tonic-gate static int attempt_delete_initcred(krb5_module_data_t *);
550Sstevel@tonic-gate static krb5_error_code krb5_renew_tgt(krb5_module_data_t *, krb5_principal,
560Sstevel@tonic-gate krb5_principal, int);
570Sstevel@tonic-gate
580Sstevel@tonic-gate extern uint_t kwarn_add_warning(char *, int);
590Sstevel@tonic-gate extern uint_t kwarn_del_warning(char *);
600Sstevel@tonic-gate
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate * pam_sm_setcred
630Sstevel@tonic-gate */
640Sstevel@tonic-gate int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char ** argv)650Sstevel@tonic-gate pam_sm_setcred(
660Sstevel@tonic-gate pam_handle_t *pamh,
670Sstevel@tonic-gate int flags,
680Sstevel@tonic-gate int argc,
690Sstevel@tonic-gate const char **argv)
700Sstevel@tonic-gate {
710Sstevel@tonic-gate int i;
720Sstevel@tonic-gate int err = 0;
730Sstevel@tonic-gate int debug = 0;
740Sstevel@tonic-gate krb5_module_data_t *kmd = NULL;
753391Ssemery char *user = NULL;
760Sstevel@tonic-gate krb5_repository_data_t *krb5_data = NULL;
770Sstevel@tonic-gate pam_repository_t *rep_data = NULL;
780Sstevel@tonic-gate
790Sstevel@tonic-gate for (i = 0; i < argc; i++) {
800Sstevel@tonic-gate if (strcasecmp(argv[i], "debug") == 0)
810Sstevel@tonic-gate debug = 1;
820Sstevel@tonic-gate else if (strcasecmp(argv[i], "nowarn") == 0)
830Sstevel@tonic-gate flags = flags | PAM_SILENT;
840Sstevel@tonic-gate }
850Sstevel@tonic-gate
860Sstevel@tonic-gate if (debug)
873391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
880Sstevel@tonic-gate "PAM-KRB5 (setcred): start: nowarn = %d, flags = 0x%x",
890Sstevel@tonic-gate flags & PAM_SILENT ? 1 : 0, flags);
900Sstevel@tonic-gate
910Sstevel@tonic-gate /* make sure flags are valid */
920Sstevel@tonic-gate if (flags &&
930Sstevel@tonic-gate !(flags & PAM_ESTABLISH_CRED) &&
940Sstevel@tonic-gate !(flags & PAM_REINITIALIZE_CRED) &&
950Sstevel@tonic-gate !(flags & PAM_REFRESH_CRED) &&
960Sstevel@tonic-gate !(flags & PAM_DELETE_CRED) &&
970Sstevel@tonic-gate !(flags & PAM_SILENT)) {
983391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
995890Sjjj "PAM-KRB5 (setcred): illegal flag %d", flags);
1000Sstevel@tonic-gate err = PAM_SYSTEM_ERR;
1010Sstevel@tonic-gate goto out;
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate
1043391Ssemery (void) pam_get_item(pamh, PAM_USER, (void**) &user);
1050Sstevel@tonic-gate
1063391Ssemery if (user == NULL || *user == '\0')
1073391Ssemery return (PAM_USER_UNKNOWN);
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate if (pam_get_data(pamh, KRB5_DATA, (const void**)&kmd) != PAM_SUCCESS) {
1100Sstevel@tonic-gate if (debug) {
1113391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
1120Sstevel@tonic-gate "PAM-KRB5 (setcred): kmd get failed, kmd=0x%p",
1130Sstevel@tonic-gate kmd);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate /*
1170Sstevel@tonic-gate * User doesn't need to authenticate for PAM_REFRESH_CRED
1180Sstevel@tonic-gate * or for PAM_DELETE_CRED
1190Sstevel@tonic-gate */
1200Sstevel@tonic-gate if (flags & (PAM_REFRESH_CRED|PAM_DELETE_CRED)) {
1213391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
1225890Sjjj "PAM-KRB5 (setcred): inst kmd structure");
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate kmd = calloc(1, sizeof (krb5_module_data_t));
1250Sstevel@tonic-gate
1266488Ssemery if (kmd == NULL)
1276488Ssemery return (PAM_BUF_ERR);
1286488Ssemery
1296488Ssemery
1306488Ssemery /*
1316488Ssemery * Need to initialize auth_status here to
1326488Ssemery * PAM_AUTHINFO_UNAVAIL else there is a false positive
1336488Ssemery * of PAM_SUCCESS.
1346488Ssemery */
1356488Ssemery kmd->auth_status = PAM_AUTHINFO_UNAVAIL;
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate if ((err = pam_set_data(pamh, KRB5_DATA,
1385890Sjjj kmd, &krb5_cleanup)) != PAM_SUCCESS) {
1390Sstevel@tonic-gate free(kmd);
1400Sstevel@tonic-gate return (PAM_SYSTEM_ERR);
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate } else {
1434621Ssemery /*
1444621Ssemery * This could mean that we are not the account authority
1454621Ssemery * for the authenticated user. Therefore we should
1464621Ssemery * return PAM_IGNORE in order to not affect the
1474621Ssemery * login process of said user.
1484621Ssemery */
1494621Ssemery err = PAM_IGNORE;
1504621Ssemery goto out;
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate } else { /* pam_get_data success */
1540Sstevel@tonic-gate if (kmd == NULL) {
1550Sstevel@tonic-gate if (debug) {
1563391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
1570Sstevel@tonic-gate "PAM-KRB5 (setcred): kmd structure"
1580Sstevel@tonic-gate " gotten but is NULL for user %s", user);
1590Sstevel@tonic-gate }
1606488Ssemery err = PAM_SYSTEM_ERR;
1610Sstevel@tonic-gate goto out;
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate if (debug)
1653391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
1660Sstevel@tonic-gate "PAM-KRB5 (setcred): kmd auth_status: %s",
1670Sstevel@tonic-gate pam_strerror(pamh, kmd->auth_status));
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate /*
1700Sstevel@tonic-gate * pam_auth has set status to ignore, so we also return ignore
1710Sstevel@tonic-gate */
1720Sstevel@tonic-gate if (kmd->auth_status == PAM_IGNORE) {
1730Sstevel@tonic-gate err = PAM_IGNORE;
1740Sstevel@tonic-gate goto out;
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate kmd->debug = debug;
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate * User must have passed pam_authenticate()
1820Sstevel@tonic-gate * in order to use PAM_ESTABLISH_CRED or PAM_REINITIALIZE_CRED
1830Sstevel@tonic-gate */
1840Sstevel@tonic-gate if ((flags & (PAM_ESTABLISH_CRED|PAM_REINITIALIZE_CRED)) &&
1850Sstevel@tonic-gate (kmd->auth_status != PAM_SUCCESS)) {
1860Sstevel@tonic-gate if (kmd->debug)
1873391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
1880Sstevel@tonic-gate "PAM-KRB5 (setcred): unable to "
1890Sstevel@tonic-gate "setcreds, not authenticated!");
1900Sstevel@tonic-gate return (PAM_CRED_UNAVAIL);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate /*
1940Sstevel@tonic-gate * We cannot assume that kmd->kcontext being non-NULL
1950Sstevel@tonic-gate * means it is valid. Other pam_krb5 mods may have
1960Sstevel@tonic-gate * freed it but not reset it to NULL.
1970Sstevel@tonic-gate * Log a message when debugging to track down memory
1980Sstevel@tonic-gate * leaks.
1990Sstevel@tonic-gate */
2000Sstevel@tonic-gate if (kmd->kcontext != NULL && kmd->debug)
2013391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
2025890Sjjj "PAM-KRB5 (setcred): kcontext != NULL, "
2035890Sjjj "possible memory leak.");
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate /*
2063391Ssemery * Use the authenticated and validated user, if applicable.
2073391Ssemery */
2083391Ssemery if (kmd->user != NULL)
2093391Ssemery user = kmd->user;
2103391Ssemery
2113391Ssemery /*
2120Sstevel@tonic-gate * If auth was short-circuited we will not have anything to
2130Sstevel@tonic-gate * renew, so just return here.
2140Sstevel@tonic-gate */
2153391Ssemery (void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data);
2163391Ssemery
2170Sstevel@tonic-gate if (rep_data != NULL) {
2180Sstevel@tonic-gate if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) {
2190Sstevel@tonic-gate if (debug)
2203391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
2215890Sjjj "PAM-KRB5 (setcred): wrong"
2225890Sjjj "repository found (%s), returning "
2235890Sjjj "PAM_IGNORE", rep_data->type);
2240Sstevel@tonic-gate return (PAM_IGNORE);
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate if (rep_data->scope_len == sizeof (krb5_repository_data_t)) {
2270Sstevel@tonic-gate krb5_data = (krb5_repository_data_t *)rep_data->scope;
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate if (krb5_data->flags ==
2305890Sjjj SUNW_PAM_KRB5_ALREADY_AUTHENTICATED &&
2315890Sjjj krb5_data->principal != NULL &&
2325890Sjjj strlen(krb5_data->principal)) {
2330Sstevel@tonic-gate if (debug)
2343391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
2355890Sjjj "PAM-KRB5 (setcred): "
2365890Sjjj "Principal %s already "
2375890Sjjj "authenticated, "
2385890Sjjj "cannot setcred",
2395890Sjjj krb5_data->principal);
2400Sstevel@tonic-gate return (PAM_SUCCESS);
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate if (flags & PAM_REINITIALIZE_CRED)
2460Sstevel@tonic-gate err = attempt_refresh_cred(kmd, user, PAM_REINITIALIZE_CRED);
2470Sstevel@tonic-gate else if (flags & PAM_REFRESH_CRED)
2480Sstevel@tonic-gate err = attempt_refresh_cred(kmd, user, PAM_REFRESH_CRED);
2490Sstevel@tonic-gate else if (flags & PAM_DELETE_CRED)
2500Sstevel@tonic-gate err = attempt_delete_initcred(kmd);
2510Sstevel@tonic-gate else {
2520Sstevel@tonic-gate /*
2530Sstevel@tonic-gate * Default case: PAM_ESTABLISH_CRED
2540Sstevel@tonic-gate */
2550Sstevel@tonic-gate err = attempt_refresh_cred(kmd, user, PAM_ESTABLISH_CRED);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate
2583391Ssemery if (err != PAM_SUCCESS)
2593391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
2600Sstevel@tonic-gate "PAM-KRB5 (setcred): pam_setcred failed "
2610Sstevel@tonic-gate "for %s (%s).", user, pam_strerror(pamh, err));
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate out:
2640Sstevel@tonic-gate if (kmd && kmd->kcontext) {
2650Sstevel@tonic-gate /*
2660Sstevel@tonic-gate * free 'kcontext' field if it is allocated,
2670Sstevel@tonic-gate * kcontext is local to the operation being performed
2680Sstevel@tonic-gate * not considered global to the entire pam module.
2690Sstevel@tonic-gate */
2700Sstevel@tonic-gate krb5_free_context(kmd->kcontext);
2710Sstevel@tonic-gate kmd->kcontext = NULL;
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate * 'kmd' is not freed here, it is handled in krb5_cleanup
2760Sstevel@tonic-gate */
2770Sstevel@tonic-gate if (debug)
2783391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
2790Sstevel@tonic-gate "PAM-KRB5 (setcred): end: %s",
2800Sstevel@tonic-gate pam_strerror(pamh, err));
2810Sstevel@tonic-gate return (err);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate static int
attempt_refresh_cred(krb5_module_data_t * kmd,char * user,int flag)2850Sstevel@tonic-gate attempt_refresh_cred(
2860Sstevel@tonic-gate krb5_module_data_t *kmd,
2870Sstevel@tonic-gate char *user,
2880Sstevel@tonic-gate int flag)
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate krb5_principal me;
2910Sstevel@tonic-gate krb5_principal server;
2920Sstevel@tonic-gate krb5_error_code code;
2930Sstevel@tonic-gate char kuser[2*MAXHOSTNAMELEN];
2940Sstevel@tonic-gate krb5_data tgtname = {
2950Sstevel@tonic-gate 0,
2960Sstevel@tonic-gate KRB5_TGS_NAME_SIZE,
2970Sstevel@tonic-gate KRB5_TGS_NAME
2980Sstevel@tonic-gate };
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate /* Create a new context here. */
3018991SPeter.Shoults@Sun.COM if (krb5_init_secure_context(&kmd->kcontext) != 0) {
3020Sstevel@tonic-gate if (kmd->debug)
3033391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
3040Sstevel@tonic-gate "PAM-KRB5 (setcred): unable to "
3050Sstevel@tonic-gate "initialize krb5 context");
3060Sstevel@tonic-gate return (PAM_SYSTEM_ERR);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate if (krb5_cc_default(kmd->kcontext, &kmd->ccache) != 0) {
3103391Ssemery return (PAM_SYSTEM_ERR);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate if ((code = get_kmd_kuser(kmd->kcontext, (const char *)user, kuser,
3145890Sjjj 2*MAXHOSTNAMELEN)) != 0) {
3150Sstevel@tonic-gate return (code);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate if (krb5_parse_name(kmd->kcontext, kuser, &me) != 0) {
3193391Ssemery return (PAM_SYSTEM_ERR);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate if (code = krb5_build_principal_ext(kmd->kcontext, &server,
3235890Sjjj krb5_princ_realm(kmd->kcontext, me)->length,
3245890Sjjj krb5_princ_realm(kmd->kcontext, me)->data,
3255890Sjjj tgtname.length, tgtname.data,
3265890Sjjj krb5_princ_realm(kmd->kcontext, me)->length,
3275890Sjjj krb5_princ_realm(kmd->kcontext, me)->data, 0)) {
3283391Ssemery krb5_free_principal(kmd->kcontext, me);
3293391Ssemery return (PAM_SYSTEM_ERR);
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate code = krb5_renew_tgt(kmd, me, server, flag);
3330Sstevel@tonic-gate
3343391Ssemery krb5_free_principal(kmd->kcontext, server);
3353391Ssemery krb5_free_principal(kmd->kcontext, me);
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate if (code) {
3383391Ssemery if (kmd->debug)
3393391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
3405890Sjjj "PAM-KRB5(setcred): krb5_renew_tgt() "
3415890Sjjj "failed: %s", error_message((errcode_t)code));
3420Sstevel@tonic-gate return (PAM_CRED_ERR);
3430Sstevel@tonic-gate } else {
3440Sstevel@tonic-gate return (PAM_SUCCESS);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate /*
3490Sstevel@tonic-gate * This code will update the credential matching "server" in the user's
3500Sstevel@tonic-gate * credential cache. The flag may be set to one of:
3518303SPeter.Shoults@Sun.COM * PAM_REINITIALIZE_CRED/PAM_ESTABLISH_CRED - If we have new credentials then
3528303SPeter.Shoults@Sun.COM * create a new cred cache with these credentials else return failure.
3536488Ssemery * PAM_REFRESH_CRED - If we have new credentials then create a new cred cache
3546488Ssemery * with these credentials else attempt to renew the credentials.
3556488Ssemery *
3568303SPeter.Shoults@Sun.COM * Note for any of the flags that if a new credential does exist from the
3578303SPeter.Shoults@Sun.COM * previous auth pass then this will overwrite any existing credentials in the
3588303SPeter.Shoults@Sun.COM * credential cache.
3590Sstevel@tonic-gate */
3600Sstevel@tonic-gate static krb5_error_code
krb5_renew_tgt(krb5_module_data_t * kmd,krb5_principal me,krb5_principal server,int flag)3610Sstevel@tonic-gate krb5_renew_tgt(
3620Sstevel@tonic-gate krb5_module_data_t *kmd,
3630Sstevel@tonic-gate krb5_principal me,
3640Sstevel@tonic-gate krb5_principal server,
3650Sstevel@tonic-gate int flag)
3660Sstevel@tonic-gate {
3670Sstevel@tonic-gate krb5_error_code retval;
3680Sstevel@tonic-gate krb5_creds creds;
3693924Sgtb krb5_creds *renewed_cred = NULL;
3700Sstevel@tonic-gate char *client_name = NULL;
3718303SPeter.Shoults@Sun.COM char *username = NULL;
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate #define my_creds (kmd->initcreds)
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate if ((flag != PAM_REFRESH_CRED) &&
3765890Sjjj (flag != PAM_REINITIALIZE_CRED) &&
3775890Sjjj (flag != PAM_ESTABLISH_CRED))
3785890Sjjj return (KRB5KRB_ERR_GENERIC);
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate /* this is needed only for the ktkt_warnd */
3813391Ssemery if ((retval = krb5_unparse_name(kmd->kcontext, me, &client_name)) != 0)
3823391Ssemery return (retval);
3830Sstevel@tonic-gate
3843924Sgtb (void) memset(&creds, 0, sizeof (krb5_creds));
3850Sstevel@tonic-gate if ((retval = krb5_copy_principal(kmd->kcontext,
3865890Sjjj server, &creds.server))) {
3870Sstevel@tonic-gate if (kmd->debug)
3883391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
3895890Sjjj "PAM-KRB5 (setcred): krb5_copy_principal "
3905890Sjjj "failed: %s",
3915890Sjjj error_message((errcode_t)retval));
3920Sstevel@tonic-gate goto cleanup_creds;
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate /* obtain ticket & session key */
3960Sstevel@tonic-gate retval = krb5_cc_get_principal(kmd->kcontext,
3975890Sjjj kmd->ccache, &creds.client);
3980Sstevel@tonic-gate if (retval && (kmd->debug))
3993391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
4005890Sjjj "PAM-KRB5 (setcred): User not in cred "
4015890Sjjj "cache (%s)", error_message((errcode_t)retval));
4020Sstevel@tonic-gate
4038303SPeter.Shoults@Sun.COM /*
4048303SPeter.Shoults@Sun.COM * We got here either with the ESTABLISH | REINIT | REFRESH flag and
4058303SPeter.Shoults@Sun.COM * auth_status returns SUCCESS or REFRESH and auth_status failure.
4068303SPeter.Shoults@Sun.COM *
4078303SPeter.Shoults@Sun.COM * Rules:
4088303SPeter.Shoults@Sun.COM * - If the prior auth pass was successful then store the new
4098303SPeter.Shoults@Sun.COM * credentials in the cache, regardless of which flag.
4108303SPeter.Shoults@Sun.COM *
4118303SPeter.Shoults@Sun.COM * - Else if REFRESH flag is used and there are no new
4128303SPeter.Shoults@Sun.COM * credentials then attempt to refresh the existing credentials.
4138303SPeter.Shoults@Sun.COM *
4148303SPeter.Shoults@Sun.COM * - Note, refresh will not work if "R" flag is not set in
4158303SPeter.Shoults@Sun.COM * original credential. We don't want to 2nd guess the
4168303SPeter.Shoults@Sun.COM * intention of the person who created the existing credential.
4178303SPeter.Shoults@Sun.COM */
4188303SPeter.Shoults@Sun.COM if (kmd->auth_status == PAM_SUCCESS) {
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate * Create a fresh ccache, and store the credentials
4210Sstevel@tonic-gate * we got from pam_authenticate()
4220Sstevel@tonic-gate */
4230Sstevel@tonic-gate if ((retval = krb5_cc_initialize(kmd->kcontext,
4245890Sjjj kmd->ccache, me)) != 0) {
4253391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
4265890Sjjj "PAM-KRB5 (setcred): krb5_cc_initialize "
4275890Sjjj "failed: %s",
4285890Sjjj error_message((errcode_t)retval));
4290Sstevel@tonic-gate } else if ((retval = krb5_cc_store_cred(kmd->kcontext,
4305890Sjjj kmd->ccache, &my_creds)) != 0) {
4313391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
4325890Sjjj "PAM-KRB5 (setcred): krb5_cc_store_cred "
4335890Sjjj "failed: %s",
4345890Sjjj error_message((errcode_t)retval));
4350Sstevel@tonic-gate }
4368303SPeter.Shoults@Sun.COM } else if ((retval == 0) && (flag & PAM_REFRESH_CRED)) {
4378303SPeter.Shoults@Sun.COM /*
4388303SPeter.Shoults@Sun.COM * If we only wanted to refresh the creds but failed
4398303SPeter.Shoults@Sun.COM * due to expiration, lack of "R" flag, or other
4408303SPeter.Shoults@Sun.COM * problems, return an error.
4418303SPeter.Shoults@Sun.COM */
4428303SPeter.Shoults@Sun.COM if (retval = krb5_get_credentials_renew(kmd->kcontext,
4438303SPeter.Shoults@Sun.COM 0, kmd->ccache, &creds, &renewed_cred)) {
4448303SPeter.Shoults@Sun.COM if (kmd->debug) {
4458303SPeter.Shoults@Sun.COM __pam_log(LOG_AUTH | LOG_DEBUG,
4468303SPeter.Shoults@Sun.COM "PAM-KRB5 (setcred): "
4478303SPeter.Shoults@Sun.COM "krb5_get_credentials"
4488303SPeter.Shoults@Sun.COM "_renew(update) failed: %s",
4498303SPeter.Shoults@Sun.COM error_message((errcode_t)retval));
4508303SPeter.Shoults@Sun.COM }
4518303SPeter.Shoults@Sun.COM }
4528303SPeter.Shoults@Sun.COM } else {
4530Sstevel@tonic-gate /*
4540Sstevel@tonic-gate * We failed to get the user's credentials.
4550Sstevel@tonic-gate * This might be due to permission error on the cache,
4560Sstevel@tonic-gate * or maybe we are looking in the wrong cache file!
4570Sstevel@tonic-gate */
4583391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
4595890Sjjj "PAM-KRB5 (setcred): Cannot find creds"
4605890Sjjj " for %s (%s)",
4615890Sjjj client_name ? client_name : "(unknown)",
4625890Sjjj error_message((errcode_t)retval));
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate cleanup_creds:
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate if ((retval == 0) && (client_name != NULL)) {
4680Sstevel@tonic-gate /*
4690Sstevel@tonic-gate * Credential update was successful!
4700Sstevel@tonic-gate *
4710Sstevel@tonic-gate * We now chown the ccache to the appropriate uid/gid
4720Sstevel@tonic-gate * combination, if its a FILE based ccache.
4730Sstevel@tonic-gate */
4746924Sps57422 if (!kmd->env || strstr(kmd->env, "FILE:")) {
4750Sstevel@tonic-gate uid_t uuid;
4760Sstevel@tonic-gate gid_t ugid;
4778303SPeter.Shoults@Sun.COM char *tmpname = NULL;
4780Sstevel@tonic-gate char *filepath = NULL;
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate username = strdup(client_name);
4815890Sjjj if (username == NULL) {
4825890Sjjj __pam_log(LOG_AUTH | LOG_ERR,
4835890Sjjj "PAM-KRB5 (setcred): Out of memory");
4845890Sjjj retval = KRB5KRB_ERR_GENERIC;
4855890Sjjj goto error;
4865890Sjjj }
4870Sstevel@tonic-gate if ((tmpname = strchr(username, '@')))
4880Sstevel@tonic-gate *tmpname = '\0';
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate if (get_pw_uid(username, &uuid) == 0 ||
4910Sstevel@tonic-gate get_pw_gid(username, &ugid) == 0) {
4923391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
4933391Ssemery "PAM-KRB5 (setcred): Unable to "
4940Sstevel@tonic-gate "find matching uid/gid pair for user `%s'",
4950Sstevel@tonic-gate username);
4963924Sgtb retval = KRB5KRB_ERR_GENERIC;
4973924Sgtb goto error;
4980Sstevel@tonic-gate }
4996924Sps57422
5006924Sps57422 if (!kmd->env) {
5016924Sps57422 char buffer[512];
5026924Sps57422
5036924Sps57422 if (snprintf(buffer, sizeof (buffer),
5046924Sps57422 "%s=FILE:/tmp/krb5cc_%d", KRB5_ENV_CCNAME,
5056924Sps57422 (int)uuid) >= sizeof (buffer)) {
5066924Sps57422 retval = KRB5KRB_ERR_GENERIC;
5076924Sps57422 goto error;
5086924Sps57422 }
5096924Sps57422
5106924Sps57422 /*
5116924Sps57422 * We MUST copy this to the heap for the putenv
5126924Sps57422 * to work!
5136924Sps57422 */
5146924Sps57422 kmd->env = strdup(buffer);
5156924Sps57422 if (!kmd->env) {
5166924Sps57422 retval = ENOMEM;
5176924Sps57422 goto error;
5186924Sps57422 } else {
5196924Sps57422 if (putenv(kmd->env)) {
5206924Sps57422 retval = ENOMEM;
5216924Sps57422 goto error;
5226924Sps57422 }
5236924Sps57422 }
5246924Sps57422 }
5256924Sps57422
5268303SPeter.Shoults@Sun.COM /*
5278303SPeter.Shoults@Sun.COM * We know at this point that kmd->env must start
5288303SPeter.Shoults@Sun.COM * with the literal string "FILE:". Set filepath
5298303SPeter.Shoults@Sun.COM * character string to point to ":"
5308303SPeter.Shoults@Sun.COM */
5318303SPeter.Shoults@Sun.COM
5328303SPeter.Shoults@Sun.COM filepath = strchr(kmd->env, ':');
5338303SPeter.Shoults@Sun.COM
5348303SPeter.Shoults@Sun.COM /*
5358303SPeter.Shoults@Sun.COM * Now check if first char after ":" is null char
5368303SPeter.Shoults@Sun.COM */
5378303SPeter.Shoults@Sun.COM if (filepath[1] == '\0') {
5383391Ssemery __pam_log(LOG_AUTH | LOG_ERR,
5395890Sjjj "PAM-KRB5 (setcred): Invalid pathname "
5405890Sjjj "for credential cache of user `%s'",
5415890Sjjj username);
5423924Sgtb retval = KRB5KRB_ERR_GENERIC;
5433924Sgtb goto error;
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate if (chown(filepath+1, uuid, ugid)) {
5460Sstevel@tonic-gate if (kmd->debug)
5473391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
5480Sstevel@tonic-gate "PAM-KRB5 (setcred): chown to user "
5490Sstevel@tonic-gate "`%s' failed for FILE=%s",
5500Sstevel@tonic-gate username, filepath);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate }
5533924Sgtb }
5540Sstevel@tonic-gate
5553924Sgtb error:
5563924Sgtb if (retval == 0) {
5573924Sgtb krb5_timestamp endtime;
5583924Sgtb
5593924Sgtb if (renewed_cred && renewed_cred->times.endtime != 0)
5603924Sgtb endtime = renewed_cred->times.endtime;
5613924Sgtb else
5623924Sgtb endtime = my_creds.times.endtime;
5633924Sgtb
5643924Sgtb if (kmd->debug)
5653924Sgtb __pam_log(LOG_AUTH | LOG_DEBUG,
5665890Sjjj "PAM-KRB5 (setcred): delete/add warning");
5673924Sgtb
568*11780SWill.Fiveash@Sun.COM if (kwarn_del_warning(client_name) != 0) {
569*11780SWill.Fiveash@Sun.COM __pam_log(LOG_AUTH | LOG_NOTICE,
570*11780SWill.Fiveash@Sun.COM "PAM-KRB5 (setcred): kwarn_del_warning"
571*11780SWill.Fiveash@Sun.COM " failed: ktkt_warnd(1M) down?");
572*11780SWill.Fiveash@Sun.COM }
573*11780SWill.Fiveash@Sun.COM
5743924Sgtb if (kwarn_add_warning(client_name, endtime) != 0) {
5753924Sgtb __pam_log(LOG_AUTH | LOG_NOTICE,
5765890Sjjj "PAM-KRB5 (setcred): kwarn_add_warning"
5775890Sjjj " failed: ktkt_warnd(1M) down?");
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate }
5803924Sgtb
5813924Sgtb if (renewed_cred != NULL)
5823924Sgtb krb5_free_creds(kmd->kcontext, renewed_cred);
5833924Sgtb
5840Sstevel@tonic-gate if (client_name != NULL)
5850Sstevel@tonic-gate free(client_name);
5860Sstevel@tonic-gate
5878303SPeter.Shoults@Sun.COM if (username)
5888303SPeter.Shoults@Sun.COM free(username);
5898303SPeter.Shoults@Sun.COM
5900Sstevel@tonic-gate krb5_free_cred_contents(kmd->kcontext, &creds);
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate return (retval);
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate
5950Sstevel@tonic-gate /*
5960Sstevel@tonic-gate * Delete the user's credentials for this session
5970Sstevel@tonic-gate */
5980Sstevel@tonic-gate static int
attempt_delete_initcred(krb5_module_data_t * kmd)5990Sstevel@tonic-gate attempt_delete_initcred(krb5_module_data_t *kmd)
6000Sstevel@tonic-gate {
6010Sstevel@tonic-gate if (kmd == NULL)
6023391Ssemery return (PAM_SUCCESS);
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate if (kmd->debug) {
6053391Ssemery __pam_log(LOG_AUTH | LOG_DEBUG,
6065890Sjjj "PAM-KRB5 (setcred): deleting user's "
6075890Sjjj "credentials (initcreds)");
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds);
6100Sstevel@tonic-gate (void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds));
6110Sstevel@tonic-gate kmd->auth_status = PAM_AUTHINFO_UNAVAIL;
6123391Ssemery return (PAM_SUCCESS);
6130Sstevel@tonic-gate }
614