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 53bfb48feSsemery * Common Development and Distribution License (the "License"). 63bfb48feSsemery * 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 /* 224a7ceb24Sjjj * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <libintl.h> 297c478bd9Sstevel@tonic-gate #include <security/pam_appl.h> 307c478bd9Sstevel@tonic-gate #include <security/pam_modules.h> 317c478bd9Sstevel@tonic-gate #include <string.h> 327c478bd9Sstevel@tonic-gate #include <stdio.h> 337c478bd9Sstevel@tonic-gate #include <stdlib.h> 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <pwd.h> 367c478bd9Sstevel@tonic-gate #include <syslog.h> 377c478bd9Sstevel@tonic-gate #include <libintl.h> 38*d80035c5Sps #include <k5-int.h> 397c478bd9Sstevel@tonic-gate #include <netdb.h> 407c478bd9Sstevel@tonic-gate #include <unistd.h> 417c478bd9Sstevel@tonic-gate #include <sys/stat.h> 427c478bd9Sstevel@tonic-gate #include <fcntl.h> 43505d05c7Sgtb #include <errno.h> 447c478bd9Sstevel@tonic-gate #include <com_err.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #include "utils.h" 477c478bd9Sstevel@tonic-gate #include "krb5_repository.h" 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define PAMTXD "SUNW_OST_SYSOSPAM" 507c478bd9Sstevel@tonic-gate #define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate extern void krb5_cleanup(pam_handle_t *, void *, int); 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate static int attempt_refresh_cred(krb5_module_data_t *, char *, int); 557c478bd9Sstevel@tonic-gate static int attempt_delete_initcred(krb5_module_data_t *); 567c478bd9Sstevel@tonic-gate static krb5_error_code krb5_renew_tgt(krb5_module_data_t *, krb5_principal, 577c478bd9Sstevel@tonic-gate krb5_principal, int); 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate extern uint_t kwarn_add_warning(char *, int); 607c478bd9Sstevel@tonic-gate extern uint_t kwarn_del_warning(char *); 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* 637c478bd9Sstevel@tonic-gate * pam_sm_setcred 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate int 667c478bd9Sstevel@tonic-gate pam_sm_setcred( 677c478bd9Sstevel@tonic-gate pam_handle_t *pamh, 687c478bd9Sstevel@tonic-gate int flags, 697c478bd9Sstevel@tonic-gate int argc, 707c478bd9Sstevel@tonic-gate const char **argv) 717c478bd9Sstevel@tonic-gate { 727c478bd9Sstevel@tonic-gate int i; 737c478bd9Sstevel@tonic-gate int err = 0; 747c478bd9Sstevel@tonic-gate int debug = 0; 757c478bd9Sstevel@tonic-gate krb5_module_data_t *kmd = NULL; 763bfb48feSsemery char *user = NULL; 777c478bd9Sstevel@tonic-gate krb5_repository_data_t *krb5_data = NULL; 787c478bd9Sstevel@tonic-gate pam_repository_t *rep_data = NULL; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 817c478bd9Sstevel@tonic-gate if (strcasecmp(argv[i], "debug") == 0) 827c478bd9Sstevel@tonic-gate debug = 1; 837c478bd9Sstevel@tonic-gate else if (strcasecmp(argv[i], "nowarn") == 0) 847c478bd9Sstevel@tonic-gate flags = flags | PAM_SILENT; 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate if (debug) 883bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 897c478bd9Sstevel@tonic-gate "PAM-KRB5 (setcred): start: nowarn = %d, flags = 0x%x", 907c478bd9Sstevel@tonic-gate flags & PAM_SILENT ? 1 : 0, flags); 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* make sure flags are valid */ 937c478bd9Sstevel@tonic-gate if (flags && 947c478bd9Sstevel@tonic-gate !(flags & PAM_ESTABLISH_CRED) && 957c478bd9Sstevel@tonic-gate !(flags & PAM_REINITIALIZE_CRED) && 967c478bd9Sstevel@tonic-gate !(flags & PAM_REFRESH_CRED) && 977c478bd9Sstevel@tonic-gate !(flags & PAM_DELETE_CRED) && 987c478bd9Sstevel@tonic-gate !(flags & PAM_SILENT)) { 993bfb48feSsemery __pam_log(LOG_AUTH | LOG_ERR, 1004a7ceb24Sjjj "PAM-KRB5 (setcred): illegal flag %d", flags); 1017c478bd9Sstevel@tonic-gate err = PAM_SYSTEM_ERR; 1027c478bd9Sstevel@tonic-gate goto out; 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate 1053bfb48feSsemery (void) pam_get_item(pamh, PAM_USER, (void**) &user); 1067c478bd9Sstevel@tonic-gate 1073bfb48feSsemery if (user == NULL || *user == '\0') 1083bfb48feSsemery return (PAM_USER_UNKNOWN); 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate if (pam_get_data(pamh, KRB5_DATA, (const void**)&kmd) != PAM_SUCCESS) { 1117c478bd9Sstevel@tonic-gate if (debug) { 1123bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 1137c478bd9Sstevel@tonic-gate "PAM-KRB5 (setcred): kmd get failed, kmd=0x%p", 1147c478bd9Sstevel@tonic-gate kmd); 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * User doesn't need to authenticate for PAM_REFRESH_CRED 1197c478bd9Sstevel@tonic-gate * or for PAM_DELETE_CRED 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate if (flags & (PAM_REFRESH_CRED|PAM_DELETE_CRED)) { 1223bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 1234a7ceb24Sjjj "PAM-KRB5 (setcred): inst kmd structure"); 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate kmd = calloc(1, sizeof (krb5_module_data_t)); 1267c478bd9Sstevel@tonic-gate 12747fc6f3cSsemery if (kmd == NULL) 12847fc6f3cSsemery return (PAM_BUF_ERR); 12947fc6f3cSsemery 13047fc6f3cSsemery 13147fc6f3cSsemery /* 13247fc6f3cSsemery * Need to initialize auth_status here to 13347fc6f3cSsemery * PAM_AUTHINFO_UNAVAIL else there is a false positive 13447fc6f3cSsemery * of PAM_SUCCESS. 13547fc6f3cSsemery */ 13647fc6f3cSsemery kmd->auth_status = PAM_AUTHINFO_UNAVAIL; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate if ((err = pam_set_data(pamh, KRB5_DATA, 1394a7ceb24Sjjj kmd, &krb5_cleanup)) != PAM_SUCCESS) { 1407c478bd9Sstevel@tonic-gate free(kmd); 1417c478bd9Sstevel@tonic-gate return (PAM_SYSTEM_ERR); 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate } else { 1443441f6a1Ssemery /* 1453441f6a1Ssemery * This could mean that we are not the account authority 1463441f6a1Ssemery * for the authenticated user. Therefore we should 1473441f6a1Ssemery * return PAM_IGNORE in order to not affect the 1483441f6a1Ssemery * login process of said user. 1493441f6a1Ssemery */ 1503441f6a1Ssemery err = PAM_IGNORE; 1513441f6a1Ssemery goto out; 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate } else { /* pam_get_data success */ 1557c478bd9Sstevel@tonic-gate if (kmd == NULL) { 1567c478bd9Sstevel@tonic-gate if (debug) { 1573bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 1587c478bd9Sstevel@tonic-gate "PAM-KRB5 (setcred): kmd structure" 1597c478bd9Sstevel@tonic-gate " gotten but is NULL for user %s", user); 1607c478bd9Sstevel@tonic-gate } 16147fc6f3cSsemery err = PAM_SYSTEM_ERR; 1627c478bd9Sstevel@tonic-gate goto out; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if (debug) 1663bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 1677c478bd9Sstevel@tonic-gate "PAM-KRB5 (setcred): kmd auth_status: %s", 1687c478bd9Sstevel@tonic-gate pam_strerror(pamh, kmd->auth_status)); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * pam_auth has set status to ignore, so we also return ignore 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate if (kmd->auth_status == PAM_IGNORE) { 1747c478bd9Sstevel@tonic-gate err = PAM_IGNORE; 1757c478bd9Sstevel@tonic-gate goto out; 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate kmd->debug = debug; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * User must have passed pam_authenticate() 1837c478bd9Sstevel@tonic-gate * in order to use PAM_ESTABLISH_CRED or PAM_REINITIALIZE_CRED 1847c478bd9Sstevel@tonic-gate */ 1857c478bd9Sstevel@tonic-gate if ((flags & (PAM_ESTABLISH_CRED|PAM_REINITIALIZE_CRED)) && 1867c478bd9Sstevel@tonic-gate (kmd->auth_status != PAM_SUCCESS)) { 1877c478bd9Sstevel@tonic-gate if (kmd->debug) 1883bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 1897c478bd9Sstevel@tonic-gate "PAM-KRB5 (setcred): unable to " 1907c478bd9Sstevel@tonic-gate "setcreds, not authenticated!"); 1917c478bd9Sstevel@tonic-gate return (PAM_CRED_UNAVAIL); 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate /* 1957c478bd9Sstevel@tonic-gate * We cannot assume that kmd->kcontext being non-NULL 1967c478bd9Sstevel@tonic-gate * means it is valid. Other pam_krb5 mods may have 1977c478bd9Sstevel@tonic-gate * freed it but not reset it to NULL. 1987c478bd9Sstevel@tonic-gate * Log a message when debugging to track down memory 1997c478bd9Sstevel@tonic-gate * leaks. 2007c478bd9Sstevel@tonic-gate */ 2017c478bd9Sstevel@tonic-gate if (kmd->kcontext != NULL && kmd->debug) 2023bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 2034a7ceb24Sjjj "PAM-KRB5 (setcred): kcontext != NULL, " 2044a7ceb24Sjjj "possible memory leak."); 2057c478bd9Sstevel@tonic-gate 2063bfb48feSsemery /* 2073bfb48feSsemery * Use the authenticated and validated user, if applicable. 2083bfb48feSsemery */ 2093bfb48feSsemery if (kmd->user != NULL) 2103bfb48feSsemery user = kmd->user; 2113bfb48feSsemery 2127c478bd9Sstevel@tonic-gate /* 2137c478bd9Sstevel@tonic-gate * If auth was short-circuited we will not have anything to 2147c478bd9Sstevel@tonic-gate * renew, so just return here. 2157c478bd9Sstevel@tonic-gate */ 2163bfb48feSsemery (void) pam_get_item(pamh, PAM_REPOSITORY, (void **)&rep_data); 2173bfb48feSsemery 2187c478bd9Sstevel@tonic-gate if (rep_data != NULL) { 2197c478bd9Sstevel@tonic-gate if (strcmp(rep_data->type, KRB5_REPOSITORY_NAME) != 0) { 2207c478bd9Sstevel@tonic-gate if (debug) 2213bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 2224a7ceb24Sjjj "PAM-KRB5 (setcred): wrong" 2234a7ceb24Sjjj "repository found (%s), returning " 2244a7ceb24Sjjj "PAM_IGNORE", rep_data->type); 2257c478bd9Sstevel@tonic-gate return (PAM_IGNORE); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate if (rep_data->scope_len == sizeof (krb5_repository_data_t)) { 2287c478bd9Sstevel@tonic-gate krb5_data = (krb5_repository_data_t *)rep_data->scope; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate if (krb5_data->flags == 2314a7ceb24Sjjj SUNW_PAM_KRB5_ALREADY_AUTHENTICATED && 2324a7ceb24Sjjj krb5_data->principal != NULL && 2334a7ceb24Sjjj strlen(krb5_data->principal)) { 2347c478bd9Sstevel@tonic-gate if (debug) 2353bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 2364a7ceb24Sjjj "PAM-KRB5 (setcred): " 2374a7ceb24Sjjj "Principal %s already " 2384a7ceb24Sjjj "authenticated, " 2394a7ceb24Sjjj "cannot setcred", 2404a7ceb24Sjjj krb5_data->principal); 2417c478bd9Sstevel@tonic-gate return (PAM_SUCCESS); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate if (flags & PAM_REINITIALIZE_CRED) 2477c478bd9Sstevel@tonic-gate err = attempt_refresh_cred(kmd, user, PAM_REINITIALIZE_CRED); 2487c478bd9Sstevel@tonic-gate else if (flags & PAM_REFRESH_CRED) 2497c478bd9Sstevel@tonic-gate err = attempt_refresh_cred(kmd, user, PAM_REFRESH_CRED); 2507c478bd9Sstevel@tonic-gate else if (flags & PAM_DELETE_CRED) 2517c478bd9Sstevel@tonic-gate err = attempt_delete_initcred(kmd); 2527c478bd9Sstevel@tonic-gate else { 2537c478bd9Sstevel@tonic-gate /* 2547c478bd9Sstevel@tonic-gate * Default case: PAM_ESTABLISH_CRED 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate err = attempt_refresh_cred(kmd, user, PAM_ESTABLISH_CRED); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2593bfb48feSsemery if (err != PAM_SUCCESS) 2603bfb48feSsemery __pam_log(LOG_AUTH | LOG_ERR, 2617c478bd9Sstevel@tonic-gate "PAM-KRB5 (setcred): pam_setcred failed " 2627c478bd9Sstevel@tonic-gate "for %s (%s).", user, pam_strerror(pamh, err)); 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate out: 2657c478bd9Sstevel@tonic-gate if (kmd && kmd->kcontext) { 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * free 'kcontext' field if it is allocated, 2687c478bd9Sstevel@tonic-gate * kcontext is local to the operation being performed 2697c478bd9Sstevel@tonic-gate * not considered global to the entire pam module. 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate krb5_free_context(kmd->kcontext); 2727c478bd9Sstevel@tonic-gate kmd->kcontext = NULL; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * 'kmd' is not freed here, it is handled in krb5_cleanup 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate if (debug) 2793bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 2807c478bd9Sstevel@tonic-gate "PAM-KRB5 (setcred): end: %s", 2817c478bd9Sstevel@tonic-gate pam_strerror(pamh, err)); 2827c478bd9Sstevel@tonic-gate return (err); 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate static int 2867c478bd9Sstevel@tonic-gate attempt_refresh_cred( 2877c478bd9Sstevel@tonic-gate krb5_module_data_t *kmd, 2887c478bd9Sstevel@tonic-gate char *user, 2897c478bd9Sstevel@tonic-gate int flag) 2907c478bd9Sstevel@tonic-gate { 2917c478bd9Sstevel@tonic-gate krb5_principal me; 2927c478bd9Sstevel@tonic-gate krb5_principal server; 2937c478bd9Sstevel@tonic-gate krb5_error_code code; 2947c478bd9Sstevel@tonic-gate char kuser[2*MAXHOSTNAMELEN]; 2957c478bd9Sstevel@tonic-gate krb5_data tgtname = { 2967c478bd9Sstevel@tonic-gate 0, 2977c478bd9Sstevel@tonic-gate KRB5_TGS_NAME_SIZE, 2987c478bd9Sstevel@tonic-gate KRB5_TGS_NAME 2997c478bd9Sstevel@tonic-gate }; 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate /* Create a new context here. */ 3027c478bd9Sstevel@tonic-gate if (krb5_init_context(&kmd->kcontext) != 0) { 3037c478bd9Sstevel@tonic-gate if (kmd->debug) 3043bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 3057c478bd9Sstevel@tonic-gate "PAM-KRB5 (setcred): unable to " 3067c478bd9Sstevel@tonic-gate "initialize krb5 context"); 3077c478bd9Sstevel@tonic-gate return (PAM_SYSTEM_ERR); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate if (krb5_cc_default(kmd->kcontext, &kmd->ccache) != 0) { 3113bfb48feSsemery return (PAM_SYSTEM_ERR); 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate if ((code = get_kmd_kuser(kmd->kcontext, (const char *)user, kuser, 3154a7ceb24Sjjj 2*MAXHOSTNAMELEN)) != 0) { 3167c478bd9Sstevel@tonic-gate return (code); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if (krb5_parse_name(kmd->kcontext, kuser, &me) != 0) { 3203bfb48feSsemery return (PAM_SYSTEM_ERR); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate if (code = krb5_build_principal_ext(kmd->kcontext, &server, 3244a7ceb24Sjjj krb5_princ_realm(kmd->kcontext, me)->length, 3254a7ceb24Sjjj krb5_princ_realm(kmd->kcontext, me)->data, 3264a7ceb24Sjjj tgtname.length, tgtname.data, 3274a7ceb24Sjjj krb5_princ_realm(kmd->kcontext, me)->length, 3284a7ceb24Sjjj krb5_princ_realm(kmd->kcontext, me)->data, 0)) { 3293bfb48feSsemery krb5_free_principal(kmd->kcontext, me); 3303bfb48feSsemery return (PAM_SYSTEM_ERR); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate code = krb5_renew_tgt(kmd, me, server, flag); 3347c478bd9Sstevel@tonic-gate 3353bfb48feSsemery krb5_free_principal(kmd->kcontext, server); 3363bfb48feSsemery krb5_free_principal(kmd->kcontext, me); 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate if (code) { 3393bfb48feSsemery if (kmd->debug) 3403bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 3414a7ceb24Sjjj "PAM-KRB5(setcred): krb5_renew_tgt() " 3424a7ceb24Sjjj "failed: %s", error_message((errcode_t)code)); 3437c478bd9Sstevel@tonic-gate return (PAM_CRED_ERR); 3447c478bd9Sstevel@tonic-gate } else { 3457c478bd9Sstevel@tonic-gate return (PAM_SUCCESS); 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* 3507c478bd9Sstevel@tonic-gate * This code will update the credential matching "server" in the user's 3517c478bd9Sstevel@tonic-gate * credential cache. The flag may be set to one of: 35247fc6f3cSsemery * PAM_ESTABLISH_CRED - If we have new credentials then create a new cred cache 35347fc6f3cSsemery * with these credentials else return failure. 35447fc6f3cSsemery * PAM_REINITIALIZE_CRED - Destroy current cred cache and create a new one. 35547fc6f3cSsemery * PAM_REFRESH_CRED - If we have new credentials then create a new cred cache 35647fc6f3cSsemery * with these credentials else attempt to renew the credentials. 35747fc6f3cSsemery * 35847fc6f3cSsemery * Note for the PAM_ESTABLISH_CRED and PAM_REFRESH_CRED flags that if a new 35947fc6f3cSsemery * credential does exist from the previous auth pass then this will overwrite 36047fc6f3cSsemery * any existing credentials in the credential cache. 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate static krb5_error_code 3637c478bd9Sstevel@tonic-gate krb5_renew_tgt( 3647c478bd9Sstevel@tonic-gate krb5_module_data_t *kmd, 3657c478bd9Sstevel@tonic-gate krb5_principal me, 3667c478bd9Sstevel@tonic-gate krb5_principal server, 3677c478bd9Sstevel@tonic-gate int flag) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate krb5_error_code retval; 3707c478bd9Sstevel@tonic-gate krb5_creds creds; 3711dac1dbeSgtb krb5_creds *renewed_cred = NULL; 3727c478bd9Sstevel@tonic-gate char *client_name = NULL; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate #define my_creds (kmd->initcreds) 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate if ((flag != PAM_REFRESH_CRED) && 3774a7ceb24Sjjj (flag != PAM_REINITIALIZE_CRED) && 3784a7ceb24Sjjj (flag != PAM_ESTABLISH_CRED)) 3794a7ceb24Sjjj return (KRB5KRB_ERR_GENERIC); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* this is needed only for the ktkt_warnd */ 3823bfb48feSsemery if ((retval = krb5_unparse_name(kmd->kcontext, me, &client_name)) != 0) 3833bfb48feSsemery return (retval); 3847c478bd9Sstevel@tonic-gate 3851dac1dbeSgtb (void) memset(&creds, 0, sizeof (krb5_creds)); 3867c478bd9Sstevel@tonic-gate if ((retval = krb5_copy_principal(kmd->kcontext, 3874a7ceb24Sjjj server, &creds.server))) { 3887c478bd9Sstevel@tonic-gate if (kmd->debug) 3893bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 3904a7ceb24Sjjj "PAM-KRB5 (setcred): krb5_copy_principal " 3914a7ceb24Sjjj "failed: %s", 3924a7ceb24Sjjj error_message((errcode_t)retval)); 3937c478bd9Sstevel@tonic-gate goto cleanup_creds; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* obtain ticket & session key */ 3977c478bd9Sstevel@tonic-gate retval = krb5_cc_get_principal(kmd->kcontext, 3984a7ceb24Sjjj kmd->ccache, &creds.client); 3997c478bd9Sstevel@tonic-gate if (retval && (kmd->debug)) 4003bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 4014a7ceb24Sjjj "PAM-KRB5 (setcred): User not in cred " 4024a7ceb24Sjjj "cache (%s)", error_message((errcode_t)retval)); 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate if ((retval == KRB5_FCC_NOFILE) && 4054a7ceb24Sjjj (flag & (PAM_ESTABLISH_CRED|PAM_REINITIALIZE_CRED))) { 4067c478bd9Sstevel@tonic-gate /* 4077c478bd9Sstevel@tonic-gate * Create a fresh ccache, and store the credentials 4087c478bd9Sstevel@tonic-gate * we got from pam_authenticate() 4097c478bd9Sstevel@tonic-gate */ 4107c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_initialize(kmd->kcontext, 4114a7ceb24Sjjj kmd->ccache, me)) != 0) { 4123bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 4134a7ceb24Sjjj "PAM-KRB5 (setcred): krb5_cc_initialize " 4144a7ceb24Sjjj "failed: %s", 4154a7ceb24Sjjj error_message((errcode_t)retval)); 4167c478bd9Sstevel@tonic-gate goto cleanup_creds; 4177c478bd9Sstevel@tonic-gate } else if ((retval = krb5_cc_store_cred(kmd->kcontext, 4184a7ceb24Sjjj kmd->ccache, &my_creds)) != 0) { 4193bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 4204a7ceb24Sjjj "PAM-KRB5 (setcred): krb5_cc_store_cred " 4214a7ceb24Sjjj "failed: %s", 4224a7ceb24Sjjj error_message((errcode_t)retval)); 4237c478bd9Sstevel@tonic-gate goto cleanup_creds; 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate } else if (retval) { 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * We failed to get the user's credentials. 4287c478bd9Sstevel@tonic-gate * This might be due to permission error on the cache, 4297c478bd9Sstevel@tonic-gate * or maybe we are looking in the wrong cache file! 4307c478bd9Sstevel@tonic-gate */ 4313bfb48feSsemery __pam_log(LOG_AUTH | LOG_ERR, 4324a7ceb24Sjjj "PAM-KRB5 (setcred): Cannot find creds" 4334a7ceb24Sjjj " for %s (%s)", 4344a7ceb24Sjjj client_name ? client_name : "(unknown)", 4354a7ceb24Sjjj error_message((errcode_t)retval)); 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate } else if (flag & PAM_REINITIALIZE_CRED) { 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * This destroys the credential cache, and stores a new 4407c478bd9Sstevel@tonic-gate * krbtgt with updated startime, endtime and renewable 4417c478bd9Sstevel@tonic-gate * lifetime. 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate creds.times.starttime = my_creds.times.starttime; 4447c478bd9Sstevel@tonic-gate creds.times.endtime = my_creds.times.endtime; 4457c478bd9Sstevel@tonic-gate creds.times.renew_till = my_creds.times.renew_till; 4467c478bd9Sstevel@tonic-gate if ((retval = krb5_get_credentials_renew(kmd->kcontext, 0, 4474a7ceb24Sjjj kmd->ccache, &creds, &renewed_cred))) { 4487c478bd9Sstevel@tonic-gate if (kmd->debug) 4494a7ceb24Sjjj __pam_log(LOG_AUTH | LOG_DEBUG, 4504a7ceb24Sjjj "PAM-KRB5 (setcred): krb5_get_credentials", 4514a7ceb24Sjjj "_renew(reinitialize) failed: %s", 4524a7ceb24Sjjj error_message((errcode_t)retval)); 4537c478bd9Sstevel@tonic-gate /* perhaps the tgt lifetime has expired */ 4547c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_initialize(kmd->kcontext, 4554a7ceb24Sjjj kmd->ccache, me)) != 0) { 4567c478bd9Sstevel@tonic-gate goto cleanup_creds; 4577c478bd9Sstevel@tonic-gate } else if ((retval = krb5_cc_store_cred(kmd->kcontext, 4584a7ceb24Sjjj kmd->ccache, &my_creds)) != 0) { 4597c478bd9Sstevel@tonic-gate goto cleanup_creds; 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate } else { 4637c478bd9Sstevel@tonic-gate /* 46447fc6f3cSsemery * Default credentials already exist, update them if possible. 4657c478bd9Sstevel@tonic-gate * We got here either with the ESTABLISH or REFRESH flag. 4667c478bd9Sstevel@tonic-gate * 4677c478bd9Sstevel@tonic-gate * Rules: 46847fc6f3cSsemery * - If the prior auth pass was successful then store the new 46947fc6f3cSsemery * credentials in the cache, regardless of which flag. 4707c478bd9Sstevel@tonic-gate * 47147fc6f3cSsemery * - Else if REFRESH flag is used and there are no new 47247fc6f3cSsemery * credentials then attempt to refresh the existing credentials. 47347fc6f3cSsemery * 47447fc6f3cSsemery * - Note, refresh will not work if "R" flag is not set in 47547fc6f3cSsemery * original credential. We don't want to 2nd guess the 47647fc6f3cSsemery * intention of the person who created the existing credential. 4777c478bd9Sstevel@tonic-gate */ 47847fc6f3cSsemery if ((kmd->auth_status != PAM_SUCCESS) && 47947fc6f3cSsemery (flag & PAM_REFRESH_CRED)) { 4807c478bd9Sstevel@tonic-gate /* 4817c478bd9Sstevel@tonic-gate * If we only wanted to refresh the creds but failed 4827c478bd9Sstevel@tonic-gate * due to expiration, lack of "R" flag, or other 48347fc6f3cSsemery * problems, return an error. 4847c478bd9Sstevel@tonic-gate */ 48547fc6f3cSsemery if (retval = krb5_get_credentials_renew(kmd->kcontext, 48647fc6f3cSsemery 0, kmd->ccache, &creds, &renewed_cred)) { 48747fc6f3cSsemery if (kmd->debug) 48847fc6f3cSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 48947fc6f3cSsemery "PAM-KRB5 (setcred): " 49047fc6f3cSsemery "krb5_get_credentials" 49147fc6f3cSsemery "_renew(update) failed: %s", 49247fc6f3cSsemery error_message((errcode_t)retval)); 4937c478bd9Sstevel@tonic-gate goto cleanup_creds; 4947c478bd9Sstevel@tonic-gate } 49547fc6f3cSsemery } else { 49647fc6f3cSsemery /* 49747fc6f3cSsemery * If we have new creds, add them to the cache. 49847fc6f3cSsemery */ 4997c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_initialize(kmd->kcontext, 5004a7ceb24Sjjj kmd->ccache, me)) != 0) { 5017c478bd9Sstevel@tonic-gate goto cleanup_creds; 50247fc6f3cSsemery } else if ((retval = krb5_cc_store_cred(kmd->kcontext, 50347fc6f3cSsemery kmd->ccache, &my_creds)) != 0) { 5044a7ceb24Sjjj goto cleanup_creds; 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate cleanup_creds: 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate if ((retval == 0) && (client_name != NULL)) { 5127c478bd9Sstevel@tonic-gate /* 5137c478bd9Sstevel@tonic-gate * Credential update was successful! 5147c478bd9Sstevel@tonic-gate * 5157c478bd9Sstevel@tonic-gate * We now chown the ccache to the appropriate uid/gid 5167c478bd9Sstevel@tonic-gate * combination, if its a FILE based ccache. 5177c478bd9Sstevel@tonic-gate */ 518*d80035c5Sps if (!kmd->env || strstr(kmd->env, "FILE:")) { 5197c478bd9Sstevel@tonic-gate uid_t uuid; 5207c478bd9Sstevel@tonic-gate gid_t ugid; 5217c478bd9Sstevel@tonic-gate char *username = NULL, *tmpname = NULL; 5227c478bd9Sstevel@tonic-gate char *filepath = NULL; 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate username = strdup(client_name); 5254a7ceb24Sjjj if (username == NULL) { 5264a7ceb24Sjjj __pam_log(LOG_AUTH | LOG_ERR, 5274a7ceb24Sjjj "PAM-KRB5 (setcred): Out of memory"); 5284a7ceb24Sjjj retval = KRB5KRB_ERR_GENERIC; 5294a7ceb24Sjjj goto error; 5304a7ceb24Sjjj } 5317c478bd9Sstevel@tonic-gate if ((tmpname = strchr(username, '@'))) 5327c478bd9Sstevel@tonic-gate *tmpname = '\0'; 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate if (get_pw_uid(username, &uuid) == 0 || 5357c478bd9Sstevel@tonic-gate get_pw_gid(username, &ugid) == 0) { 5363bfb48feSsemery __pam_log(LOG_AUTH | LOG_ERR, 5373bfb48feSsemery "PAM-KRB5 (setcred): Unable to " 5387c478bd9Sstevel@tonic-gate "find matching uid/gid pair for user `%s'", 5397c478bd9Sstevel@tonic-gate username); 5401dac1dbeSgtb retval = KRB5KRB_ERR_GENERIC; 5411dac1dbeSgtb goto error; 5427c478bd9Sstevel@tonic-gate } 543*d80035c5Sps 544*d80035c5Sps if (!kmd->env) { 545*d80035c5Sps char buffer[512]; 546*d80035c5Sps 547*d80035c5Sps if (snprintf(buffer, sizeof (buffer), 548*d80035c5Sps "%s=FILE:/tmp/krb5cc_%d", KRB5_ENV_CCNAME, 549*d80035c5Sps (int)uuid) >= sizeof (buffer)) { 550*d80035c5Sps retval = KRB5KRB_ERR_GENERIC; 551*d80035c5Sps goto error; 552*d80035c5Sps } 553*d80035c5Sps 554*d80035c5Sps /* 555*d80035c5Sps * We MUST copy this to the heap for the putenv 556*d80035c5Sps * to work! 557*d80035c5Sps */ 558*d80035c5Sps kmd->env = strdup(buffer); 559*d80035c5Sps if (!kmd->env) { 560*d80035c5Sps retval = ENOMEM; 561*d80035c5Sps goto error; 562*d80035c5Sps } else { 563*d80035c5Sps if (putenv(kmd->env)) { 564*d80035c5Sps retval = ENOMEM; 565*d80035c5Sps goto error; 566*d80035c5Sps } 567*d80035c5Sps } 568*d80035c5Sps } 569*d80035c5Sps 5707c478bd9Sstevel@tonic-gate if (!(filepath = strchr(kmd->env, ':')) || 5717c478bd9Sstevel@tonic-gate !(filepath+1)) { 5723bfb48feSsemery __pam_log(LOG_AUTH | LOG_ERR, 5734a7ceb24Sjjj "PAM-KRB5 (setcred): Invalid pathname " 5744a7ceb24Sjjj "for credential cache of user `%s'", 5754a7ceb24Sjjj username); 5761dac1dbeSgtb retval = KRB5KRB_ERR_GENERIC; 5771dac1dbeSgtb goto error; 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate if (chown(filepath+1, uuid, ugid)) { 5807c478bd9Sstevel@tonic-gate if (kmd->debug) 5813bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 5827c478bd9Sstevel@tonic-gate "PAM-KRB5 (setcred): chown to user " 5837c478bd9Sstevel@tonic-gate "`%s' failed for FILE=%s", 5847c478bd9Sstevel@tonic-gate username, filepath); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate free(username); 5887c478bd9Sstevel@tonic-gate } 5891dac1dbeSgtb } 5907c478bd9Sstevel@tonic-gate 5911dac1dbeSgtb error: 5921dac1dbeSgtb if (retval == 0) { 5931dac1dbeSgtb krb5_timestamp endtime; 5941dac1dbeSgtb 5951dac1dbeSgtb if (renewed_cred && renewed_cred->times.endtime != 0) 5961dac1dbeSgtb endtime = renewed_cred->times.endtime; 5971dac1dbeSgtb else 5981dac1dbeSgtb endtime = my_creds.times.endtime; 5991dac1dbeSgtb 6001dac1dbeSgtb if (kmd->debug) 6011dac1dbeSgtb __pam_log(LOG_AUTH | LOG_DEBUG, 6024a7ceb24Sjjj "PAM-KRB5 (setcred): delete/add warning"); 6031dac1dbeSgtb 6041dac1dbeSgtb kwarn_del_warning(client_name); 6051dac1dbeSgtb if (kwarn_add_warning(client_name, endtime) != 0) { 6061dac1dbeSgtb __pam_log(LOG_AUTH | LOG_NOTICE, 6074a7ceb24Sjjj "PAM-KRB5 (setcred): kwarn_add_warning" 6084a7ceb24Sjjj " failed: ktkt_warnd(1M) down?"); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate } 6111dac1dbeSgtb 6121dac1dbeSgtb if (renewed_cred != NULL) 6131dac1dbeSgtb krb5_free_creds(kmd->kcontext, renewed_cred); 6141dac1dbeSgtb 6157c478bd9Sstevel@tonic-gate if (client_name != NULL) 6167c478bd9Sstevel@tonic-gate free(client_name); 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate krb5_free_cred_contents(kmd->kcontext, &creds); 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate return (retval); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* 6247c478bd9Sstevel@tonic-gate * Delete the user's credentials for this session 6257c478bd9Sstevel@tonic-gate */ 6267c478bd9Sstevel@tonic-gate static int 6277c478bd9Sstevel@tonic-gate attempt_delete_initcred(krb5_module_data_t *kmd) 6287c478bd9Sstevel@tonic-gate { 6297c478bd9Sstevel@tonic-gate if (kmd == NULL) 6303bfb48feSsemery return (PAM_SUCCESS); 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate if (kmd->debug) { 6333bfb48feSsemery __pam_log(LOG_AUTH | LOG_DEBUG, 6344a7ceb24Sjjj "PAM-KRB5 (setcred): deleting user's " 6354a7ceb24Sjjj "credentials (initcreds)"); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate krb5_free_cred_contents(kmd->kcontext, &kmd->initcreds); 6387c478bd9Sstevel@tonic-gate (void) memset((char *)&kmd->initcreds, 0, sizeof (krb5_creds)); 6397c478bd9Sstevel@tonic-gate kmd->auth_status = PAM_AUTHINFO_UNAVAIL; 6403bfb48feSsemery return (PAM_SUCCESS); 6417c478bd9Sstevel@tonic-gate } 642