static DWORD LsaUnjoinDomain( IN PCWSTR pwszDnsDomainName, IN PCWSTR pwszMachineSamAccountName, IN OPTIONAL PCWSTR pwszUserName, IN OPTIONAL PCWSTR pwszUserDomain, IN OPTIONAL PCWSTR pwszUserPassword, IN DWORD dwUnjoinFlags ) { DWORD dwError = ERROR_SUCCESS; NTSTATUS ntStatus = STATUS_SUCCESS; PWSTR pwszDCName = NULL; PIO_CREDS pCreds = NULL; dwError = LsaGetRwDcName(pwszDnsDomainName, FALSE, &pwszDCName); BAIL_ON_LSA_ERROR(dwError); /* disable the account only if requested */ if (dwUnjoinFlags & LSAJOIN_ACCT_DELETE) { if (pwszUserName && pwszUserPassword) { ntStatus = LwIoCreatePlainCredsW(pwszUserName, pwszUserDomain, pwszUserPassword, &pCreds); dwError = LwNtStatusToWin32Error(ntStatus); BAIL_ON_LSA_ERROR(dwError); } else { ntStatus = LwIoGetActiveCreds(NULL, &pCreds); dwError = LwNtStatusToWin32Error(ntStatus); BAIL_ON_LSA_ERROR(dwError); } ntStatus = LsaDisableMachineAccount(pwszDCName, pCreds, pwszMachineSamAccountName); dwError = LwNtStatusToWin32Error(ntStatus); BAIL_ON_LSA_ERROR(dwError); } error: LSA_ASSERT(!ntStatus || dwError); LW_SAFE_FREE_MEMORY(pwszDCName); if (pCreds) { LwIoDeleteCreds(pCreds); } return dwError; }
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; }
NET_API_STATUS NetGetDomainName( IN PCWSTR pwszHostname, OUT PWSTR *ppwszDomainName ) { const DWORD dwConnAccess = SAMR_ACCESS_OPEN_DOMAIN | SAMR_ACCESS_ENUM_DOMAINS; NTSTATUS ntStatus = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; PNET_CONN pConn = NULL; size_t sDomainNameLen = 0; PWSTR pwszDomainName = NULL; PIO_CREDS pCreds = NULL; BAIL_ON_INVALID_PTR(ppwszDomainName, err); ntStatus = LwIoGetActiveCreds(NULL, &pCreds); BAIL_ON_NT_STATUS(ntStatus); ntStatus = NetConnectSamr(&pConn, pwszHostname, dwConnAccess, 0, pCreds); BAIL_ON_NT_STATUS(ntStatus); err = LwWc16sLen(pConn->Rpc.Samr.pwszDomainName, &sDomainNameLen); BAIL_ON_WIN_ERROR(err); ntStatus = NetAllocateMemory( OUT_PPVOID(&pwszDomainName), sizeof(pwszDomainName[0]) * (sDomainNameLen + 1)); BAIL_ON_NT_STATUS(ntStatus); err = LwWc16snCpy(pwszDomainName, pConn->Rpc.Samr.pwszDomainName, sDomainNameLen); BAIL_ON_WIN_ERROR(err); *ppwszDomainName = pwszDomainName; cleanup: NetDisconnectSamr(&pConn); if (pCreds) { LwIoDeleteCreds(pCreds); } if (err == ERROR_SUCCESS && ntStatus != STATUS_SUCCESS) { err = NtStatusToWin32Error(ntStatus); } return err; error: if (pwszDomainName) { NetFreeMemory(pwszDomainName); } *ppwszDomainName = NULL; goto cleanup; }
NTSTATUS LwNtCreateFile( OUT PIO_FILE_HANDLE FileHandle, IN OUT OPTIONAL PIO_ASYNC_CONTROL_BLOCK AsyncControlBlock, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PIO_FILE_NAME FileName, IN OPTIONAL PSECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor, IN OPTIONAL PVOID SecurityQualityOfService, // TBD IN ACCESS_MASK DesiredAccess, IN OPTIONAL LONG64 AllocationSize, IN FILE_ATTRIBUTES FileAttributes, IN FILE_SHARE_FLAGS ShareAccess, IN FILE_CREATE_DISPOSITION CreateDisposition, IN FILE_CREATE_OPTIONS CreateOptions, IN OPTIONAL PVOID EaBuffer, // PFILE_FULL_EA_INFORMATION IN ULONG EaLength, IN OPTIONAL PIO_ECP_LIST EcpList, IN OPTIONAL LW_PIO_CREDS pCreds ) { NTSTATUS status = 0; int EE = 0; PIO_CREDS pActiveCreds = NULL; PCREATEFILE_CONTEXT pCreateContext = NULL; if (!pCreds) { status = LwIoGetActiveCreds(FileName->FileName, &pActiveCreds); GOTO_CLEANUP_ON_STATUS_EE(status, EE); pCreds = pActiveCreds; } status = NtpAllocAsyncContext(OUT_PPVOID(&pCreateContext), sizeof(*pCreateContext)); GOTO_CLEANUP_ON_STATUS_EE(status, EE); pCreateContext->IoStatusBlock = IoStatusBlock; pCreateContext->FileHandle = FileHandle; status = LwIoResolveCreds(pCreds, &pCreateContext->Request.pSecurityToken); GOTO_CLEANUP_ON_STATUS_EE(status, EE); pCreateContext->Request.FileName = *FileName; pCreateContext->Request.DesiredAccess = DesiredAccess; pCreateContext->Request.AllocationSize = AllocationSize; pCreateContext->Request.FileAttributes = FileAttributes; pCreateContext->Request.ShareAccess = ShareAccess; pCreateContext->Request.CreateDisposition = CreateDisposition; pCreateContext->Request.CreateOptions = CreateOptions; pCreateContext->Request.EaBuffer = EaBuffer; pCreateContext->Request.EaLength = EaLength; if (SecurityDescriptor) { pCreateContext->Request.SecurityDescriptor = SecurityDescriptor; pCreateContext->Request.SecDescLength = RtlLengthSecurityDescriptorRelative(SecurityDescriptor); } pCreateContext->Request.EcpCount = IoRtlEcpListGetCount(EcpList); if (pCreateContext->Request.EcpCount) { PCSTR pszType = NULL; ULONG ecpIndex = 0; status = RTL_ALLOCATE( &pCreateContext->Request.EcpList, NT_IPC_HELPER_ECP, sizeof(*pCreateContext->Request.EcpList) * pCreateContext->Request.EcpCount); GOTO_CLEANUP_ON_STATUS_EE(status, EE); while (ecpIndex < pCreateContext->Request.EcpCount) { status = IoRtlEcpListGetNext( EcpList, pszType, &pCreateContext->Request.EcpList[ecpIndex].pszType, &pCreateContext->Request.EcpList[ecpIndex].pData, &pCreateContext->Request.EcpList[ecpIndex].Size); GOTO_CLEANUP_ON_STATUS_EE(status, EE); pszType = pCreateContext->Request.EcpList[ecpIndex].pszType; ecpIndex++; } assert(ecpIndex == pCreateContext->Request.EcpCount); status = STATUS_SUCCESS; } status = NtpCtxCallAsync( &pCreateContext->Base, NT_IPC_MESSAGE_TYPE_CREATE_FILE, &pCreateContext->Request, NT_IPC_MESSAGE_TYPE_CREATE_FILE_RESULT, AsyncControlBlock, LwNtCreateFileComplete); GOTO_CLEANUP_ON_STATUS_EE(status, EE); cleanup: if (pActiveCreds) { LwIoDeleteCreds(pActiveCreds); } if (status != STATUS_PENDING) { if (pCreateContext) { LwNtCreateFileComplete(&pCreateContext->Base, status); status = IoStatusBlock->Status; NtpFreeClientAsyncContext(&pCreateContext->Base); } else { IoStatusBlock->Status = status; } } LOG_LEAVE_IF_STATUS_EE(status, EE); return status; }
NET_API_STATUS NetUserGetLocalGroups( PCWSTR pwszHostname, PCWSTR pwszUsername, DWORD dwLevel, DWORD dwFlags, PVOID *ppBuffer, DWORD dwMaxBufferSize, PDWORD pdwNumEntries, PDWORD pdwTotalEntries ) { const DWORD dwBuiltinDomainAccess = DOMAIN_ACCESS_OPEN_ACCOUNT | DOMAIN_ACCESS_ENUM_ACCOUNTS; const DWORD dwUserAccess = USER_ACCESS_GET_GROUP_MEMBERSHIP; NTSTATUS status = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; PNET_CONN pConn = NULL; SAMR_BINDING hSamrBinding = NULL; DOMAIN_HANDLE hDomain = NULL; DOMAIN_HANDLE hBtinDomain = NULL; ACCOUNT_HANDLE hUser = NULL; PSID pDomainSid = NULL; PSID pUserSid = NULL; DWORD dwUserRid = 0; DWORD dwSidLen = 0; DWORD i = 0; PDWORD pdwUserRids = NULL; PDWORD pdwBuiltinUserRids = NULL; DWORD dwRidsCount = 0; DWORD dwBuiltinRidsCount = 0; DWORD dwInfoLevelSize = 0; DWORD dwTotalNumEntries = 0; PWSTR *ppwszAliasNames = NULL; PWSTR *ppwszBuiltinAliasNames = NULL; PDWORD pdwAliasTypes = NULL; PDWORD pdwBuiltinAliasTypes = NULL; PWSTR *ppwszLocalGroupNames = NULL; PVOID pSourceBuffer = NULL; PVOID pBuffer = NULL; PVOID pBufferCursor = NULL; DWORD dwSize = 0; DWORD dwTotalSize = 0; DWORD dwNumEntries = 0; DWORD dwSpaceAvailable = 0; PIO_CREDS pCreds = NULL; NET_VALIDATION_LEVEL eValidation = NET_VALIDATION_NONE; BAIL_ON_INVALID_PTR(pwszUsername, err); BAIL_ON_INVALID_PTR(ppBuffer, err); BAIL_ON_INVALID_PTR(pdwNumEntries, err); BAIL_ON_INVALID_PTR(pdwTotalEntries, err); switch (dwLevel) { case 0: dwInfoLevelSize = sizeof(LOCALGROUP_USERS_INFO_0); break; default: err = ERROR_INVALID_LEVEL; BAIL_ON_WIN_ERROR(err); } status = LwIoGetActiveCreds(NULL, &pCreds); BAIL_ON_NT_STATUS(status); status = NetConnectSamr(&pConn, pwszHostname, 0, dwBuiltinDomainAccess, pCreds); BAIL_ON_NT_STATUS(status); hSamrBinding = pConn->Rpc.Samr.hBinding; hDomain = pConn->Rpc.Samr.hDomain; hBtinDomain = pConn->Rpc.Samr.hBuiltin; pDomainSid = pConn->Rpc.Samr.pDomainSid; status = NetOpenUser(pConn, pwszUsername, dwUserAccess, &hUser, &dwUserRid); BAIL_ON_NT_STATUS(status); dwSidLen = RtlLengthRequiredSid(pDomainSid->SubAuthorityCount + 1); err = LwAllocateMemory(dwSidLen, OUT_PPVOID(&pUserSid)); BAIL_ON_WIN_ERROR(err); status = RtlCopySid(dwSidLen, pUserSid, pDomainSid); BAIL_ON_NT_STATUS(status); status = RtlAppendRidSid(dwSidLen, pUserSid, dwUserRid); BAIL_ON_NT_STATUS(status); status = SamrGetAliasMembership(hSamrBinding, hDomain, &pUserSid, 1, &pdwUserRids, &dwRidsCount); BAIL_ON_NT_STATUS(status); status = SamrGetAliasMembership(hSamrBinding, hBtinDomain, &pUserSid, 1, &pdwBuiltinUserRids, &dwBuiltinRidsCount); BAIL_ON_NT_STATUS(status); dwTotalNumEntries = dwRidsCount + dwBuiltinRidsCount; err = LwAllocateMemory( sizeof(ppwszLocalGroupNames[0]) * dwTotalNumEntries, OUT_PPVOID(&ppwszLocalGroupNames)); BAIL_ON_WIN_ERROR(err); if (dwRidsCount > 0) { status = SamrLookupRids(hSamrBinding, hDomain, dwRidsCount, pdwUserRids, &ppwszAliasNames, &pdwAliasTypes); BAIL_ON_NT_STATUS(status); for (i = 0; i < dwRidsCount; i++) { ppwszLocalGroupNames[i] = ppwszAliasNames[i]; } } if (dwBuiltinRidsCount > 0) { status = SamrLookupRids(hSamrBinding, hBtinDomain, dwBuiltinRidsCount, pdwBuiltinUserRids, &ppwszBuiltinAliasNames, &pdwBuiltinAliasTypes); BAIL_ON_NT_STATUS(status); for (i = 0; i < dwBuiltinRidsCount; i++) { ppwszLocalGroupNames[i + dwRidsCount] = ppwszBuiltinAliasNames[i]; } } for (i = 0; i < dwTotalNumEntries; i++) { pSourceBuffer = ppwszLocalGroupNames[i]; dwSize = 0; err = NetAllocateLocalGroupUsersInfo(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++) { pSourceBuffer = ppwszLocalGroupNames[i]; pBufferCursor = pBuffer + (i * dwInfoLevelSize); err = NetAllocateLocalGroupUsersInfo(pBufferCursor, &dwSpaceAvailable, dwLevel, pSourceBuffer, &dwSize, eValidation); BAIL_ON_WIN_ERROR(err); } if (dwNumEntries < dwTotalNumEntries) { err = ERROR_MORE_DATA; } status = SamrClose(hSamrBinding, hUser); BAIL_ON_NT_STATUS(status); *ppBuffer = pBuffer; *pdwNumEntries = dwNumEntries; *pdwTotalEntries = dwTotalNumEntries; cleanup: LW_SAFE_FREE_MEMORY(pUserSid); LW_SAFE_FREE_MEMORY(ppwszLocalGroupNames); if (pdwUserRids) { SamrFreeMemory(pdwUserRids); } if (pdwBuiltinUserRids) { SamrFreeMemory(pdwBuiltinUserRids); } if (ppwszAliasNames) { SamrFreeMemory(ppwszAliasNames); } if (pdwAliasTypes) { SamrFreeMemory(pdwAliasTypes); } if (ppwszBuiltinAliasNames) { SamrFreeMemory(ppwszBuiltinAliasNames); } if (pdwBuiltinAliasTypes) { SamrFreeMemory(pdwBuiltinAliasTypes); } if (pCreds) { LwIoDeleteCreds(pCreds); } return err; error: if (pBuffer) { NetFreeMemory(pBuffer); } *ppBuffer = NULL; *pdwNumEntries = 0; *pdwTotalEntries = 0; goto cleanup; }
NET_API_STATUS NetUserAdd( PCWSTR pwszHostname, DWORD dwLevel, PVOID pBuffer, PDWORD pdwParmErr ) { const DWORD dwUserAccess = USER_ACCESS_GET_NAME_ETC | USER_ACCESS_SET_LOC_COM | USER_ACCESS_GET_LOCALE | USER_ACCESS_GET_LOGONINFO | USER_ACCESS_GET_ATTRIBUTES | USER_ACCESS_GET_GROUPS | USER_ACCESS_GET_GROUP_MEMBERSHIP | USER_ACCESS_CHANGE_GROUP_MEMBERSHIP | USER_ACCESS_SET_ATTRIBUTES | USER_ACCESS_SET_PASSWORD; const DWORD dwDomainAccess = DOMAIN_ACCESS_CREATE_USER | DOMAIN_ACCESS_LOOKUP_INFO_1; NTSTATUS status = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; PNET_CONN pConn = NULL; SAMR_BINDING hSamrBinding = NULL; DOMAIN_HANDLE hDomain = NULL; ACCOUNT_HANDLE hUser = NULL; DWORD dwSamrInfoLevel = 0; DWORD dwSamrPasswordInfoLevel = 0; DWORD dwParmErr = 0; UserInfo *pSamrUserInfo = NULL; UserInfo *pSamrPasswordUserInfo = NULL; DWORD dwSize = 0; DWORD dwSpaceLeft = 0; PIO_CREDS pCreds = NULL; PWSTR pwszUsername = NULL; DWORD dwRid = 0; BOOL bPasswordSet = FALSE; NET_VALIDATION_LEVEL eValidation = NET_VALIDATION_USER_ADD; BAIL_ON_INVALID_PTR(pBuffer, err); if (!(dwLevel == 1 || dwLevel == 2 || dwLevel == 3 || dwLevel == 4)) { err = ERROR_INVALID_LEVEL; BAIL_ON_WIN_ERROR(err); } status = LwIoGetActiveCreds(NULL, &pCreds); BAIL_ON_NT_STATUS(status); err = NetAllocateSamrUserInfo(NULL, &dwSamrInfoLevel, NULL, dwLevel, pBuffer, pConn, &dwSize, eValidation, &dwParmErr); BAIL_ON_WIN_ERROR(err); dwSpaceLeft = dwSize; dwSize = 0; if (dwSpaceLeft) { status = NetAllocateMemory((void**)&pSamrUserInfo, dwSpaceLeft); BAIL_ON_NT_STATUS(status); } err = NetAllocateSamrUserInfo(&pSamrUserInfo->info21, &dwSamrInfoLevel, &dwSpaceLeft, dwLevel, pBuffer, pConn, &dwSize, eValidation, &dwParmErr); BAIL_ON_WIN_ERROR(err); status = NetConnectSamr(&pConn, pwszHostname, dwDomainAccess, 0, pCreds); BAIL_ON_NT_STATUS(status); hSamrBinding = pConn->Rpc.Samr.hBinding; hDomain = pConn->Rpc.Samr.hDomain; err = LwAllocateWc16StringFromUnicodeString( &pwszUsername, (PUNICODE_STRING)&pSamrUserInfo->info21.account_name); BAIL_ON_WIN_ERROR(err); status = SamrCreateUser(hSamrBinding, hDomain, pwszUsername, dwUserAccess, &hUser, &dwRid); if (status == STATUS_USER_EXISTS) { err = NERR_UserExists; } else if (status == STATUS_ALIAS_EXISTS) { err = NERR_GroupExists; } BAIL_ON_NT_STATUS(status); /* * Check if there's password to be set (if it's NULL * the function returns ERROR_INVALID_PASSWORD) */ dwSamrPasswordInfoLevel = 26; dwSize = 0; err = NetAllocateSamrUserInfo(NULL, &dwSamrPasswordInfoLevel, NULL, dwLevel, pBuffer, pConn, &dwSize, eValidation, &dwParmErr); if (err == ERROR_SUCCESS) { dwSpaceLeft = dwSize; dwSize = 0; if (dwSpaceLeft) { status = NetAllocateMemory((void**)&pSamrPasswordUserInfo, dwSpaceLeft); BAIL_ON_NT_STATUS(status); } err = NetAllocateSamrUserInfo(&pSamrPasswordUserInfo->info26, &dwSamrPasswordInfoLevel, &dwSpaceLeft, dwLevel, pBuffer, pConn, &dwSize, eValidation, &dwParmErr); BAIL_ON_WIN_ERROR(err); status = SamrSetUserInfo(hSamrBinding, hUser, dwSamrPasswordInfoLevel, pSamrPasswordUserInfo); BAIL_ON_NT_STATUS(status); bPasswordSet = TRUE; } else if (err == ERROR_INVALID_PASSWORD) { /* This error only means we're not going to try set the password */ err = ERROR_SUCCESS; } else { BAIL_ON_WIN_ERROR(err); } /* * Prevent from trying to rename (to the same name) the account * that has just been created. Created samr user info buffer * contains whatever is passed from net user info buffer. */ if (dwSamrInfoLevel == 21 && (pSamrUserInfo->info21.fields_present & SAMR_FIELD_ACCOUNT_NAME)) { pSamrUserInfo->info21.fields_present ^= SAMR_FIELD_ACCOUNT_NAME; } /* * Disable the account only if there was no password */ if (!bPasswordSet && dwSamrInfoLevel == 21) { pSamrUserInfo->info21.account_flags |= ACB_DISABLED; } status = SamrSetUserInfo(hSamrBinding, hUser, dwSamrInfoLevel, pSamrUserInfo); BAIL_ON_NT_STATUS(status); status = SamrClose(hSamrBinding, hUser); BAIL_ON_NT_STATUS(status); cleanup: NetDisconnectSamr(&pConn); if (pdwParmErr) { *pdwParmErr = dwParmErr; } if (pSamrUserInfo) { NetFreeMemory(pSamrUserInfo); } if (pSamrPasswordUserInfo) { NetFreeMemory(pSamrPasswordUserInfo); } LW_SAFE_FREE_MEMORY(pwszUsername); if (pCreds) { LwIoDeleteCreds(pCreds); } if (err == ERROR_SUCCESS && status != STATUS_SUCCESS) { err = NtStatusToWin32Error(status); } return err; error: 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; }
NET_API_STATUS NetUserSetInfo( PCWSTR pwszHostname, PCWSTR pwszUsername, DWORD dwLevel, PVOID pBuffer, PDWORD pdwParmErr ) { /* This is necessary to be able to set account password. Otherwise we get access denied. Don't ask... */ const DWORD dwDomainAccess = DOMAIN_ACCESS_LOOKUP_INFO_1; const DWORD dwUserAccess = USER_ACCESS_GET_NAME_ETC | USER_ACCESS_GET_LOCALE | USER_ACCESS_GET_LOGONINFO | USER_ACCESS_GET_ATTRIBUTES | USER_ACCESS_GET_GROUPS | USER_ACCESS_GET_GROUP_MEMBERSHIP | USER_ACCESS_SET_LOC_COM | USER_ACCESS_SET_ATTRIBUTES | USER_ACCESS_CHANGE_PASSWORD | USER_ACCESS_SET_PASSWORD; NTSTATUS status = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; PNET_CONN pConn = NULL; SAMR_BINDING hSamrBinding = NULL; ACCOUNT_HANDLE hUser = NULL; DWORD dwUserRid = 0; DWORD dwSamrInfoLevel = 0; DWORD dwSamrPasswordInfoLevel = 0; DWORD dwParmErr = 0; UserInfo *pSamrUserInfo = NULL; UserInfo *pSamrPasswordUserInfo = NULL; DWORD dwSize = 0; DWORD dwSpaceLeft = 0; PIO_CREDS pCreds = NULL; NET_VALIDATION_LEVEL eValidation = NET_VALIDATION_USER_SET; if (!(dwLevel == 0 || dwLevel == 1 || dwLevel == 2 || dwLevel == 3 || dwLevel == 4 || dwLevel == 1003 || dwLevel == 1007 || dwLevel == 1008 || dwLevel == 1011)) { err = ERROR_INVALID_LEVEL; BAIL_ON_WIN_ERROR(err); } BAIL_ON_INVALID_PTR(pwszUsername, err); BAIL_ON_INVALID_PTR(pBuffer, err); status = LwIoGetActiveCreds(NULL, &pCreds); BAIL_ON_NT_STATUS(status); err = NetAllocateSamrUserInfo(NULL, &dwSamrInfoLevel, NULL, dwLevel, pBuffer, pConn, &dwSize, eValidation, &dwParmErr); BAIL_ON_WIN_ERROR(err); dwSpaceLeft = dwSize; dwSize = 0; if (dwSpaceLeft) { status = NetAllocateMemory(OUT_PPVOID(&pSamrUserInfo), dwSpaceLeft); BAIL_ON_NT_STATUS(status); err = NetAllocateSamrUserInfo(&pSamrUserInfo->info21, &dwSamrInfoLevel, &dwSpaceLeft, dwLevel, pBuffer, pConn, &dwSize, eValidation, &dwParmErr); BAIL_ON_WIN_ERROR(err); } status = NetConnectSamr(&pConn, pwszHostname, dwDomainAccess, 0, pCreds); BAIL_ON_NT_STATUS(status); hSamrBinding = pConn->Rpc.Samr.hBinding; status = NetOpenUser(pConn, pwszUsername, dwUserAccess, &hUser, &dwUserRid); BAIL_ON_NT_STATUS(status); /* * Check if there's password to be set (if it's NULL * the function returns ERROR_INVALID_PASSWORD) */ dwSamrPasswordInfoLevel = 26; dwSize = 0; err = NetAllocateSamrUserInfo(NULL, &dwSamrPasswordInfoLevel, NULL, dwLevel, pBuffer, pConn, &dwSize, eValidation, &dwParmErr); if (err == ERROR_SUCCESS) { dwSpaceLeft = dwSize; dwSize = 0; if (dwSpaceLeft) { status = NetAllocateMemory(OUT_PPVOID(&pSamrPasswordUserInfo), dwSpaceLeft); BAIL_ON_NT_STATUS(status); } err = NetAllocateSamrUserInfo(&pSamrPasswordUserInfo->info26, &dwSamrPasswordInfoLevel, &dwSpaceLeft, dwLevel, pBuffer, pConn, &dwSize, eValidation, &dwParmErr); BAIL_ON_WIN_ERROR(err); status = SamrSetUserInfo(hSamrBinding, hUser, dwSamrPasswordInfoLevel, pSamrPasswordUserInfo); BAIL_ON_NT_STATUS(status); } else if (err == ERROR_INVALID_LEVEL || (err == ERROR_INVALID_PASSWORD && dwLevel != 1003)) { /* This error only means we're not going to try set the password. Either it's set to NULL in infolevel where it's optional or called infolevel doesn't support setting password */ err = ERROR_SUCCESS; } else { BAIL_ON_WIN_ERROR(err); } if (dwSamrInfoLevel) { status = SamrSetUserInfo(hSamrBinding, hUser, dwSamrInfoLevel, pSamrUserInfo); BAIL_ON_NT_STATUS(status); } status = SamrClose(hSamrBinding, hUser); BAIL_ON_NT_STATUS(status); cleanup: NetDisconnectSamr(&pConn); if (pdwParmErr) { *pdwParmErr = dwParmErr; } if (pSamrUserInfo) { NetFreeMemory(pSamrUserInfo); } if (pCreds) { LwIoDeleteCreds(pCreds); } if (err == ERROR_SUCCESS && status != STATUS_SUCCESS) { err = LwNtStatusToWin32Error(status); } return err; 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; }
NET_API_STATUS NetLocalGroupGetMembers( IN PCWSTR pwszHostname, IN PCWSTR pwszAliasname, IN DWORD dwLevel, OUT PVOID *ppBuffer, IN DWORD dwMaxBufferSize, OUT PDWORD pdwNumEntries, OUT PDWORD pdwTotalEntries, OUT PDWORD pdwResume ) { const DWORD dwLsaAccessFlags = LSA_ACCESS_LOOKUP_NAMES_SIDS; const DWORD dwAliasAccessFlags = ALIAS_ACCESS_GET_MEMBERS; const WORD wLookupLevel = 1; NTSTATUS status = STATUS_SUCCESS; WINERROR err = ERROR_SUCCESS; PNET_CONN pConn = NULL; SAMR_BINDING hSamrBinding = NULL; LSA_BINDING hLsaBinding = NULL; ACCOUNT_HANDLE hAlias = NULL; PSID *ppSids = NULL; DWORD dwInfoLevelSize = 0; DWORD dwTotalNumEntries = 0; DWORD dwResume = 0; DWORD dwAliasRid = 0; DWORD i = 0; DWORD dwNumSids = 0; DWORD dwCount = 0; POLICY_HANDLE hLsaPolicy = NULL; SID_ARRAY Sids = {0}; RefDomainList *pDomains = NULL; TranslatedName *pNames = NULL; PNET_RESOLVED_NAME pResolvedNames = NULL; PVOID pSourceBuffer = NULL; PVOID pBuffer = NULL; PVOID pBufferCursor = NULL; DWORD dwSize = 0; DWORD dwTotalSize = 0; DWORD dwNumEntries = 0; DWORD dwSpaceAvailable = 0; PIO_CREDS pCreds = NULL; NET_VALIDATION_LEVEL eValidation = NET_VALIDATION_NONE; BAIL_ON_INVALID_PTR(pwszAliasname, err); BAIL_ON_INVALID_PTR(ppBuffer, err); BAIL_ON_INVALID_PTR(pdwNumEntries, err); BAIL_ON_INVALID_PTR(pdwTotalEntries, err); BAIL_ON_INVALID_PTR(pdwResume, err); switch (dwLevel) { case 0: dwInfoLevelSize = sizeof(LOCALGROUP_MEMBERS_INFO_0); break; case 3: dwInfoLevelSize = sizeof(LOCALGROUP_MEMBERS_INFO_3); break; case 1: case 2: 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; status = NetOpenAlias(pConn, pwszAliasname, dwAliasAccessFlags, &hAlias, &dwAliasRid); if (status == STATUS_NONE_MAPPED) { /* No such alias in host's domain. Try to look in builtin domain. */ status = NetOpenAlias(pConn, pwszAliasname, dwAliasAccessFlags, &hAlias, &dwAliasRid); BAIL_ON_NT_STATUS(status); } else if (status != STATUS_SUCCESS) { BAIL_ON_NT_STATUS(status); } status = SamrGetMembersInAlias(hSamrBinding, hAlias, &ppSids, &dwNumSids); BAIL_ON_NT_STATUS(status); status = SamrClose(hSamrBinding, hAlias); BAIL_ON_NT_STATUS(status); dwTotalNumEntries = dwNumSids; if (dwLevel == 0) { for (i = 0; i + dwResume < dwNumSids; i++) { pSourceBuffer = ppSids[i + dwResume]; err = NetAllocateLocalGroupMembersInfo(NULL, NULL, dwLevel, pSourceBuffer, &dwSize, eValidation); BAIL_ON_WIN_ERROR(err); dwTotalSize += dwSize; dwNumEntries++; if (dwTotalSize > dwMaxBufferSize) { dwTotalSize -= dwSize; dwNumEntries--; break; } } } else { status = NetConnectLsa(&pConn, pwszHostname, dwLsaAccessFlags, pCreds); BAIL_ON_NT_STATUS(status); hLsaBinding = pConn->Rpc.Lsa.hBinding; hLsaPolicy = pConn->Rpc.Lsa.hPolicy; Sids.dwNumSids = dwNumSids; status = NetAllocateMemory(OUT_PPVOID(&Sids.pSids), sizeof(Sids.pSids[0]) * Sids.dwNumSids); BAIL_ON_NT_STATUS(status); for (i = 0; i < Sids.dwNumSids; i++) { Sids.pSids[i].pSid = ppSids[i]; } status = LsaLookupSids(hLsaBinding, hLsaPolicy, &Sids, &pDomains, &pNames, wLookupLevel, &dwCount); if (status != STATUS_SUCCESS && status != LW_STATUS_SOME_NOT_MAPPED) { BAIL_ON_NT_STATUS(status); } status = NetAllocateMemory(OUT_PPVOID(&pResolvedNames), sizeof(*pResolvedNames) * dwCount); BAIL_ON_NT_STATUS(status); for (i = 0; i + dwResume < dwCount; i++) { DWORD iDomain = pNames[i + dwResume].sid_index; pResolvedNames[i].AccountName = pNames[i + dwResume].name; pResolvedNames[i].usType = pNames[i + dwResume].type; pResolvedNames[i].DomainName = pDomains->domains[iDomain].name; pSourceBuffer = pResolvedNames; err = NetAllocateLocalGroupMembersInfo(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 = ppSids[i + dwResume]; } else { pSourceBuffer = &(pResolvedNames[i]); } pBufferCursor = pBuffer + (i * dwInfoLevelSize); err = NetAllocateLocalGroupMembersInfo(pBufferCursor, &dwSpaceAvailable, dwLevel, pSourceBuffer, &dwSize, eValidation); BAIL_ON_WIN_ERROR(err); } if (dwResume + dwNumEntries < dwTotalNumEntries) { err = ERROR_MORE_DATA; } *ppBuffer = pBuffer; *pdwResume = dwResume + dwNumEntries; *pdwNumEntries = dwNumEntries; *pdwTotalEntries = dwTotalNumEntries; cleanup: NetDisconnectSamr(&pConn); if (Sids.pSids) { NetFreeMemory(Sids.pSids); } if (ppSids) { SamrFreeMemory(ppSids); } if (pNames) { SamrFreeMemory(pNames); } if (pDomains) { SamrFreeMemory(pDomains); } if (pCreds) { LwIoDeleteCreds(pCreds); } if (err == ERROR_SUCCESS && status != STATUS_SUCCESS) { err = LwNtStatusToWin32Error(status); } return err; error: if (pBuffer) { NetFreeMemory(pBuffer); } *ppBuffer = NULL; goto cleanup; }