From 01e6e22c15c646931c63e2595f063a8e3822c1b4 Mon Sep 17 00:00:00 2001 From: Asanka Herath Date: Fri, 16 Jul 2004 04:48:22 +0000 Subject: [PATCH] afslogon-20040715 New file for AD logon processing routines. --- src/WINNT/afsd/logon_ad.cpp | 338 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 src/WINNT/afsd/logon_ad.cpp diff --git a/src/WINNT/afsd/logon_ad.cpp b/src/WINNT/afsd/logon_ad.cpp new file mode 100644 index 0000000..965e7e2 --- /dev/null +++ b/src/WINNT/afsd/logon_ad.cpp @@ -0,0 +1,338 @@ +/* + +Copyright 2004 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + + +//#pragma keyword("interface",on) +#define interface struct +#define SECURITY_WIN32 +#include "afslogon.h" + +/**/ +#include +#include +#include +#include +#include +#include +#include +/**/ + +#define SEC_ERR_VALUE(v) if(status==v) return #v + +char * _get_sec_err_text(SECURITY_STATUS status) { + SEC_ERR_VALUE(SEC_E_OK); + SEC_ERR_VALUE(SEC_I_CONTINUE_NEEDED); + SEC_ERR_VALUE(SEC_I_COMPLETE_NEEDED); + SEC_ERR_VALUE(SEC_I_COMPLETE_AND_CONTINUE); + SEC_ERR_VALUE(SEC_E_INCOMPLETE_MESSAGE); + SEC_ERR_VALUE(SEC_I_INCOMPLETE_CREDENTIALS); + SEC_ERR_VALUE(SEC_E_INVALID_HANDLE); + SEC_ERR_VALUE(SEC_E_TARGET_UNKNOWN); + SEC_ERR_VALUE(SEC_E_LOGON_DENIED); + SEC_ERR_VALUE(SEC_E_INTERNAL_ERROR); + SEC_ERR_VALUE(SEC_E_NO_CREDENTIALS); + SEC_ERR_VALUE(SEC_E_NO_AUTHENTICATING_AUTHORITY); + SEC_ERR_VALUE(SEC_E_INSUFFICIENT_MEMORY); + SEC_ERR_VALUE(SEC_E_INVALID_TOKEN); + SEC_ERR_VALUE(SEC_E_UNSUPPORTED_FUNCTION); + SEC_ERR_VALUE(SEC_E_WRONG_PRINCIPAL); + return "Unknown"; +} + +#undef SEC_ERR_VALUE + +DWORD LogonSSP(PLUID lpLogonId, PCtxtHandle outCtx) { + DWORD code = 1; + SECURITY_STATUS status; + CredHandle creds; + CtxtHandle ctxclient,ctxserver; + TimeStamp expiry; + BOOL cont = TRUE; + BOOL first = TRUE; + SecBufferDesc sdescc,sdescs; + SecBuffer stokc,stoks; + ULONG cattrs,sattrs; + int iters = 10; + + outCtx->dwLower = 0; + outCtx->dwUpper = 0; + + cattrs = 0; + sattrs = 0; + + status = AcquireCredentialsHandle( + NULL, + "Negotiate", + SECPKG_CRED_BOTH, + lpLogonId, + NULL, + NULL, + NULL, + &creds, + &expiry); + + if(status != SEC_E_OK) { + DebugEvent(NULL,"AcquireCredentialsHandle failed: %lX", status); + goto ghp_0; + } + + sdescc.cBuffers = 1; + sdescc.pBuffers = &stokc; + sdescc.ulVersion = SECBUFFER_VERSION; + + stokc.BufferType = SECBUFFER_TOKEN; + stokc.cbBuffer = 0; + stokc.pvBuffer = NULL; + + sdescs.cBuffers = 1; + sdescs.pBuffers = &stoks; + sdescs.ulVersion = SECBUFFER_VERSION; + + stoks.BufferType = SECBUFFER_TOKEN; + stoks.cbBuffer = 0; + stoks.pvBuffer = NULL; + + do { + status = InitializeSecurityContext( + &creds, + ((first)? NULL:&ctxclient), + NULL, + ISC_REQ_DELEGATE | ISC_REQ_ALLOCATE_MEMORY, + 0, + SECURITY_NATIVE_DREP, + ((first)?NULL:&sdescs), + 0, + &ctxclient, + &sdescc, + &cattrs, + &expiry + ); + + DebugEvent(NULL,"InitializeSecurityContext returns status[%lX](%s)",status,_get_sec_err_text(status)); + + if(!first) FreeContextBuffer(stoks.pvBuffer); + + if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) { + CompleteAuthToken(&ctxclient, &sdescc); + } + + if(status != SEC_I_CONTINUE_NEEDED && status != SEC_I_COMPLETE_AND_CONTINUE) { + cont = FALSE; + } + + if(!stokc.cbBuffer && !cont) { + DebugEvent(NULL,"Breaking out after InitializeSecurityContext"); + break; + } + + status = AcceptSecurityContext( + &creds, + ((first)?NULL:&ctxserver), + &sdescc, + ASC_REQ_DELEGATE | ASC_REQ_ALLOCATE_MEMORY, + SECURITY_NATIVE_DREP, + &ctxserver, + &sdescs, + &sattrs, + &expiry); + + DebugEvent(NULL,"AcceptSecurityContext returns status[%lX](%s)", status, _get_sec_err_text(status)); + + FreeContextBuffer(stokc.pvBuffer); + + if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) { + CompleteAuthToken(&ctxserver,&sdescs); + } + + if(status == SEC_I_CONTINUE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) { + cont = TRUE; + } + + if(!cont) + FreeContextBuffer(stoks.pvBuffer); + + first = FALSE; + iters--; /* just in case, hard limit on loop */ + } while(cont && iters); + + if(sattrs & ASC_RET_DELEGATE) { + DebugEvent(NULL,"Received delegate context"); + *outCtx = ctxserver; + code = 0; + } else { + DebugEvent(NULL,"Didn't receive delegate context"); + outCtx->dwLower = 0; + outCtx->dwUpper = 0; + DeleteSecurityContext(&ctxserver); + } + +ghp_2: + DeleteSecurityContext(&ctxclient); +ghp_1: + FreeCredentialsHandle(&creds); +ghp_0: + return code; +} + +DWORD QueryAdHomePath(char * homePath, size_t homePathLen, PLUID lpLogonId) { + DWORD code = 1; /* default is failure */ + + PSECURITY_LOGON_SESSION_DATA plsd; + NTSTATUS rv = 0; + DWORD size1,size2; + SID_NAME_USE snu; + HRESULT hr = S_OK; + LPWSTR p = NULL; + WCHAR adsPath[MAX_PATH] = L""; + BOOL coInitialized = FALSE; + + homePath[0] = '\0'; + + rv = LsaGetLogonSessionData(lpLogonId, &plsd); + if(rv == 0){ + if(ConvertSidToStringSidW(plsd->Sid,&p)) { + IADsNameTranslate *pNto; + + DebugEvent(NULL, "Got SID string [%S]", p); + + hr = CoInitialize(NULL); + if(SUCCEEDED(hr)) + coInitialized = TRUE; + + hr = CoCreateInstance(CLSID_NameTranslate, + NULL, + CLSCTX_INPROC_SERVER, + IID_IADsNameTranslate, + (void**)&pNto); + + if(FAILED(hr)) { DebugEvent(NULL,"Can't create nametranslate object"); } + else { + hr = pNto->Init(ADS_NAME_INITTYPE_GC,L""); //,clientUpn/*IL->UserName.Buffer*/,IL->LogonDomainName.Buffer,IL->Password.Buffer); + if (FAILED(hr)) { + DebugEvent(NULL,"NameTranslate Init failed [%ld]", hr); + } + else { + hr = pNto->Set(ADS_NAME_TYPE_SID_OR_SID_HISTORY_NAME, p); + if(FAILED(hr)) { DebugEvent(NULL,"Can't set sid string"); } + else { + BSTR bstr; + + hr = pNto->Get(ADS_NAME_TYPE_1779, &bstr); + wcscpy(adsPath, bstr); + + SysFreeString(bstr); + } + } + pNto->Release(); + } + + LocalFree(p); + + } else { + DebugEvent(NULL, "Can't convert sid to string"); + } + + LsaFreeReturnBuffer(plsd); + } else { + DebugEvent(NULL, "LsaGetLogonSessionData failed"); + } + + if(adsPath[0]) { + WCHAR fAdsPath[MAX_PATH]; + IADsUser *pAdsUser; + BSTR bstHomeDir = NULL; + + hr = StringCchPrintfW(fAdsPath, MAX_PATH, L"LDAP://%s", adsPath); + if(hr != S_OK) { + DebugEvent(NULL, "Can't format full adspath"); + goto cleanup; + } + + DebugEvent(NULL, "Trying adsPath=[%S]", fAdsPath); + + hr = ADsGetObject( fAdsPath, IID_IADsUser, (LPVOID *) &pAdsUser); + if(hr != S_OK) { + DebugEvent(NULL, "Can't open IADs object"); + goto cleanup; + } + + hr = pAdsUser->get_Profile(&bstHomeDir); + if(hr != S_OK) { + DebugEvent(NULL, "Can't get profile directory"); + goto cleanup_homedir_section; + } + + wcstombs(homePath, bstHomeDir, homePathLen); + + DebugEvent(NULL, "Got homepath [%s]", homePath); + + SysFreeString(bstHomeDir); + + code = 0; + +cleanup_homedir_section: + pAdsUser->Release(); + } + +cleanup: + if(coInitialized) + CoUninitialize(); + + return code; +} + +/* Try to determine the user's AD home path. *homePath is assumed to be at least MAXPATH bytes. + If successful, opt.flags is updated with LOGON_FLAG_AD_REALM to indicate that we are dealing with + an AD realm. */ +DWORD GetAdHomePath(char * homePath, size_t homePathLen, PLUID lpLogonId, MSV1_0_INTERACTIVE_LOGON * IL, LogonOptions_t * opt) { + CtxtHandle ctx; + SECURITY_STATUS status; + + if(LogonSSP(lpLogonId,&ctx)) + return 1; + else { + SecPkgContext_Names name; + status = QueryContextAttributes(&ctx,SECPKG_ATTR_NAMES,&name); + if(status != SEC_E_OK) { + DebugEvent(NULL,"Can't query names from context [%lX]",status); + goto ghp_0; + } + DebugEvent(NULL,"Context name [%s]",name.sUserName); + + status = ImpersonateSecurityContext(&ctx); + if(status == SEC_E_OK) { + if(!QueryAdHomePath(homePath,homePathLen,lpLogonId)) { + DebugEvent(NULL,"Returned home path [%s]",homePath); + opt->flags |= LOGON_FLAG_AD_REALM; + } + RevertSecurityContext(&ctx); + } else { + DebugEvent(NULL,"Can't impersonate context [%lX]",status); + } +ghp_0: + DeleteSecurityContext(&ctx); + return 0; + } +} -- 1.9.4