static int pamGssAcquireCred(pam_handle_t *pamh, int confFlags, gss_name_t userName, gss_buffer_t passwordBuf, gss_OID mech, gss_cred_id_t *cred) { int status; OM_uint32 major, minor; gss_OID_set_desc mechOids; #ifdef __APPLE__ CFDictionaryRef attributes = NULL; status = pam_get_data(pamh, CREDUI_ATTR_DATA, (const void **)&attributes); if (status == PAM_SUCCESS) return pamGssAcquireAaplInitialCred(pamh, userName, mech, attributes, cred); #endif /* __APPLE__ */ mechOids.count = 1; mechOids.elements = mech; major = gss_acquire_cred_with_password(&minor, userName, passwordBuf, GSS_C_INDEFINITE, &mechOids, GSS_C_INITIATE, cred, NULL, NULL); BAIL_ON_GSS_ERROR(major, minor); status = PAM_SUCCESS; cleanup: return status; }
DWORD LwKrb5SetThreadDefaultCachePath( IN PCSTR pszCachePath, OUT PSTR* ppszPreviousCachePath ) { DWORD dwError = 0; DWORD dwMajorStatus = 0; DWORD dwMinorStatus = 0; PSTR pszOrigCachePath = NULL; // Set the default for gss dwMajorStatus = gss_krb5_ccache_name( (OM_uint32 *)&dwMinorStatus, pszCachePath, (ppszPreviousCachePath) ? (const char**)&pszOrigCachePath : NULL); BAIL_ON_GSS_ERROR(dwError, dwMajorStatus, dwMinorStatus); LW_LOG_DEBUG("Switched gss krb5 credentials path from %s to %s", LW_SAFE_LOG_STRING(pszOrigCachePath), LW_SAFE_LOG_STRING(pszCachePath)); if (ppszPreviousCachePath) { if (!LW_IS_NULL_OR_EMPTY_STR(pszOrigCachePath)) { dwError = LwAllocateString(pszOrigCachePath, ppszPreviousCachePath); BAIL_ON_LW_ERROR(dwError); } else { *ppszPreviousCachePath = NULL; } } cleanup: return dwError; error: if (ppszPreviousCachePath) { *ppszPreviousCachePath = NULL; } goto cleanup; }
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { int status; OM_uint32 major, minor; gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; gss_OID mech = GSS_C_NO_OID; if (flags && (flags & PAM_ESTABLISH_CRED) == 0) return PAM_SUCCESS; status = pam_get_data(pamh, GSS_CRED_DATA, (const void **)&cred); BAIL_ON_PAM_ERROR(status); status = pam_get_data(pamh, GSS_MECH_DATA, (const void **)&mech); BAIL_ON_PAM_ERROR(status); major = gss_store_cred(&minor, cred, GSS_C_INITIATE, mech, 1, 1, NULL, NULL); BAIL_ON_GSS_ERROR(major, minor); cleanup: return status; }
int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { int status, confFlags = 0; char hostNameBufBuf[5 + MAXHOSTNAMELEN + 1] = "host@"; int isConvPasswordBuf = 0; OM_uint32 major, minor; gss_buffer_desc userNameBuf = GSS_C_EMPTY_BUFFER; gss_buffer_desc hostNameBuf = GSS_C_EMPTY_BUFFER; gss_buffer_desc passwordBuf = GSS_C_EMPTY_BUFFER; gss_name_t userName = GSS_C_NO_NAME; gss_name_t hostName = GSS_C_NO_NAME; gss_cred_id_t initiatorCred = GSS_C_NO_CREDENTIAL; gss_cred_id_t acceptorCred = GSS_C_NO_CREDENTIAL; gss_OID mech = &gss_spnego_mechanism_oid_desc; gss_OID_set_desc mechOids; confFlags = readConfFlags(argc, argv); status = readConfMechOid(argc, argv, &mech); BAIL_ON_PAM_ERROR(status); if (flags & PAM_DISALLOW_NULL_AUTHTOK) confFlags &= ~(FLAG_NULLOK); status = pam_get_user(pamh, (void *)&userNameBuf.value, NULL); BAIL_ON_PAM_ERROR(status); userNameBuf.length = strlen((char *)userNameBuf.value); major = gss_import_name(&minor, &userNameBuf, GSS_C_NT_USER_NAME, &userName); BAIL_ON_GSS_ERROR(major, minor); if (gethostname(&hostNameBufBuf[5], MAXHOSTNAMELEN) != 0) { status = PAM_SYSTEM_ERR; goto cleanup; } hostNameBuf.length = strlen(hostNameBufBuf); hostNameBuf.value = hostNameBufBuf; major = gss_import_name(&minor, &hostNameBuf, GSS_C_NT_HOSTBASED_SERVICE, &hostName); BAIL_ON_GSS_ERROR(major, minor); mechOids.count = 1; mechOids.elements = mech; major = gss_acquire_cred(&minor, hostName, GSS_C_INDEFINITE, &mechOids, GSS_C_ACCEPT, &acceptorCred, NULL, NULL); BAIL_ON_GSS_ERROR(major, minor); status = PAM_AUTHINFO_UNAVAIL; if (confFlags & (FLAG_USE_FIRST_PASS | FLAG_TRY_FIRST_PASS)) { status = pam_get_item(pamh, PAM_AUTHTOK, (void *)&passwordBuf.value); BAIL_ON_PAM_ERROR(status); if (passwordBuf.value != NULL) passwordBuf.length = strlen((char *)passwordBuf.value); status = pamGssAcquireCred(pamh, confFlags, userName, &passwordBuf, mech, &initiatorCred); if (status == PAM_SUCCESS) status = pamGssInitAcceptSecContext(pamh, confFlags, initiatorCred, acceptorCred, hostName, mech); if (confFlags & FLAG_USE_FIRST_PASS) BAIL_ON_PAM_ERROR(status); } if (status != PAM_SUCCESS) { isConvPasswordBuf = 1; if (flags & PAM_SILENT) goto cleanup; status = pamGssGetAuthTok(pamh, confFlags, &passwordBuf); BAIL_ON_PAM_ERROR(status); gss_release_cred(&minor, &initiatorCred); status = pamGssAcquireCred(pamh, confFlags, userName, &passwordBuf, mech, &initiatorCred); if (status == PAM_SUCCESS) status = pamGssInitAcceptSecContext(pamh, confFlags, initiatorCred, acceptorCred, hostName, mech); BAIL_ON_PAM_ERROR(status); } status = pam_set_data(pamh, GSS_CRED_DATA, initiatorCred, pamGssCleanupCred); BAIL_ON_PAM_ERROR(status); initiatorCred = GSS_C_NO_CREDENTIAL; cleanup: gss_release_name(&minor, &userName); gss_release_name(&minor, &hostName); gss_release_cred(&minor, &initiatorCred); gss_release_cred(&minor, &acceptorCred); #ifdef __APPLE__ if (mech != &gss_spnego_mechanism_oid_desc) gss_release_oid(&minor, &mech); #endif if (isConvPasswordBuf) { memset((char *)passwordBuf.value, 0, passwordBuf.length); free(passwordBuf.value); } return status; }
static int pamGssInitAcceptSecContext(pam_handle_t *pamh, int confFlags, gss_cred_id_t cred, gss_cred_id_t acceptorCred, gss_name_t hostName, gss_OID mech) { int status; OM_uint32 major, minor; gss_buffer_desc initiatorToken = GSS_C_EMPTY_BUFFER; gss_buffer_desc acceptorToken = GSS_C_EMPTY_BUFFER; gss_ctx_id_t initiatorContext = GSS_C_NO_CONTEXT; gss_ctx_id_t acceptorContext = GSS_C_NO_CONTEXT; gss_buffer_desc canonUserNameBuf = GSS_C_EMPTY_BUFFER; gss_name_t canonUserName = GSS_C_NO_NAME; gss_OID canonMech = GSS_C_NO_OID; OM_uint32 gssFlags; do { major = gss_init_sec_context(&minor, cred, &initiatorContext, hostName, mech, GSS_C_MUTUAL_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &acceptorToken, NULL, &initiatorToken, &gssFlags, NULL); gss_release_buffer(&minor, &acceptorToken); #ifdef GSS_S_PROMPTING_NEEDED if (major == GSS_S_PROMPTING_NEEDED) { status = PAM_CRED_INSUFFICIENT; goto cleanup; } #endif BAIL_ON_GSS_ERROR(major, minor); if (initiatorToken.length != 0) { major = gss_accept_sec_context(&minor, &acceptorContext, acceptorCred, &initiatorToken, GSS_C_NO_CHANNEL_BINDINGS, &canonUserName, &canonMech, &acceptorToken, NULL, NULL, NULL); gss_release_buffer(&minor, &initiatorToken); } BAIL_ON_GSS_ERROR(major, minor); } while (major == GSS_S_CONTINUE_NEEDED); BAIL_ON_GSS_ERROR(major, minor); if ((gssFlags & GSS_C_MUTUAL_FLAG) == 0) { status = PAM_PERM_DENIED; goto cleanup; } #ifndef __APPLE__ major = gss_localname(&minor, canonUserName, GSS_C_NO_OID, &canonUserNameBuf); if (major == GSS_S_COMPLETE) { status = pam_set_item(pamh, PAM_USER, canonUserNameBuf.value); BAIL_ON_PAM_ERROR(status); } else if (major != GSS_S_UNAVAILABLE) goto cleanup; #endif status = pam_set_data(pamh, GSS_NAME_DATA, canonUserName, pamGssCleanupName); BAIL_ON_PAM_ERROR(status); canonUserName = GSS_C_NO_NAME; status = pam_set_data(pamh, GSS_MECH_DATA, canonMech, pamGssCleanupMech); BAIL_ON_PAM_ERROR(status); canonMech = GSS_C_NO_OID; status = PAM_SUCCESS; cleanup: gss_release_name(&minor, &canonUserName); gss_release_buffer(&minor, &initiatorToken); gss_release_buffer(&minor, &acceptorToken); gss_delete_sec_context(&minor, &initiatorContext, NULL); gss_delete_sec_context(&minor, &acceptorContext, NULL); gss_release_buffer(&minor, &canonUserNameBuf); if (IGNORE_ERR_P(status, confFlags)) status = PAM_IGNORE; return status; }
DWORD LwKrb5CheckInitiatorCreds( IN PCSTR pszTargetPrincipalName, OUT PBOOLEAN pbNeedCredentials ) { DWORD dwError = 0; BOOLEAN bNeedCredentials = FALSE; OM_uint32 majorStatus = 0; OM_uint32 minorStatus = 0; gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT; gss_buffer_desc importName = GSS_C_EMPTY_BUFFER; gss_buffer_desc inputBufferDesc = GSS_C_EMPTY_BUFFER; gss_buffer_desc outputBufferDesc = GSS_C_EMPTY_BUFFER; OM_uint32 outputFlags = 0; gss_name_t targetName = GSS_C_NO_NAME; // discard const importName.value = (PSTR) pszTargetPrincipalName; importName.length = strlen(pszTargetPrincipalName); // discard const from GSS_KRB5_NT_PRINCIPAL_NAME majorStatus = gss_import_name(&minorStatus, &importName, (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME, &targetName); LW_GSS_LOG_IF_NOT_COMPLETE("gss_import_name", majorStatus, minorStatus); BAIL_ON_GSS_ERROR(dwError, majorStatus, minorStatus); // discard const from GSS_KRB5_NT_PRINCIPAL_NAME majorStatus = gss_init_sec_context(&minorStatus, NULL, &gssContext, targetName, (gss_OID) gss_mech_krb5, GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG, 0, NULL, &inputBufferDesc, NULL, &outputBufferDesc, &outputFlags, NULL); LW_GSS_LOG_IF_NOT_COMPLETE_OR_CONTINUE("gss_init_sec_context", majorStatus, minorStatus); // Need to cast below for correct comparison. Note that // some compilers do not catch the mismatch. if (((majorStatus == GSS_S_FAILURE) && ((minorStatus == (OM_uint32) KRB5KRB_AP_ERR_TKT_EXPIRED) || (minorStatus == (OM_uint32) KRB5KDC_ERR_NEVER_VALID) || (minorStatus == (OM_uint32) KRB5KDC_ERR_TGT_REVOKED))) || ((majorStatus == GSS_S_CRED_UNAVAIL) && (minorStatus == KG_EMPTY_CCACHE))) { // Need (new) Kerberos credentials because there are no // credentials or the credentials are expired or otherwise // invalid. bNeedCredentials = TRUE; goto error; } if (majorStatus == GSS_S_FAILURE) { switch (minorStatus) { case (OM_uint32) KRB5KRB_AP_ERR_SKEW: dwError = ERROR_TIME_SKEW; BAIL_ON_LW_ERROR(dwError); break; default: BAIL_ON_GSS_ERROR(dwError, majorStatus, minorStatus); break; } } if ((majorStatus != GSS_S_COMPLETE) && (majorStatus != GSS_S_CONTINUE_NEEDED)) { BAIL_ON_GSS_ERROR(dwError, majorStatus, minorStatus); } error: if (targetName) { gss_release_name(&minorStatus, &targetName); } if (outputBufferDesc.value) { majorStatus = gss_release_buffer(&minorStatus, &outputBufferDesc); } if (gssContext) { majorStatus = gss_delete_sec_context(&minorStatus, &gssContext, GSS_C_NO_BUFFER); } *pbNeedCredentials = bNeedCredentials; return dwError; }