void LsaFreeSMBCreds( IN OUT PLSA_CREDS_FREE_INFO* ppFreeInfo ) { PLSA_CREDS_FREE_INFO pFreeInfo = *ppFreeInfo; if (!pFreeInfo) { goto cleanup; } LwIoSetThreadCreds(pFreeInfo->pRestoreCreds); if (pFreeInfo->pRestoreCreds != NULL) { LwIoDeleteCreds(pFreeInfo->pRestoreCreds); } if (pFreeInfo->bKrbCreds) { LwKrb5SetThreadDefaultCachePath( pFreeInfo->pszRestoreCache, NULL); LW_SAFE_FREE_STRING(pFreeInfo->pszRestoreCache); if (pFreeInfo->ctx != NULL) { if (pFreeInfo->cc != NULL) { krb5_cc_destroy(pFreeInfo->ctx, pFreeInfo->cc); } krb5_free_context(pFreeInfo->ctx); } } LwFreeMemory(pFreeInfo); *ppFreeInfo = NULL; cleanup: return; }
static DWORD AD_GetComputerDn( IN OPTIONAL PCSTR pszDnsDomainName, OUT PSTR* ppszComputerDn ) { DWORD dwError = 0; PSTR pszComputerDn = NULL; PLSA_MACHINE_PASSWORD_INFO_A pPasswordInfo = NULL; PSTR pszUserPrincipalName = NULL; PCSTR pszKrb5CachePath = "MEMORY:lsass_get_computer_dn"; PSTR pszPreviousKrb5CachePath = NULL; HANDLE hDirectory = NULL; // Lock to protect the cache: static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; BOOLEAN isLocked = FALSE; BOOLEAN needDestroyCache = FALSE; // // In the future, if we have cached DN information in the domain state, // we will use that. However, since that does not currently exist, // we will fetch it directly. // // Since this code should work regardless of the internal state, // we will need to use a private memory cache to establish credentials. // dwError = AD_GetMachinePasswordInfoA(pszDnsDomainName, &pPasswordInfo); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateStringPrintf( &pszUserPrincipalName, "%s@%s", pPasswordInfo->Account.SamAccountName, pPasswordInfo->Account.DnsDomainName); BAIL_ON_LSA_ERROR(dwError); dwError = LwMapErrnoToLwError(pthread_mutex_lock(&mutex)); BAIL_ON_LSA_ERROR(dwError); isLocked = TRUE; dwError = LwKrb5InitializeCredentials( pszUserPrincipalName, pPasswordInfo->Password, pszKrb5CachePath, NULL); BAIL_ON_LSA_ERROR(dwError); needDestroyCache = TRUE; dwError = LwKrb5SetThreadDefaultCachePath(pszKrb5CachePath, &pszPreviousKrb5CachePath); BAIL_ON_LSA_ERROR(dwError); dwError = LsaLdapOpenDirectoryDomain( pPasswordInfo->Account.DnsDomainName, NULL, 0, &hDirectory); BAIL_ON_LSA_ERROR(dwError); dwError = AD_RawFindComputerDn( hDirectory, pPasswordInfo->Account.DnsDomainName, pPasswordInfo->Account.SamAccountName, &pszComputerDn); BAIL_ON_LSA_ERROR(dwError); error: if (dwError) { LW_SAFE_FREE_STRING(pszComputerDn); } if (needDestroyCache) { LwKrb5DestroyCache(pszKrb5CachePath); } if (pszPreviousKrb5CachePath) { LwKrb5SetThreadDefaultCachePath(pszPreviousKrb5CachePath, NULL); } if (isLocked) { int localError = pthread_mutex_unlock(&mutex); LSA_ASSERT(!localError); } LsaSrvFreeMachinePasswordInfoA(pPasswordInfo); LW_SAFE_FREE_STRING(pszUserPrincipalName); LW_SAFE_FREE_STRING(pszPreviousKrb5CachePath); if (hDirectory) { LwLdapCloseDirectory(hDirectory); } *ppszComputerDn = pszComputerDn; return dwError; }
DWORD IDMLdapSaslBind( LDAP* pLd /* IN */ ) { DWORD dwError = 0; DWORD dwCleanupError = 0; BOOLEAN bLocked = FALSE; PSTR pszCachePath = NULL; if (!pLd) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_ERROR(dwError); } switch (IDMKrbGetState(pgIdmKrbContext)) { case IDM_KRB_CONTEXT_STATE_INITIAL: dwError = IDMKrbDetermineJoinState(pgIdmKrbContext); BAIL_ON_ERROR(dwError); case IDM_KRB_CONTEXT_STATE_JOINED: dwError = IDMKrbRenewCredentials(pgIdmKrbContext); if (dwError) { // Refreshing credentials might fail if the system left // the domain or there were issues reaching the domain // controller. IDMKrbSetState(pgIdmKrbContext, IDM_KRB_CONTEXT_STATE_INITIAL); } BAIL_ON_ERROR(dwError); IDM_RWMUTEX_LOCK_SHARED( &pgIdmKrbContext->mutex_rw, bLocked, dwError); BAIL_ON_ERROR(dwError); dwError = LwKrb5SetThreadDefaultCachePath( pgIdmKrbContext->pszCachePath, &pszCachePath); BAIL_ON_ERROR(dwError); dwError = LwMapLdapErrorToLwError( ldap_sasl_interactive_bind_s( pLd, NULL, "GSSAPI", NULL, NULL, LDAP_SASL_QUIET, &IDMSASLInteraction, NULL)); BAIL_ON_ERROR(dwError); break; default: dwError = ERROR_INVALID_STATE; BAIL_ON_ERROR(dwError); break; } cleanup: if (pszCachePath) { LwKrb5SetThreadDefaultCachePath(pszCachePath, NULL); LwFreeMemory(pszCachePath); } IDM_RWMUTEX_UNLOCK(&pgIdmKrbContext->mutex_rw, bLocked, dwCleanupError); if(!dwError) { dwError = dwCleanupError; } return dwError; error: goto cleanup; }
DWORD LsaSetSMBCreds( IN PCSTR pszUserPrincipalName, IN PCSTR pszPassword, IN BOOLEAN bSetDefaultCachePath, OUT PLSA_CREDS_FREE_INFO* ppFreeInfo ) { DWORD dwError = 0; krb5_error_code ret = 0; PSTR pszNewCachePath = NULL; PCSTR pszCacheName = NULL; PCSTR pszCacheType = NULL; krb5_context ctx = 0; krb5_ccache cc = 0; LW_PIO_CREDS pNewCreds = NULL; LW_PIO_CREDS pOldCreds = NULL; PLSA_CREDS_FREE_INFO pFreeInfo = NULL; PSTR pszOldCachePath = NULL; BOOLEAN bSwitchedPath = FALSE; BAIL_ON_INVALID_POINTER(ppFreeInfo); BAIL_ON_INVALID_STRING(pszUserPrincipalName); ret = krb5_init_context(&ctx); BAIL_ON_KRB_ERROR(ctx, ret); /* Generates a new filed based credentials cache in /tmp. The file will * be owned by root and only accessible by root. */ ret = krb5_cc_new_unique( ctx, "FILE", "hint", &cc); BAIL_ON_KRB_ERROR(ctx, ret); pszCacheType = krb5_cc_get_type(ctx, cc); pszCacheName = krb5_cc_get_name(ctx, cc); dwError = LwAllocateStringPrintf(&pszNewCachePath, "%s:%s", pszCacheType, pszCacheName); BAIL_ON_LSA_ERROR(dwError); dwError = LwKrb5GetTgt( pszUserPrincipalName, pszPassword, pszNewCachePath, NULL); BAIL_ON_LSA_ERROR(dwError); if (bSetDefaultCachePath) { LSA_LOG_DEBUG("Switching default credentials path for new access token"); dwError = LwKrb5SetThreadDefaultCachePath( pszNewCachePath, &pszOldCachePath); BAIL_ON_LSA_ERROR(dwError); bSwitchedPath = TRUE; } dwError = LwIoCreateKrb5CredsA( pszUserPrincipalName, pszNewCachePath, &pNewCreds); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateMemory(sizeof(*pFreeInfo), (PVOID*)&pFreeInfo); BAIL_ON_LSA_ERROR(dwError); dwError = LwIoGetThreadCreds(&pOldCreds); BAIL_ON_LSA_ERROR(dwError); dwError = LwIoSetThreadCreds(pNewCreds); BAIL_ON_LSA_ERROR(dwError); pFreeInfo->ctx = ctx; pFreeInfo->cc = cc; pFreeInfo->pRestoreCreds = pOldCreds; pFreeInfo->pszRestoreCache = pszOldCachePath; pFreeInfo->bKrbCreds = TRUE; pOldCreds = NULL; cleanup: *ppFreeInfo = pFreeInfo; if (pOldCreds != NULL) { LwIoDeleteCreds(pOldCreds); } if (pNewCreds != NULL) { LwIoDeleteCreds(pNewCreds); } LW_SAFE_FREE_STRING(pszNewCachePath); return dwError; error: if (ctx != NULL) { if (cc != NULL) { krb5_cc_destroy(ctx, cc); } krb5_free_context(ctx); } if (pFreeInfo) { LwFreeMemory(pFreeInfo); pFreeInfo = NULL; } if (bSwitchedPath) { LwKrb5SetThreadDefaultCachePath( pszOldCachePath, NULL); LW_SAFE_FREE_STRING(pszOldCachePath); } goto cleanup; }