积极答复者
请教,使用 NetUserEnum 获取账户名称以及 SID 时出现的问题

问题
-
由于项目需要枚举账户名称以及其对应的 SID,所以我找到了 Platform SDK 里面的这个方法。根据 MSDN 的说明:
ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.WIN32COM.v10.en/netmgmt/netmgmt/netuserenum.htm
(我的环境是 Windows XP, Visual studio 2005)MSDN 上的例子使用 Level 0 的,里面没有 SID,所以我就改用 Level 23,代码如下:(绝大部分抄袭 MSDN,仅修改两处,使用 “//已修改” 注释做抬头)
int _tmain(int argc, _TCHAR* argv[]) { //已修改, 适应 Level 23 LPUSER_INFO_23 pBuf = NULL; LPUSER_INFO_23 pTmpBuf; DWORD dwLevel = 23; DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; DWORD dwEntriesRead = 0; DWORD dwTotalEntries = 0; DWORD dwResumeHandle = 0; DWORD i; DWORD dwTotalCount = 0; NET_API_STATUS nStatus; LPTSTR pszServerName = NULL; if (argc > 2) { fwprintf(stderr, L"Usage: %s [\\\\ServerName]\n", argv[0]); exit(1); } // The server is not the default local computer. // if (argc == 2) pszServerName = argv[1]; wprintf(L"\nUser account on %s: \n", pszServerName); // // Call the NetUserEnum function, specifying level 0; // enumerate global user account types only. // do // begin do { nStatus = NetUserEnum(pszServerName, dwLevel, FILTER_NORMAL_ACCOUNT, // global users (LPBYTE*)&pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries, &dwResumeHandle); // // If the call succeeds, // if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) { if ((pTmpBuf = pBuf) != NULL) { // // Loop through the entries. // for (i = 0; (i < dwEntriesRead); i++) { // assert(pTmpBuf != NULL); if (pTmpBuf == NULL) { fprintf(stderr, "An access violation has occurred\n"); break; } // // Print the name of the user account. // //已修改,变量名不同 wprintf(L"\t-- %s\n", pTmpBuf->usri23_name); pTmpBuf++; dwTotalCount++; } } } // // Otherwise, print the system error. // else fprintf(stderr, "A system error has occurred: %d\n", nStatus); // // Free the allocated buffer. // if (pBuf != NULL) { NetApiBufferFree(pBuf); pBuf = NULL; } } // Continue to call NetUserEnum while // there are more entries. // while (nStatus == ERROR_MORE_DATA); // end do // // Check again for allocated memory. // if (pBuf != NULL) NetApiBufferFree(pBuf); // // Print the final count of users enumerated. // fprintf(stderr, "\nTotal of %d entries enumerated\n", dwTotalCount); getchar(); return 0; }
结果一开始 NetUserEnum 就没有预期结果。此函数的返回值 NET_API_STATUS nStatus 是一个对不上号的数值 “124”
继而我又企图使用 Level 3,因为我看到 USER_INFO_3 里面的说明:
It is recommended that you use the USER_INFO_4 structure instead
所以就是用 Level 3 与 USER_INFO_4 来作为 NetUserEnum 的参数。
结果是可以运行,但是当我企图用 ConvertSidToStringSid 来把 USER_INFO_4.usri4_user_sid 转换为 LPCTSTR 格式的时候, ConvertSidToStringSid 的返回结果是 FALSE, GetLastError 的结果是 ERROR_INVALID_SID。
我在是无计可施了,恳请哪位有在这方面有经验的高人,指点一下我是用错了哪些东西。或者提供其他的能够枚举计算机上账户以及其对应 SID 的方法。谢谢
答案
-
Specifies a DWORD value that contains the relative ID (RID) of the user 这个是关于useri3_user_sid的解释,其实用level3,和level20获得的都是这个,所以把它当成SID的话都会报ERROR_INVALID_SID的错误。
可以用LookupAccountName 来用usriN_full_name获得SID
谢谢你的提示。
LookupAccountName 的 lpAccountName 要求 domain_name\user_name 格式的名称,我个人感觉不好办。
所以后来我采用了以下的解决方法
1. NetUserEnum 采用 Level 0 以及 USER_INFO_0 做参数
2. NetUserGetInfo 采用 Level 4 以及 USER_INFO_4 做参数, 此时的 USER_INFO_4.usri4_user_sid 才是真正的 PSID
3. ConvertSidToStringSid,搞掂。
感觉有一种“曲线救国”的味道...不知道有没有更好的办法
全部回复
-
Specifies a DWORD value that contains the relative ID (RID) of the user 这个是关于useri3_user_sid的解释,其实用level3,和level20获得的都是这个,所以把它当成SID的话都会报ERROR_INVALID_SID的错误。
可以用LookupAccountName 来用usriN_full_name获得SID
谢谢你的提示。
LookupAccountName 的 lpAccountName 要求 domain_name\user_name 格式的名称,我个人感觉不好办。
所以后来我采用了以下的解决方法
1. NetUserEnum 采用 Level 0 以及 USER_INFO_0 做参数
2. NetUserGetInfo 采用 Level 4 以及 USER_INFO_4 做参数, 此时的 USER_INFO_4.usri4_user_sid 才是真正的 PSID
3. ConvertSidToStringSid,搞掂。
感觉有一种“曲线救国”的味道...不知道有没有更好的办法