static DWORD LwmEvtSrvCreateError( DWORD ErrorCode, PCWSTR pErrorMessage, PEVT_IPC_GENERIC_ERROR* ppError ) { DWORD dwError = 0; PEVT_IPC_GENERIC_ERROR pError = NULL; dwError = LwAllocateMemory(sizeof(*pError), (PVOID*) &pError); BAIL_ON_EVT_ERROR(dwError); if (pErrorMessage) { dwError = LwAllocateWc16String( (PWSTR*)&pError->pErrorMessage, pErrorMessage); BAIL_ON_EVT_ERROR(dwError); } pError->Error = ErrorCode; *ppError = pError; error: return dwError; }
static DWORD LwSmQueryServiceDependencyClosureHelper( LW_SERVICE_HANDLE hHandle, PWSTR** pppwszServiceList ) { DWORD dwError = 0; PLW_SERVICE_INFO pInfo = NULL; LW_SERVICE_HANDLE hDepHandle = NULL; PWSTR pwszDepName = NULL; size_t i = 0; dwError = LwSmQueryServiceInfo(hHandle, &pInfo); BAIL_ON_ERROR(dwError); for (i = 0; pInfo->ppwszDependencies[i]; i++) { dwError = LwSmAcquireServiceHandle(pInfo->ppwszDependencies[i], &hDepHandle); BAIL_ON_ERROR(dwError); dwError = LwSmQueryServiceDependencyClosureHelper(hDepHandle, pppwszServiceList); BAIL_ON_ERROR(dwError); if (!LwSmStringListContains(*pppwszServiceList, pInfo->ppwszDependencies[i])) { dwError = LwAllocateWc16String(&pwszDepName, pInfo->ppwszDependencies[i]); BAIL_ON_ERROR(dwError); dwError = LwSmStringListAppend(pppwszServiceList, pwszDepName); BAIL_ON_ERROR(dwError); pwszDepName = NULL; } LwSmReleaseServiceHandle(hDepHandle); hDepHandle = NULL; } cleanup: LW_SAFE_FREE_MEMORY(pwszDepName); if (pInfo) { LwSmCommonFreeServiceInfo(pInfo); } if (hDepHandle) { LwSmReleaseServiceHandle(hDepHandle); } return dwError; error: goto cleanup; }
DWORD LwSmTableEnumerateEntries( PWSTR** pppwszServiceNames ) { DWORD dwError = 0; BOOL bLocked = FALSE; PSM_LINK pLink = NULL; PSM_TABLE_ENTRY pEntry = NULL; size_t count = 0; size_t i = 0; PWSTR* ppwszServiceNames = NULL; LOCK(bLocked, gServiceTable.pLock); for (pLink = NULL; (pLink = SM_LINK_ITERATE(&gServiceTable.entries, pLink));) { count++; } dwError = LwAllocateMemory( sizeof(*ppwszServiceNames) * (count + 1), OUT_PPVOID(&ppwszServiceNames)); BAIL_ON_ERROR(dwError); for (pLink = NULL, i = 0; (pLink = SM_LINK_ITERATE(&gServiceTable.entries, pLink)); i++) { pEntry = STRUCT_FROM_MEMBER(pLink, SM_TABLE_ENTRY, link); dwError = LwAllocateWc16String(&ppwszServiceNames[i], pEntry->pInfo->pwszName); BAIL_ON_ERROR(dwError); } *pppwszServiceNames = ppwszServiceNames; cleanup: UNLOCK(bLocked, gServiceTable.pLock); return dwError; error: *pppwszServiceNames = NULL; if (ppwszServiceNames) { LwSmFreeStringList(ppwszServiceNames); } goto cleanup; }
static inline DWORD LocalWc16StrDupOrNull( IN OPTIONAL PCWSTR InputString, OUT PWSTR* OutputString ) { DWORD dwError = 0; if (InputString) { dwError = LwAllocateWc16String(OutputString, InputString); } else { *OutputString = NULL; } return dwError; }
static DWORD LwSmTableGetEntryReverseDependencyClosureHelper( PSM_TABLE_ENTRY pEntry, PWSTR* ppwszAllServices, PWSTR** pppwszServiceList ) { DWORD dwError = 0; PLW_SERVICE_INFO pInfo = NULL; PLW_SERVICE_INFO pDepInfo = NULL; size_t i = 0; PSM_TABLE_ENTRY pDepEntry = NULL; PWSTR pwszDepName = NULL; BOOLEAN bLocked = FALSE; LOCK(bLocked, pEntry->pLock); dwError = LwSmCopyServiceInfo(pEntry->pInfo, &pInfo); UNLOCK(bLocked, pEntry->pLock); BAIL_ON_ERROR(dwError); for (i = 0; ppwszAllServices[i]; i++) { dwError = LwSmTableGetEntry(ppwszAllServices[i], &pDepEntry); BAIL_ON_ERROR(dwError); LOCK(bLocked, pEntry->pLock); dwError = LwSmCopyServiceInfo(pDepEntry->pInfo, &pDepInfo); UNLOCK(bLocked, pEntry->pLock); BAIL_ON_ERROR(dwError); if (LwSmStringListContains(pDepInfo->ppwszDependencies, pInfo->pwszName)) { dwError = LwSmTableGetEntryReverseDependencyClosureHelper( pDepEntry, ppwszAllServices, pppwszServiceList); BAIL_ON_ERROR(dwError); dwError = LwAllocateWc16String(&pwszDepName, pDepInfo->pwszName); BAIL_ON_ERROR(dwError); dwError = LwSmStringListAppend(pppwszServiceList, pwszDepName); BAIL_ON_ERROR(dwError); pwszDepName = NULL; } LwSmCommonFreeServiceInfo(pDepInfo); pDepInfo = NULL; LwSmTableReleaseEntry(pDepEntry); pDepEntry = NULL; } cleanup: LW_SAFE_FREE_MEMORY(pwszDepName); if (pInfo) { LwSmCommonFreeServiceInfo(pInfo); } if (pDepInfo) { LwSmCommonFreeServiceInfo(pDepInfo); } if (pDepEntry) { LwSmTableReleaseEntry(pDepEntry); } return dwError; error: goto cleanup; }
BOOLEAN CreateRpcBinding( PVOID *phBinding, RPC_BINDING_TYPE eBindingType, PCWSTR pwszHostname, PCWSTR pwszBinding, PCREDENTIALS pCredentials ) { PCSTR pszNtlmsspAuth = "ntlmssp"; PCSTR pszSign = "sign"; PCSTR pszSeal = "seal"; BOOLEAN bRet = TRUE; NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = ERROR_SUCCESS; unsigned32 rpcStatus = RPC_S_OK; LSA_BINDING hBinding = NULL; LW_PIO_CREDS pIoCreds = NULL; PWSTR pwszBindingString = NULL; size_t sBindingStringLen = 0; PSTR pszBindingString = NULL; PSTR *ppszOptions = NULL; DWORD iOpt = 0; DWORD i = 0; DWORD dwNumValidOptions = 0; unsigned32 AuthType = 0; unsigned32 ProtectionLevel = 0; SEC_WINNT_AUTH_IDENTITY *pNtlmSspAuthInfo = NULL; PVOID pAuthInfo = NULL; unsigned char *pszUuid = NULL; unsigned char *pszProtSeq = NULL; unsigned char *pszNetworkAddr = NULL; unsigned char *pszEndpoint = NULL; unsigned char *pszOptions = NULL; PSTR pszHostname = NULL; if (phBinding == NULL) { ntStatus = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntStatus); } if (pwszBinding) { dwError = LwAllocateWc16String(&pwszBindingString, pwszBinding); BAIL_ON_WIN_ERROR(dwError); dwError = LwWc16sLen(pwszBindingString, &sBindingStringLen); BAIL_ON_WIN_ERROR(dwError); dwError = LwWc16sToMbs(pwszBindingString, &pszBindingString); BAIL_ON_WIN_ERROR(dwError); ppszOptions = get_string_list(pszBindingString, ':'); if (ppszOptions == NULL) { ntStatus = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntStatus); } /* * Find and identify valid options */ while (ppszOptions[iOpt]) { if (!strcasecmp(pszNtlmsspAuth, ppszOptions[iOpt])) { AuthType = rpc_c_authn_winnt; dwNumValidOptions++; } else if (!strcasecmp(pszSign, ppszOptions[iOpt])) { ProtectionLevel = rpc_c_authn_level_pkt_integrity; dwNumValidOptions++; } else if (!strcasecmp(pszSeal, ppszOptions[iOpt])) { ProtectionLevel = rpc_c_authn_level_pkt_privacy; dwNumValidOptions++; } iOpt++; } } /* * Cut off the options from the binding string so it can * be passed to rpc routines */ if (dwNumValidOptions > 0) { i = sBindingStringLen; while (dwNumValidOptions && pwszBindingString[--i]) { if (pwszBindingString[i] == (WCHAR)':') { dwNumValidOptions--; } } pwszBindingString[i] = (WCHAR)'\0'; pszBindingString[i] = '\0'; } ntStatus = LwIoGetActiveCreds(NULL, &pIoCreds); BAIL_ON_NT_STATUS(ntStatus); if (pwszBindingString) { ntStatus = RpcInitBindingFromBindingString( (handle_t*)&hBinding, pwszBindingString, pIoCreds); } else { switch (eBindingType) { case RPC_LSA_BINDING: ntStatus = LsaInitBindingDefault(&hBinding, pwszHostname, pIoCreds); break; case RPC_SAMR_BINDING: ntStatus = SamrInitBindingDefault(&hBinding, pwszHostname, pIoCreds); break; case RPC_NETLOGON_BINDING: ntStatus = NetrInitBindingDefault(&hBinding, pwszHostname, pIoCreds); break; case RPC_DSSETUP_BINDING: ntStatus = DsrInitBindingDefault(&hBinding, pwszHostname, pIoCreds); break; case RPC_WKSSVC_BINDING: ntStatus = WkssInitBindingDefault(&hBinding, pwszHostname, pIoCreds); break; default: ntStatus = STATUS_NOT_IMPLEMENTED; break; } } BAIL_ON_NT_STATUS(ntStatus); switch (AuthType) { case rpc_c_authn_winnt: dwError = LwAllocateMemory(sizeof(*pNtlmSspAuthInfo), OUT_PPVOID(&pNtlmSspAuthInfo)); BAIL_ON_WIN_ERROR(dwError); if (pCredentials->Ntlm.pwszDomain) { dwError = LwWc16sToMbs(pCredentials->Ntlm.pwszDomain, &pNtlmSspAuthInfo->Domain); BAIL_ON_WIN_ERROR(dwError); pNtlmSspAuthInfo->DomainLength = strlen(pNtlmSspAuthInfo->Domain); } dwError = LwWc16sToMbs(pCredentials->Ntlm.pwszUsername, &pNtlmSspAuthInfo->User); BAIL_ON_WIN_ERROR(dwError); pNtlmSspAuthInfo->UserLength = strlen(pNtlmSspAuthInfo->User); dwError = LwWc16sToMbs(pCredentials->Ntlm.pwszPassword, &pNtlmSspAuthInfo->Password); BAIL_ON_WIN_ERROR(dwError); pNtlmSspAuthInfo->PasswordLength = strlen(pNtlmSspAuthInfo->Password); pAuthInfo = (PVOID)pNtlmSspAuthInfo; break; default: pAuthInfo = NULL; break; } if (pwszHostname) { dwError = LwWc16sToMbs(pwszHostname, &pszHostname); BAIL_ON_WIN_ERROR(dwError); } else { rpc_string_binding_parse((unsigned char*)pszBindingString, &pszUuid, &pszProtSeq, &pszNetworkAddr, &pszEndpoint, &pszOptions, &rpcStatus); if (rpcStatus) { ntStatus = LwRpcStatusToNtStatus(rpcStatus); BAIL_ON_NT_STATUS(ntStatus); } dwError = LwAllocateString((PSTR)pszNetworkAddr, &pszHostname); BAIL_ON_WIN_ERROR(dwError); } if (AuthType) { rpc_binding_set_auth_info(hBinding, (unsigned char*)pszHostname, ProtectionLevel, AuthType, (rpc_auth_identity_handle_t)pAuthInfo, rpc_c_authz_name, /* authz_protocol */ &rpcStatus); if (rpcStatus) { ntStatus = LwRpcStatusToNtStatus(rpcStatus); BAIL_ON_NT_STATUS(ntStatus); } } *phBinding = hBinding; cleanup: if (pIoCreds) { LwIoDeleteCreds(pIoCreds); } LW_SAFE_FREE_MEMORY(pwszBindingString); LW_SAFE_FREE_MEMORY(pszBindingString); LW_SAFE_FREE_MEMORY(pszHostname); rpc_string_free(&pszUuid, &rpcStatus); rpc_string_free(&pszProtSeq, &rpcStatus); rpc_string_free(&pszNetworkAddr, &rpcStatus); rpc_string_free(&pszEndpoint, &rpcStatus); rpc_string_free(&pszOptions, &rpcStatus); if (ppszOptions) { free_string_list(ppszOptions); } if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } if (ntStatus != STATUS_SUCCESS) { bRet = FALSE; } return bRet; error: *phBinding = NULL; bRet = FALSE; goto cleanup; }
static DWORD LwSmRegistryReadStringList( HANDLE hReg, HKEY pRootKey, PCWSTR pwszParentKey, PCWSTR pwszValueName, PWSTR** pppwszValues ) { DWORD dwError = 0; PWSTR pwszValuesString = NULL; PWSTR pwszCursor = NULL; PWSTR pwszSpace = NULL; PWSTR* ppwszValues = NULL; size_t count = 0; size_t i = 0; dwError = LwSmRegistryReadString(hReg, pRootKey, pwszParentKey, pwszValueName, &pwszValuesString); BAIL_ON_ERROR(dwError); if (*pwszValuesString) { count = LwSmCountTokens(pwszValuesString); } else { count = 0; } dwError = LwAllocateMemory((count + 1) * sizeof(*ppwszValues), OUT_PPVOID(&ppwszValues)); BAIL_ON_ERROR(dwError); for (pwszCursor = pwszValuesString, i = 0; i < count; i++) { for (pwszSpace = pwszCursor; *pwszSpace && *pwszSpace != ' '; pwszSpace++); *pwszSpace = (WCHAR) '\0'; dwError = LwAllocateWc16String(&ppwszValues[i], pwszCursor); BAIL_ON_ERROR(dwError); for (pwszCursor = pwszSpace + 1; *pwszCursor == ' '; pwszCursor++); } *pppwszValues = ppwszValues; cleanup: LW_SAFE_FREE_MEMORY(pwszValuesString); return dwError; error: *pppwszValues = NULL; if (ppwszValues) { LwSmFreeStringList(ppwszValues); } goto cleanup; }
DWORD LwSmRegistryReadServiceInfo( HANDLE hReg, PCWSTR pwszName, PLW_SERVICE_INFO* ppInfo ) { DWORD dwError = 0; PLW_SERVICE_INFO pInfo = NULL; HKEY pRootKey = NULL; PWSTR pwszParentKey = NULL; DWORD dwType = 0; PSTR pszName = NULL; PSTR pszParentKey = NULL; DWORD dwAutostart = 0; static const WCHAR wszDescription[] = {'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 0}; static const WCHAR wszType[] = {'T', 'y', 'p', 'e', 0}; static const WCHAR wszPath[] = {'P', 'a', 't', 'h', 0}; static const WCHAR wszArguments[] = {'A', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's', 0}; static const WCHAR wszDependencies[] = {'D', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's', 0}; static const WCHAR wszEnvironment[] = {'E', 'n', 'v', 'i', 'r', 'o', 'n', 'm', 'e', 'n', 't', 0}; static const WCHAR wszGroup[] = {'S', 'e', 'r', 'v', 'i', 'c', 'e', 'G', 'r', 'o', 'u', 'p', 0}; static const WCHAR wszAutostart[] = {'A', 'u', 't', 'o', 's', 't', 'a', 'r', 't', 0}; static const WCHAR wszFdLimit[] = {'F', 'd', 'L', 'i', 'm', 'i', 't', 0}; dwError = LwWc16sToMbs(pwszName, &pszName); BAIL_ON_ERROR(dwError); dwError = LwAllocateStringPrintf(&pszParentKey, "Services\\%s", pszName); BAIL_ON_ERROR(dwError); dwError = LwMbsToWc16s(pszParentKey, &pwszParentKey); BAIL_ON_ERROR(dwError); dwError = RegOpenKeyExA( hReg, NULL, HKEY_THIS_MACHINE, 0, KEY_READ, &pRootKey); BAIL_ON_ERROR(dwError); dwError = LwAllocateMemory(sizeof(*pInfo), OUT_PPVOID(&pInfo)); BAIL_ON_ERROR(dwError); dwError = LwSmRegistryReadDword( hReg, pRootKey, pwszParentKey, wszType, &dwType); BAIL_ON_ERROR(dwError); pInfo->type = dwType; dwError = LwAllocateWc16String(&pInfo->pwszName, pwszName); BAIL_ON_ERROR(dwError); dwError = LwSmRegistryReadString( hReg, pRootKey, pwszParentKey, wszDescription, &pInfo->pwszDescription); BAIL_ON_ERROR(dwError); dwError = LwSmRegistryReadString( hReg, pRootKey, pwszParentKey, wszPath, &pInfo->pwszPath); BAIL_ON_ERROR(dwError); dwError = LwSmRegistryReadStringList( hReg, pRootKey, pwszParentKey, wszArguments, &pInfo->ppwszArgs); BAIL_ON_ERROR(dwError); dwError = LwSmRegistryReadStringList( hReg, pRootKey, pwszParentKey, wszEnvironment, &pInfo->ppwszEnv); BAIL_ON_ERROR(dwError); dwError = LwSmRegistryReadStringList( hReg, pRootKey, pwszParentKey, wszDependencies, &pInfo->ppwszDependencies); BAIL_ON_ERROR(dwError); dwError = LwSmRegistryReadDword( hReg, pRootKey, pwszParentKey, wszAutostart, &dwAutostart); if (dwError == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { dwError = 0; dwAutostart = FALSE; } BAIL_ON_ERROR(dwError); pInfo->bAutostart = dwAutostart ? TRUE : FALSE; dwError = LwSmRegistryReadDword( hReg, pRootKey, pwszParentKey, wszFdLimit, &pInfo->dwFdLimit); if (dwError == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { dwError = 0; pInfo->dwFdLimit = 0; } BAIL_ON_ERROR(dwError); dwError = LwSmRegistryReadString( hReg, pRootKey, pwszParentKey, wszGroup, &pInfo->pwszGroup); if (dwError == LWREG_ERROR_NO_SUCH_KEY_OR_VALUE) { #ifdef SERVICE_DIRECT dwError = LwMbsToWc16s("direct", &pInfo->pwszGroup); #else dwError = LwAllocateWc16String(&pInfo->pwszGroup, pInfo->pwszName); #endif } BAIL_ON_ERROR(dwError); *ppInfo = pInfo; cleanup: LW_SAFE_FREE_MEMORY(pszName); LW_SAFE_FREE_MEMORY(pszParentKey); LW_SAFE_FREE_MEMORY(pwszParentKey); if (pRootKey) { RegCloseKey(hReg, pRootKey); } return dwError; error: *ppInfo = NULL; if (pInfo) { LwSmCommonFreeServiceInfo(pInfo); } goto cleanup; }
NET_API_STATUS NetLocalGroupEnum( PCWSTR pwszHostname, DWORD dwLevel, PVOID *ppBuffer, DWORD dwMaxBufferSize, PDWORD pdwNumEntries, PDWORD pdwTotalNumEntries, PDWORD pdwResume ) { const DWORD dwAccountFlags = 0; const DWORD dwAliasAccessFlags = ALIAS_ACCESS_LOOKUP_INFO; const WORD wInfoLevel = ALIAS_INFO_ALL; NTSTATUS status = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; DWORD dwResume = 0; PNET_CONN pConn = NULL; SAMR_BINDING hSamrBinding = NULL; DOMAIN_HANDLE hDomain = NULL; DOMAIN_HANDLE hBtinDomain = NULL; DWORD dwSamrResume = 0; PWSTR *ppwszDomainAliases = NULL; PDWORD pdwDomainRids = NULL; DWORD dwNumDomainEntries = 0; DWORD dwTotalNumDomainEntries = 0; PWSTR *ppwszBtinDomainAliases = NULL; PDWORD pdwBtinDomainRids = NULL; DWORD dwNumBtinDomainEntries = 0; DWORD dwTotalNumBtinDomainEntries = 0; DWORD dwTotalNumEntries = 0; DWORD dwNumEntries = 0; DWORD i = 0; PDWORD pdwRids = NULL; PWSTR *ppwszAliases = NULL; ACCOUNT_HANDLE hAlias = NULL; AliasInfo *pSamrAliasInfo = NULL; AliasInfoAll **ppAliasInfo = NULL; DWORD dwInfoLevelSize = 0; PVOID pSourceBuffer = NULL; DWORD dwSize = 0; DWORD dwTotalSize = 0; DWORD dwSpaceAvailable = 0; PVOID pBuffer = NULL; PVOID pBufferCursor = NULL; PIO_CREDS pCreds = NULL; NET_VALIDATION_LEVEL eValidation = NET_VALIDATION_NONE; BAIL_ON_INVALID_PTR(ppBuffer, err); BAIL_ON_INVALID_PTR(pdwNumEntries, err); BAIL_ON_INVALID_PTR(pdwTotalNumEntries, err); BAIL_ON_INVALID_PTR(pdwResume, err); switch (dwLevel) { case 0: dwInfoLevelSize = sizeof(LOCALGROUP_INFO_0); break; case 1: dwInfoLevelSize = sizeof(LOCALGROUP_INFO_1); break; default: err = ERROR_INVALID_LEVEL; BAIL_ON_WIN_ERROR(err); } dwResume = *pdwResume; status = LwIoGetActiveCreds(NULL, &pCreds); BAIL_ON_NT_STATUS(status); status = NetConnectSamr(&pConn, pwszHostname, 0, 0, pCreds); BAIL_ON_NT_STATUS(status); hSamrBinding = pConn->Rpc.Samr.hBinding; hDomain = pConn->Rpc.Samr.hDomain; hBtinDomain = pConn->Rpc.Samr.hBuiltin; do { status = SamrEnumDomainAliases(hSamrBinding, hDomain, &dwSamrResume, dwAccountFlags, &ppwszDomainAliases, &pdwDomainRids, &dwNumDomainEntries); if (status != STATUS_SUCCESS && status != STATUS_MORE_ENTRIES) { BAIL_ON_NT_STATUS(status); } if (ppwszDomainAliases) { SamrFreeMemory(ppwszDomainAliases); ppwszDomainAliases = NULL; } if (pdwDomainRids) { SamrFreeMemory(pdwDomainRids); pdwDomainRids = NULL; } dwTotalNumDomainEntries += dwNumDomainEntries; dwNumDomainEntries = 0; } while (status == STATUS_MORE_ENTRIES); dwSamrResume = 0; do { status = SamrEnumDomainAliases(hSamrBinding, hBtinDomain, &dwSamrResume, dwAccountFlags, &ppwszBtinDomainAliases, &pdwBtinDomainRids, &dwNumBtinDomainEntries); if (status != STATUS_SUCCESS && status != STATUS_MORE_ENTRIES) { BAIL_ON_NT_STATUS(status); } if (ppwszBtinDomainAliases) { SamrFreeMemory(ppwszBtinDomainAliases); ppwszBtinDomainAliases = NULL; } if (pdwBtinDomainRids) { SamrFreeMemory(pdwBtinDomainRids); pdwBtinDomainRids = NULL; } dwTotalNumBtinDomainEntries += dwNumBtinDomainEntries; dwNumBtinDomainEntries = 0; } while (status == STATUS_MORE_ENTRIES); dwTotalNumEntries = dwTotalNumDomainEntries + dwTotalNumBtinDomainEntries; status = NetAllocateMemory(OUT_PPVOID(&pdwRids), sizeof(pdwRids[0]) * dwTotalNumEntries); BAIL_ON_NT_STATUS(status); status = NetAllocateMemory(OUT_PPVOID(&ppwszAliases), sizeof(ppwszAliases[0]) * dwTotalNumEntries); BAIL_ON_NT_STATUS(status); status = NetAllocateMemory(OUT_PPVOID(&ppAliasInfo), sizeof(ppAliasInfo[0]) * dwTotalNumEntries); BAIL_ON_NT_STATUS(status); dwTotalNumDomainEntries = 0; dwTotalNumBtinDomainEntries = 0; dwSamrResume = 0; do { status = SamrEnumDomainAliases(hSamrBinding, hDomain, &dwSamrResume, dwAccountFlags, &ppwszDomainAliases, &pdwDomainRids, &dwNumDomainEntries); if (status != STATUS_SUCCESS && status != STATUS_MORE_ENTRIES) { BAIL_ON_NT_STATUS(status); } for (i = 0; i < dwNumDomainEntries; i++) { err = LwAllocateWc16String(&ppwszAliases[dwTotalNumDomainEntries + i], ppwszDomainAliases[i]); BAIL_ON_WIN_ERROR(err); pdwRids[dwTotalNumDomainEntries + i] = pdwDomainRids[i]; } dwTotalNumDomainEntries += dwNumDomainEntries; dwNumDomainEntries = 0; if (ppwszDomainAliases) { SamrFreeMemory(ppwszDomainAliases); ppwszDomainAliases = NULL; } if (pdwDomainRids) { SamrFreeMemory(pdwDomainRids); pdwDomainRids = NULL; } } while (status == STATUS_MORE_ENTRIES); dwSamrResume = 0; do { status = SamrEnumDomainAliases(hSamrBinding, hBtinDomain, &dwSamrResume, dwAccountFlags, &ppwszBtinDomainAliases, &pdwBtinDomainRids, &dwNumBtinDomainEntries); if (status != STATUS_SUCCESS && status != STATUS_MORE_ENTRIES) { BAIL_ON_NT_STATUS(status); } for (i = 0; i < dwNumBtinDomainEntries; i++) { err = LwAllocateWc16String(&ppwszAliases[dwTotalNumDomainEntries + dwTotalNumBtinDomainEntries + i], ppwszBtinDomainAliases[i]); BAIL_ON_WIN_ERROR(err); pdwRids[dwTotalNumDomainEntries + dwTotalNumBtinDomainEntries + i] = pdwBtinDomainRids[i]; } dwTotalNumBtinDomainEntries += dwNumBtinDomainEntries; dwNumBtinDomainEntries = 0; if (ppwszBtinDomainAliases) { SamrFreeMemory(ppwszBtinDomainAliases); ppwszBtinDomainAliases = NULL; } if (pdwBtinDomainRids) { SamrFreeMemory(pdwBtinDomainRids); pdwBtinDomainRids = NULL; } } while (status == STATUS_MORE_ENTRIES); for (i = dwResume; i < dwTotalNumEntries; i++) { if (dwLevel == 0) { pSourceBuffer = ppwszAliases[i]; } else { DOMAIN_HANDLE hDom = NULL; DWORD dwRid = 0; hDom = (i < dwTotalNumDomainEntries) ? hDomain : hBtinDomain; dwRid = pdwRids[i]; status = SamrOpenAlias(hSamrBinding, hDom, dwAliasAccessFlags, dwRid, &hAlias); BAIL_ON_NT_STATUS(status); status = SamrQueryAliasInfo(hSamrBinding, hAlias, wInfoLevel, &pSamrAliasInfo); BAIL_ON_NT_STATUS(status); ppAliasInfo[i - dwResume] = &pSamrAliasInfo->all; pSourceBuffer = &pSamrAliasInfo->all; status = SamrClose(hSamrBinding, hAlias); BAIL_ON_NT_STATUS(status); } dwSize = 0; err = NetAllocateLocalGroupInfo(NULL, NULL, dwLevel, pSourceBuffer, &dwSize, eValidation); BAIL_ON_WIN_ERROR(err); dwTotalSize += dwSize; dwNumEntries++; if (dwTotalSize > dwMaxBufferSize) { dwTotalSize -= dwSize; dwNumEntries--; break; } } if (dwTotalNumEntries > 0 && dwNumEntries == 0) { err = ERROR_INSUFFICIENT_BUFFER; BAIL_ON_WIN_ERROR(err); } if (dwTotalSize) { status = NetAllocateMemory(OUT_PPVOID(&pBuffer), dwTotalSize); BAIL_ON_NT_STATUS(status); } dwSize = 0; pBufferCursor = pBuffer; dwSpaceAvailable = dwTotalSize; for (i = 0; i < dwNumEntries; i++) { if (dwLevel == 0) { pSourceBuffer = ppwszAliases[dwResume + i]; } else { pSourceBuffer = ppAliasInfo[i]; } pBufferCursor = pBuffer + (i * dwInfoLevelSize); err = NetAllocateLocalGroupInfo(pBufferCursor, &dwSpaceAvailable, dwLevel, pSourceBuffer, &dwSize, eValidation); BAIL_ON_WIN_ERROR(err); } if (dwResume + dwNumEntries < dwTotalNumEntries) { err = ERROR_MORE_DATA; } *ppBuffer = pBuffer; *pdwNumEntries = dwNumEntries; *pdwTotalNumEntries = dwTotalNumEntries; *pdwResume = dwResume + dwNumEntries; cleanup: NetDisconnectSamr(&pConn); if (pdwRids) { NetFreeMemory(pdwRids); } if (ppwszAliases) { for (i = 0; i < dwTotalNumEntries; i++) { LW_SAFE_FREE_MEMORY(ppwszAliases[i]); } NetFreeMemory(ppwszAliases); } if (ppAliasInfo) { for (i = 0; i < dwNumEntries; i++) { if (ppAliasInfo[i]) { SamrFreeMemory(ppAliasInfo[i]); } } NetFreeMemory(ppAliasInfo); } if (ppwszDomainAliases) { SamrFreeMemory(ppwszDomainAliases); } if (pdwDomainRids) { SamrFreeMemory(pdwDomainRids); } if (ppwszBtinDomainAliases) { SamrFreeMemory(ppwszBtinDomainAliases); } if (pdwBtinDomainRids) { SamrFreeMemory(pdwBtinDomainRids); } if (pCreds) { LwIoDeleteCreds(pCreds); } if (err == ERROR_SUCCESS && status != STATUS_SUCCESS) { err = NtStatusToWin32Error(status); } return err; error: if (pBuffer) { NetFreeMemory(pBuffer); } *ppBuffer = NULL; *pdwNumEntries = 0; *pdwTotalNumEntries = 0; *pdwResume = 0; goto cleanup; }
/** * @brief Get Local Share path based on Windows path * When migrating shares, we want to create all shares under the * folder where our C$ is set to. * * The Likewise CIFS code maps C$ itself to /. * * For instance, if the remote share was at the physical path * C:\likewise, and our default share path was "/lwcifs", we would map * the remote path "C:\likewise" to "C:\lwcifs\likewise". * */ DWORD LwTaskGetLocalSharePathW( PWSTR pwszSharePathWindows, PWSTR* ppwszSharePathLocal ) { DWORD dwError = 0; wchar16_t wszBackslash[] = {'\\', 0}; wchar16_t wszFwdslash[] = {'/', 0}; wchar16_t wszColon[] = {':', 0}; size_t sSharePathWindowsLen = 0; size_t sRequiredLen = 0; size_t sFSPrefixLen = 3; // length("C:\"); PWSTR pwszPathReadCursor = pwszSharePathWindows; PWSTR pwszPathWriteCursor = NULL; PWSTR pwszSharePathLocal = NULL; PWSTR pwszDefaultSharePath = NULL; if (IsNullOrEmptyString(pwszSharePathWindows)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_LW_TASK_ERROR(dwError); } pwszDefaultSharePath = gLwTaskGlobals.pwszDefaultSharePath; while (!IsNullOrEmptyString(pwszDefaultSharePath) && ((*pwszDefaultSharePath == wszBackslash[0]) || (*pwszDefaultSharePath == wszFwdslash[0]))) { pwszDefaultSharePath++; } if (IsNullOrEmptyString(pwszDefaultSharePath)) { dwError = LwAllocateWc16String( &pwszSharePathLocal, pwszSharePathWindows); BAIL_ON_LW_TASK_ERROR(dwError); goto done; } sSharePathWindowsLen = wc16slen(pwszSharePathWindows); if (((pwszSharePathWindows[1] != wszColon[0]) && !(pwszSharePathWindows[2] == wszBackslash[0] || pwszSharePathWindows[2] == wszFwdslash[0]))) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_LW_TASK_ERROR(dwError); } else { pwszPathReadCursor += sFSPrefixLen; } if ((wc16slen(pwszPathReadCursor) >= wc16slen(pwszDefaultSharePath)) && !wc16scasecmp(pwszPathReadCursor, pwszDefaultSharePath)) { // Already have the required prefix ? dwError = LwAllocateWc16String( &pwszSharePathLocal, pwszSharePathWindows); BAIL_ON_LW_TASK_ERROR(dwError); goto done; } sRequiredLen = (wc16slen(pwszSharePathWindows) + wc16slen(pwszDefaultSharePath) + 2 )* sizeof(wchar16_t); dwError = LwAllocateMemory(sRequiredLen, (PVOID*)&pwszSharePathLocal); BAIL_ON_LW_TASK_ERROR(dwError); pwszPathWriteCursor = pwszSharePathLocal; pwszPathReadCursor = pwszSharePathWindows; memcpy( (PBYTE)pwszPathWriteCursor, (PBYTE)pwszPathReadCursor, sFSPrefixLen * sizeof(wchar16_t)); pwszPathWriteCursor += sFSPrefixLen; pwszPathReadCursor += sFSPrefixLen; memcpy( (PBYTE)pwszPathWriteCursor, (PBYTE)pwszDefaultSharePath, wc16slen(pwszDefaultSharePath) * sizeof(wchar16_t)); pwszPathWriteCursor += wc16slen(pwszDefaultSharePath); *pwszPathWriteCursor++ = wszBackslash[0]; memcpy( (PBYTE)pwszPathWriteCursor, (PBYTE)pwszPathReadCursor, wc16slen(pwszPathReadCursor) * sizeof(wchar16_t)); pwszPathWriteCursor = pwszSharePathLocal; while (!IsNullOrEmptyString(pwszPathWriteCursor)) { if (*pwszPathWriteCursor == wszFwdslash[0]) { *pwszPathWriteCursor = wszBackslash[0]; } pwszPathWriteCursor++; } done: *ppwszSharePathLocal = pwszSharePathLocal; cleanup: return dwError; error: *ppwszSharePathLocal = NULL; LW_SAFE_FREE_MEMORY(pwszSharePathLocal); goto cleanup; }
DWORD LsaSrvPrivsLookupPrivilegeDescription( IN OPTIONAL HANDLE hServer, IN OPTIONAL PACCESS_TOKEN AccessToken, IN PCWSTR PrivilegeName, IN SHORT ClientLanguageId, IN SHORT ClientSystemLanguageId, OUT PWSTR *pPrivilegeDescription, OUT PUSHORT pLanguageId ) { DWORD err = ERROR_SUCCESS; NTSTATUS ntStatus = STATUS_SUCCESS; PLSASRV_PRIVILEGE_GLOBALS pGlobals = &gLsaPrivilegeGlobals; PACCESS_TOKEN accessToken = AccessToken; BOOLEAN releaseAccessToken = FALSE; ACCESS_MASK accessRights = LSA_ACCESS_VIEW_POLICY_INFO; ACCESS_MASK grantedAccess = 0; GENERIC_MAPPING genericMapping = {0}; PSTR pszPrivilegeName = NULL; PLSA_PRIVILEGE pPrivilegeEntry = NULL; PWSTR privilegeDescription = NULL; USHORT descriptionLanguageId = 0; if (!accessToken) { err = LsaSrvPrivsGetAccessTokenFromServerHandle( hServer, &accessToken); BAIL_ON_LSA_ERROR(err); releaseAccessToken = TRUE; } if (!RtlAccessCheck(pGlobals->pPrivilegesSecDesc, accessToken, accessRights, 0, &genericMapping, &grantedAccess, &ntStatus)) { BAIL_ON_NT_STATUS(ntStatus); } if (ClientLanguageId || ClientSystemLanguageId) { // // Right now we don't support multilingual privilege descriptions // so just return 0x0409 (which means "en-US") whenever a caller // requests some particular language id // descriptionLanguageId = 0x0409; } err = LwWc16sToMbs(PrivilegeName, &pszPrivilegeName); BAIL_ON_LSA_ERROR(err); err = LsaSrvGetPrivilegeEntryByName( pszPrivilegeName, &pPrivilegeEntry); BAIL_ON_LSA_ERROR(err); err = LwAllocateWc16String( &privilegeDescription, pPrivilegeEntry->pwszDescription); BAIL_ON_LSA_ERROR(err); *pPrivilegeDescription = privilegeDescription; *pLanguageId = descriptionLanguageId; error: if (err || ntStatus) { if (pPrivilegeDescription) { *pPrivilegeDescription = NULL; } if (pLanguageId) { *pLanguageId = 0; } } LW_SAFE_FREE_MEMORY(pszPrivilegeName); if (releaseAccessToken) { RtlReleaseAccessToken(&accessToken); } if (err == ERROR_SUCCESS && ntStatus != STATUS_SUCCESS) { err = LwNtStatusToWin32Error(ntStatus); } return err; }
NTSTATUS NetOpenUser( PNET_CONN pConn, PCWSTR pwszUsername, DWORD dwAccessMask, ACCOUNT_HANDLE *phUser, PDWORD pdwRid ) { const DWORD dwNumUsers = 1; NTSTATUS status = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; SAMR_BINDING hSamrBinding = NULL; DOMAIN_HANDLE hDomain = NULL; ACCOUNT_HANDLE hUser = NULL; PWSTR ppwszUsernames[1] = {0}; PDWORD pdwRids = NULL; PDWORD pdwTypes = NULL; BAIL_ON_INVALID_PTR(pConn, err); BAIL_ON_INVALID_PTR(pwszUsername, err); BAIL_ON_INVALID_PTR(phUser, err); BAIL_ON_INVALID_PTR(pdwRid, err); hSamrBinding = pConn->Rpc.Samr.hBinding; hDomain = pConn->Rpc.Samr.hDomain; err = LwAllocateWc16String(&ppwszUsernames[0], pwszUsername); BAIL_ON_WIN_ERROR(err); status = SamrLookupNames(hSamrBinding, hDomain, dwNumUsers, ppwszUsernames, &pdwRids, &pdwTypes, NULL); BAIL_ON_NT_STATUS(status); status = SamrOpenUser(hSamrBinding, hDomain, dwAccessMask, pdwRids[0], &hUser); BAIL_ON_NT_STATUS(status); *pdwRid = pdwRids[0]; *phUser = hUser; cleanup: if (pdwRids) { SamrFreeMemory(pdwRids); } if (pdwTypes) { SamrFreeMemory(pdwTypes); } LW_SAFE_FREE_MEMORY(ppwszUsernames[0]); return status; error: *pdwRid = 0; *phUser = NULL; goto cleanup; }
NTSTATUS NetOpenAlias( PNET_CONN pConn, PCWSTR pwszAliasname, DWORD dwAccessMask, ACCOUNT_HANDLE *phAlias, PDWORD pdwRid ) { const DWORD dwNumAliases = 1; NTSTATUS status = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; SAMR_BINDING hSamrBinding = NULL; DOMAIN_HANDLE hDomains[2] = {0}; DOMAIN_HANDLE hDomain = NULL; ACCOUNT_HANDLE hAlias = NULL; PWSTR ppwszAliasnames[1] = {0}; PDWORD pdwRids = NULL; PDWORD pdwTypes = NULL; DWORD dwAliasRid = 0; DWORD i = 0; BAIL_ON_INVALID_PTR(pConn, err); BAIL_ON_INVALID_PTR(pwszAliasname, err); BAIL_ON_INVALID_PTR(phAlias, err); BAIL_ON_INVALID_PTR(pdwRid, err); hSamrBinding = pConn->Rpc.Samr.hBinding; hDomains[0] = pConn->Rpc.Samr.hDomain; hDomains[1] = pConn->Rpc.Samr.hBuiltin; err = LwAllocateWc16String(&ppwszAliasnames[0], pwszAliasname); BAIL_ON_WIN_ERROR(err); /* * Try to look for alias in host domain first, then in builtin */ for (i = 0; i < sizeof(hDomains)/sizeof(hDomains[0]); i++) { status = SamrLookupNames(hSamrBinding, hDomains[i], dwNumAliases, ppwszAliasnames, (PUINT32*)&pdwRids, (PUINT32*)&pdwTypes, NULL); if (status == STATUS_SUCCESS) { /* * Alias has been found in one of domains so pass * that domain handle further down */ hDomain = hDomains[i]; dwAliasRid = pdwRids[0]; break; } else if (status == STATUS_NONE_MAPPED) { if (pdwRids) { SamrFreeMemory((void*)pdwRids); pdwRids = NULL; } if (pdwTypes) { SamrFreeMemory((void*)pdwTypes); pdwTypes = NULL; } continue; } /* Catch other possible errors */ BAIL_ON_NT_STATUS(status); } /* Allow to open alias only if a valid one has been found */ BAIL_ON_NT_STATUS(status); status = SamrOpenAlias(hSamrBinding, hDomain, dwAccessMask, dwAliasRid, &hAlias); BAIL_ON_NT_STATUS(status); *pdwRid = dwAliasRid; *phAlias = hAlias; cleanup: LW_SAFE_FREE_MEMORY(ppwszAliasnames[0]); if (pdwRids) { SamrFreeMemory((void*)pdwRids); } if (pdwTypes) { SamrFreeMemory((void*)pdwTypes); } return status; error: *pdwRid = 0; *phAlias = NULL; goto cleanup; }
NTSTATUS NetrSamLogoff( IN NETR_BINDING hBinding, IN NetrCredentials *pCreds, IN PCWSTR pwszServer, IN PCWSTR pwszDomain, IN PCWSTR pwszComputer, IN PCWSTR pwszUsername, IN PCWSTR pwszPassword, IN UINT32 LogonLevel ) { NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwError = ERROR_SUCCESS; PWSTR pwszServerName = NULL; PWSTR pwszComputerName = NULL; NetrAuth *pAuth = NULL; NetrAuth *pReturnedAuth = NULL; NetrLogonInfo LogonInfo = {0}; NetrPasswordInfo *pPassInfo = NULL; DWORD dwOffset = 0; DWORD dwSpaceLeft = 0; DWORD dwSize = 0; BAIL_ON_INVALID_PTR(hBinding, ntStatus); BAIL_ON_INVALID_PTR(pCreds, ntStatus); BAIL_ON_INVALID_PTR(pwszServer, ntStatus); /* pwszDomain can be NULL */ BAIL_ON_INVALID_PTR(pwszComputer, ntStatus); BAIL_ON_INVALID_PTR(pwszUsername, ntStatus); BAIL_ON_INVALID_PTR(pwszPassword, ntStatus); if (!(LogonLevel == 1 || LogonLevel == 3 || LogonLevel == 5)) { ntStatus = STATUS_INVALID_INFO_CLASS; BAIL_ON_NT_STATUS(ntStatus); } dwError = LwAllocateWc16String(&pwszServerName, pwszServer); BAIL_ON_WIN_ERROR(dwError); dwError = LwAllocateWc16String(&pwszComputerName, pwszComputer); BAIL_ON_WIN_ERROR(dwError); /* Create authenticator info with credentials chain */ ntStatus = NetrAllocateMemory(OUT_PPVOID(&pAuth), sizeof(NetrAuth)); BAIL_ON_NT_STATUS(ntStatus); pCreds->sequence += 2; NetrCredentialsCliStep(pCreds); pAuth->timestamp = pCreds->sequence; memcpy(pAuth->cred.data, pCreds->cli_chal.data, sizeof(pAuth->cred.data)); /* Allocate returned authenticator */ ntStatus = NetrAllocateMemory(OUT_PPVOID(&pReturnedAuth), sizeof(NetrAuth)); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NetrAllocateLogonPasswordInfo(NULL, &dwOffset, NULL, pwszDomain, pwszComputerName, pwszUsername, pwszPassword, pCreds, &dwSize); BAIL_ON_NT_STATUS(ntStatus); dwSpaceLeft = dwSize; dwSize = 0; dwOffset = 0; ntStatus = NetrAllocateMemory(OUT_PPVOID(&pPassInfo), dwSpaceLeft); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NetrAllocateLogonPasswordInfo(pPassInfo, &dwOffset, &dwSpaceLeft, pwszDomain, pwszComputerName, pwszUsername, pwszPassword, pCreds, &dwSize); BAIL_ON_NT_STATUS(ntStatus); switch (LogonLevel) { case 1: LogonInfo.password1 = pPassInfo; break; case 3: LogonInfo.password3 = pPassInfo; break; case 5: LogonInfo.password5 = pPassInfo; break; } DCERPC_CALL(ntStatus, cli_NetrLogonSamLogoff(hBinding, pwszServerName, pwszComputerName, pAuth, pReturnedAuth, LogonLevel, &LogonInfo)); BAIL_ON_NT_STATUS(ntStatus); cleanup: LW_SAFE_FREE_MEMORY(pwszServerName); LW_SAFE_FREE_MEMORY(pwszComputerName); if (pAuth) { NetrFreeMemory(pAuth); } if (pReturnedAuth) { NetrFreeMemory(pReturnedAuth); } if (pPassInfo) { NetrFreeMemory(pPassInfo); } if (ntStatus == STATUS_SUCCESS && dwError != ERROR_SUCCESS) { ntStatus = LwWin32ErrorToNtStatus(dwError); } return ntStatus; error: goto cleanup; }
NET_API_STATUS NetJoinDomain( IN PCWSTR pwszServerName, IN PCWSTR pwszDomainName, IN PCWSTR pwszAccountOu, IN PCWSTR pwszAccountName, IN PCWSTR pwszPassword, IN DWORD dwJoinFlags ) { WINERROR err = ERROR_SUCCESS; NTSTATUS ntStatus = STATUS_SUCCESS; PNET_CONN pConn = NULL; WKSS_BINDING hWkssBinding = NULL; PWSTR pwszServer = NULL; PWSTR pwszDomain = NULL; PWSTR pwszAccount = NULL; PWSTR pwszOu = NULL; PIO_CREDS pCreds = NULL; ENC_JOIN_PASSWORD_BUFFER PasswordBuffer; BAIL_ON_INVALID_PTR(pwszDomainName, err); BAIL_ON_INVALID_PTR(pwszAccountName, err); BAIL_ON_INVALID_PTR(pwszPassword, err); memset(&PasswordBuffer, 0, sizeof(PasswordBuffer)); ntStatus = LwIoGetActiveCreds(NULL, &pCreds); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NetConnectWkssvc(&pConn, pwszServerName, pCreds); BAIL_ON_NT_STATUS(ntStatus); hWkssBinding = pConn->Rpc.WksSvc.hBinding; if (pwszServerName) { err = LwAllocateWc16String(&pwszServer, pwszServerName); BAIL_ON_WIN_ERROR(err); } err = LwAllocateWc16String(&pwszDomain, pwszDomainName); BAIL_ON_WIN_ERROR(err); err = LwAllocateWc16String(&pwszAccount, pwszAccountName); BAIL_ON_WIN_ERROR(err); if (pwszAccountOu) { err = LwAllocateWc16String(&pwszOu, pwszAccountOu); BAIL_ON_WIN_ERROR(err); } err = NetEncryptJoinPasswordBuffer(pConn, pwszPassword, &PasswordBuffer); BAIL_ON_WIN_ERROR(err); err = NetrJoinDomain2(hWkssBinding, pwszServer, pwszDomain, pwszOu, pwszAccount, &PasswordBuffer, dwJoinFlags); BAIL_ON_WIN_ERROR(err); cleanup: if (pConn) { NetDisconnectWkssvc(&pConn); } memset(&PasswordBuffer, 0, sizeof(PasswordBuffer)); LW_SAFE_FREE_MEMORY(pwszServer); LW_SAFE_FREE_MEMORY(pwszDomain); LW_SAFE_FREE_MEMORY(pwszOu); LW_SAFE_FREE_MEMORY(pwszAccount); if (pCreds) { LwIoDeleteCreds(pCreds); } if (err == ERROR_SUCCESS && ntStatus != STATUS_SUCCESS) { err = LwNtStatusToWin32Error(ntStatus); } return (NET_API_STATUS)err; error: goto cleanup; }