int _pam_krb5_sly_maybe_refresh(pam_handle_t *pamh, int flags, int argc, PAM_KRB5_MAYBE_CONST char **argv) { PAM_KRB5_MAYBE_CONST char *user; krb5_context ctx; struct _pam_krb5_options *options; struct _pam_krb5_user_info *userinfo; struct _pam_krb5_stash *stash; struct stat st; int i, retval, stored; uid_t uid; gid_t gid; const char *v5ccname, *v5filename, *v4tktfile; #ifdef TKT_ROOT char v4tktfilebuf[PATH_MAX]; #endif /* Inexpensive checks. */ switch (_pam_krb5_sly_looks_unsafe()) { case 0: /* nothing: everything's okay */ break; case 1: warn("won't refresh credentials while running under sudo"); return PAM_SERVICE_ERR; break; case 2: warn("won't refresh credentials while running setuid"); return PAM_SERVICE_ERR; break; case 3: warn("won't refresh credentials while running setgid"); return PAM_SERVICE_ERR; break; default: warn("not safe to refresh credentials"); return PAM_SERVICE_ERR; break; } /* Initialize Kerberos. */ if (_pam_krb5_init_ctx(&ctx, argc, argv) != 0) { warn("error initializing Kerberos"); return PAM_SERVICE_ERR; } /* Get the user's name. */ i = pam_get_user(pamh, &user, NULL); if ((i != PAM_SUCCESS) || (user == NULL)) { warn("could not identify user name"); krb5_free_context(ctx); return i; } /* Read our options. */ options = _pam_krb5_options_init(pamh, argc, argv, ctx); if (options == NULL) { warn("error parsing options (shouldn't happen)"); krb5_free_context(ctx); return PAM_SERVICE_ERR; } if (options->debug) { debug("called to update credentials for '%s'", user); } /* Get information about the user and the user's principal name. */ userinfo = _pam_krb5_user_info_init(ctx, user, options); if (userinfo == NULL) { if (options->ignore_unknown_principals) { retval = PAM_IGNORE; } else { warn("error getting information about '%s' " "(shouldn't happen)", user); retval = PAM_USER_UNKNOWN; } _pam_krb5_options_free(pamh, ctx, options); krb5_free_context(ctx); return retval; } if ((options->user_check) && (options->minimum_uid != (uid_t)-1) && (userinfo->uid < options->minimum_uid)) { if (options->debug) { debug("ignoring '%s' -- uid below minimum", user); } _pam_krb5_user_info_free(ctx, userinfo); _pam_krb5_options_free(pamh, ctx, options); krb5_free_context(ctx); return PAM_IGNORE; } /* Get the stash for this user. */ stash = _pam_krb5_stash_get(pamh, user, userinfo, options); if (stash == NULL) { warn("error retrieving stash for '%s' (shouldn't happen)", user); _pam_krb5_user_info_free(ctx, userinfo); _pam_krb5_options_free(pamh, ctx, options); krb5_free_context(ctx); return PAM_SERVICE_ERR; } retval = PAM_SERVICE_ERR; /* Save credentials in the right places. */ v5ccname = krb5_cc_default_name(ctx); v5filename = NULL; if (v5ccname == NULL) { /* This should never happen, but all we can do is tell libpam * to ignore us. We have nothing to do. */ if (options->debug) { debug("ignoring '%s' -- no default ccache name", user); } retval = PAM_IGNORE; } else { if (strncmp(v5ccname, "FILE:", 5) == 0) { v5filename = v5ccname + 5; if (options->debug) { debug("ccache is a file named '%s'", v5filename); } } else { if (options->debug) { debug("ccache '%s' is not a file", v5ccname); } } } stored = 0; uid = options->user_check ? userinfo->uid : getuid(); gid = options->user_check ? userinfo->gid : getgid(); if (v5_creds_check_initialized(ctx, &stash->v5creds) == 0) { if (v5filename != NULL) { /* Check the permissions on the ccache file. */ if ((access(v5filename, R_OK | W_OK) == 0) && (lstat(v5filename, &st) == 0)) { if (S_ISREG(st.st_mode) && ((st.st_mode & S_IRWXG) == 0) && ((st.st_mode & S_IRWXO) == 0) && (st.st_uid == uid) && (st.st_gid == gid)) { if (options->debug) { debug("updating ccache '%s' " "for '%s'", v5ccname, user); } retval = sly_v5(ctx, v5ccname, userinfo, stash); stored = (retval == PAM_SUCCESS); } else { if (options->debug) { debug("not updating '%s'", v5ccname); } retval = PAM_SUCCESS; } } else { if (errno == ENOENT) { /* We have nothing to do. */ retval = PAM_SUCCESS; } } } else { if (v5ccname != NULL) { /* Go ahead and update the current not-a-file * ccache. */ if (options->debug) { debug("updating ccache '%s' for '%s'", v5ccname, user); } retval = sly_v5(ctx, v5ccname, userinfo, stash); stored = (retval == PAM_SUCCESS); } } } else { if (options->debug) { debug("no credentials available to store in '%s'", v5ccname); } retval = PAM_SUCCESS; } v4tktfile = getenv("KRBTKFILE"); #ifdef TKT_ROOT if ((v4tktfile == NULL) && (options->user_check)) { snprintf(v4tktfilebuf, sizeof(v4tktfilebuf), "%s%ld", TKT_ROOT, (long) uid); v4tktfile = v4tktfilebuf; } #endif if ((stash->v4present) && (v4tktfile != NULL)) { if (access(v4tktfile, R_OK | W_OK) == 0) { if (lstat(v4tktfile, &st) == 0) { if (S_ISREG(st.st_mode) && ((st.st_mode & S_IRWXG) == 0) && ((st.st_mode & S_IRWXO) == 0) && (st.st_uid == uid) && (st.st_gid == gid)) { if (options->debug) { debug("updating ticket file " "'%s' for '%s'", v4tktfile, user); } sly_v4(ctx, v4tktfile, userinfo, stash); stored = 1; } else { if (options->debug) { debug("not updating '%s'", v4tktfile); } } } else { if (errno == ENOENT) { /* We have nothing to do. */ if (options->debug) { debug("no preexisting ticket " "file found"); } retval = PAM_SUCCESS; } } } else { /* Touch nothing. */ if (options->debug) { debug("unable to access preexisting ticket " "file"); } retval = PAM_SUCCESS; } } if (stored && !options->ignore_afs) { tokens_obtain(ctx, stash, options, userinfo, 0); } if (options->debug) { debug("_pam_krb5_sly_refresh returning %d (%s)", retval, pam_strerror(pamh, retval)); } _pam_krb5_user_info_free(ctx, userinfo); _pam_krb5_options_free(pamh, ctx, options); krb5_free_context(ctx); return retval; }
int v4_get_creds(krb5_context ctx, pam_handle_t *pamh, struct _pam_krb5_stash *stash, struct _pam_krb5_user_info *userinfo, struct _pam_krb5_options *options, char *password, int *result) { int i; #if defined(HAVE_KRB5_524_CONVERT_CREDS) || \ defined(HAVE_KRB524_CONVERT_CREDS_KDC) krb5_creds *v4_compat_creds, *in_creds; v4_compat_creds = NULL; if (options->v4_use_524) { if (options->debug) { debug("obtaining v4-compatible key"); } /* We need a DES-CBC-CRC v5 credential to convert to a proper v4 * credential. */ i = v5_get_creds_etype(ctx, userinfo, options, &stash->v5creds, ENCTYPE_DES_CBC_CRC, &v4_compat_creds); if (i == 0) { if (options->debug) { debug("obtained des-cbc-crc v5 creds"); } in_creds = v4_compat_creds; } else { if (options->debug) { debug("failed to obtain des-cbc-crc v5 creds: " "%d (%s)", i, v5_error_message(i)); } in_creds = NULL; if (v5_creds_check_initialized(ctx, &stash->v5creds) == 0) { krb5_copy_creds(ctx, &stash->v5creds, &in_creds); } } #ifdef HAVE_KRB5_524_CONVERT_CREDS if (options->debug) { debug("converting v5 creds to v4 creds (etype = %d)", in_creds ? v5_creds_get_etype(in_creds) : 0); } if ((in_creds != NULL) && (v5_creds_check_initialized(ctx, in_creds) == 0)) { i = krb5_524_convert_creds(ctx, in_creds, &stash->v4creds); if (i == 0) { if (options->debug) { debug("conversion succeeded"); } stash->v4present = 1; if (result) { *result = i; } krb5_free_creds(ctx, in_creds); return PAM_SUCCESS; } else { if (options->debug) { debug("conversion failed: %d (%s)", i, v5_error_message(i)); } } } #else #ifdef HAVE_KRB524_CONVERT_CREDS_KDC if (options->debug) { debug("converting v5 creds to v4 creds (etype = %d)", in_creds ? v5_creds_get_etype(in_creds) : 0); } if ((in_creds != NULL) && (v5_creds_check_initialized(ctx, in_creds) == 0)) { i = krb524_convert_creds_kdc(ctx, in_creds, &stash->v4creds); if (i == 0) { if (options->debug) { debug("conversion succeeded"); } stash->v4present = 1; if (result) { *result = i; } krb5_free_creds(ctx, in_creds); return PAM_SUCCESS; } else { if (options->debug) { debug("conversion failed: %d (%s)", i, v5_error_message(i)); } } } #endif #endif if ((in_creds != NULL) && (v5_creds_check_initialized(ctx, in_creds) == 0)) { krb5_free_creds(ctx, in_creds); } } #endif if ((password != NULL) && (options->v4_use_as_req)) { if (options->debug) { debug("attempting to obtain initial v4 creds"); } i = _pam_krb5_v4_init(ctx, stash, userinfo, options, KRB5_TGS_NAME, NULL, password, result); if (i == PAM_SUCCESS) { if (options->debug) { debug("initial v4 creds obtained"); } stash->v4present = 1; return PAM_SUCCESS; } if (options->debug) { debug("could not obtain initial v4 creds: %d (%s)", i, v5_error_message(i)); } } return PAM_AUTH_ERR; }