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 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; }