Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

828 lines
19 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995
  5. //
  6. // File: cenumGroupCollection.cxx
  7. //
  8. // Contents: Windows NT 3.5 GroupCollection Enumeration Code
  9. //
  10. //
  11. //
  12. //
  13. //
  14. //
  15. // History:
  16. //----------------------------------------------------------------------------
  17. #include "winnt.hxx"
  18. #pragma hdrstop
  19. COMPUTER_GROUP_MEMBER CompMember;
  20. //
  21. // This assumes that addr is an LPBYTE type.
  22. //
  23. #define WORD_ALIGN_DOWN(addr) \
  24. addr = ((LPBYTE)((DWORD_PTR)addr & ~1))
  25. DWORD ComputerGrpMemberStrings[]=
  26. {
  27. FIELD_OFFSET(COMPUTER_GROUP_MEMBER, Parent),
  28. FIELD_OFFSET(COMPUTER_GROUP_MEMBER, Computer),
  29. FIELD_OFFSET(COMPUTER_GROUP_MEMBER, Domain),
  30. FIELD_OFFSET(COMPUTER_GROUP_MEMBER, Name),
  31. 0xFFFFFFFF
  32. };
  33. DECLARE_INFOLEVEL(GrpUt)
  34. DECLARE_DEBUG(GrpUt)
  35. #define GrpUtDebugOut(x) GrpUtInlineDebugOut x
  36. BOOL
  37. WinNTLocalGroupOpen(
  38. LPWSTR szDomainName,
  39. LPWSTR szComputerName,
  40. LPWSTR szGroupName,
  41. PHANDLE phGroup
  42. )
  43. {
  44. WCHAR szTempBuffer[MAX_PATH];
  45. PINI_COMP_GROUP pIniCompGrp;
  46. HRESULT hr;
  47. if (!phGroup) {
  48. return(FALSE);
  49. }
  50. pIniCompGrp = (PINI_COMP_GROUP)AllocADsMem(
  51. sizeof(INI_COMP_GROUP)
  52. );
  53. if (!pIniCompGrp) {
  54. return(FALSE);
  55. }
  56. hr = MakeUncName(
  57. szComputerName,
  58. szTempBuffer
  59. );
  60. BAIL_ON_FAILURE(hr);
  61. if (!(pIniCompGrp->szUncCompName = AllocADsStr(szTempBuffer))){
  62. goto error;
  63. }
  64. // to guard against the case of domainName == NULL for no
  65. // workstation services
  66. if (szDomainName != NULL) {
  67. if (!(pIniCompGrp->szDomainName = AllocADsStr(szDomainName))) {
  68. goto error;
  69. }
  70. }
  71. if (!(pIniCompGrp->szComputerName = AllocADsStr(szComputerName))){
  72. goto error;
  73. }
  74. if (!(pIniCompGrp->szGroupName = AllocADsStr(szGroupName))){
  75. goto error;
  76. }
  77. *phGroup = (HANDLE)pIniCompGrp;
  78. return(TRUE);
  79. error:
  80. if (pIniCompGrp) {
  81. FreeIniCompGroup(pIniCompGrp);
  82. }
  83. *phGroup = NULL;
  84. return(FALSE);
  85. }
  86. BOOL
  87. WinNTLocalGroupEnum(
  88. HANDLE hGroup,
  89. DWORD dwRequested,
  90. LPBYTE * ppBuffer,
  91. PDWORD pdwReturned
  92. )
  93. {
  94. LPCOMPUTER_GROUP_MEMBER * ppGroupMembers = NULL;
  95. DWORD i = 0;
  96. BOOL dwRet = FALSE;
  97. DWORD dwReturned = 0;
  98. DWORD dwSize = 0;
  99. LPCOMPUTER_GROUP_MEMBER pBuffer = NULL;
  100. LPBYTE pEnd = NULL;
  101. DWORD dwError;
  102. BOOL fretVal = FALSE;
  103. ppGroupMembers = (LPCOMPUTER_GROUP_MEMBER *)AllocADsMem(
  104. sizeof(LPCOMPUTER_GROUP_MEMBER)* dwRequested
  105. );
  106. if (!ppGroupMembers) {
  107. return(FALSE);
  108. }
  109. for (i = 0; i < dwRequested; i++) {
  110. dwRet = WinNTLocalGroupGetObject(
  111. hGroup,
  112. &ppGroupMembers[dwReturned]
  113. );
  114. if (!dwRet) {
  115. dwError = GetLastError();
  116. if (dwError == ERROR_INVALID_SID) {
  117. continue;
  118. }
  119. //
  120. // it was not because of a bad sid
  121. // so break out, nothing more can be done
  122. //
  123. break;
  124. }
  125. dwReturned++;
  126. }
  127. dwRet = ComputeLocalGroupDataSize(
  128. ppGroupMembers,
  129. dwReturned,
  130. &dwSize
  131. );
  132. pBuffer = (LPCOMPUTER_GROUP_MEMBER)AllocADsMem(
  133. dwSize
  134. );
  135. if (pBuffer) {
  136. fretVal = TRUE;
  137. pEnd = (LPBYTE)((LPBYTE)(pBuffer) + dwSize);
  138. for (i = 0; i < dwReturned; i++) {
  139. pEnd = CopyIniCompGroupToCompGroup(
  140. ppGroupMembers[i],
  141. (LPBYTE)(pBuffer + i),
  142. pEnd
  143. );
  144. }
  145. }
  146. for (i = 0; i < dwReturned; i++ ) {
  147. FreeIntCompGroup(*(ppGroupMembers + i));
  148. }
  149. FreeADsMem(ppGroupMembers);
  150. //
  151. // Will correctl set to NULL if alloc failed.
  152. //
  153. *ppBuffer = (LPBYTE)pBuffer;
  154. *pdwReturned = fretVal ? dwReturned : 0;
  155. if (!fretVal) {
  156. return(FALSE);
  157. }
  158. if (dwReturned == dwRequested){
  159. return(TRUE);
  160. }else {
  161. return(FALSE);
  162. }
  163. }
  164. BOOL
  165. WinNTLocalGroupGetObject(
  166. HANDLE hGroup,
  167. LPCOMPUTER_GROUP_MEMBER * ppGroupMember
  168. )
  169. {
  170. BOOL dwRet = FALSE;
  171. PINI_COMP_GROUP pIniCompGrp = (PINI_COMP_GROUP)hGroup;
  172. NET_API_STATUS nasStatus = 0;
  173. if ((!pIniCompGrp->_pBuffer) ||
  174. (pIniCompGrp->_dwCurrentObject == pIniCompGrp->_dwObjectReturned)) {
  175. if (pIniCompGrp->_bNoMore) {
  176. //
  177. // No more objects to return
  178. //
  179. return(FALSE);
  180. }
  181. if (pIniCompGrp->_pBuffer) {
  182. NetApiBufferFree(pIniCompGrp->_pBuffer);
  183. pIniCompGrp->_pBuffer = NULL;
  184. }
  185. pIniCompGrp->_dwObjectReturned = 0;
  186. pIniCompGrp->_dwCurrentObject = 0;
  187. pIniCompGrp->_dwTotalObjects = 0;
  188. nasStatus = NetLocalGroupGetMembers(
  189. pIniCompGrp->szUncCompName,
  190. pIniCompGrp->szGroupName,
  191. 2,
  192. &pIniCompGrp->_pBuffer,
  193. MAX_PREFERRED_LENGTH,
  194. &pIniCompGrp->_dwObjectReturned,
  195. &pIniCompGrp->_dwTotalObjects,
  196. &pIniCompGrp->_dwResumeHandle
  197. );
  198. if ((nasStatus != ERROR_SUCCESS) && (nasStatus != ERROR_MORE_DATA)){
  199. SetLastError(nasStatus);
  200. return(FALSE);
  201. }
  202. if (nasStatus != ERROR_MORE_DATA) {
  203. pIniCompGrp->_bNoMore = TRUE;
  204. }
  205. //
  206. // If there are no more objects to return,
  207. // return FALSE
  208. //
  209. if (!pIniCompGrp->_dwObjectReturned) {
  210. return(FALSE);
  211. }
  212. }
  213. while ( dwRet != TRUE &&
  214. (pIniCompGrp->_dwCurrentObject < pIniCompGrp->_dwTotalObjects))
  215. {
  216. dwRet = BuildLocalGroupMember(
  217. hGroup,
  218. (LPBYTE)((LPLOCALGROUP_MEMBERS_INFO_2)pIniCompGrp->_pBuffer
  219. + pIniCompGrp->_dwCurrentObject),
  220. ppGroupMember
  221. );
  222. if (dwRet == FALSE) {
  223. if (GetLastError() == ERROR_INVALID_SID) {
  224. pIniCompGrp->_dwCurrentObject++;
  225. continue;
  226. //
  227. // proceed to the top of the while loop
  228. //
  229. }
  230. else
  231. goto error;
  232. }
  233. }
  234. //
  235. // the while loop
  236. //
  237. if (dwRet == FALSE)
  238. goto error;
  239. pIniCompGrp->_dwCurrentObject++;
  240. return(TRUE);
  241. error:
  242. return(FALSE);
  243. }
  244. BOOL
  245. WinNTLocalGroupClose(
  246. HANDLE hGroup
  247. )
  248. {
  249. PINI_COMP_GROUP pIniCompGrp = (PINI_COMP_GROUP)hGroup;
  250. if (pIniCompGrp) {
  251. FreeIniCompGroup(pIniCompGrp);
  252. }
  253. return(TRUE);
  254. }
  255. void
  256. FreeIniCompGroup(
  257. PINI_COMP_GROUP pIniCompGrp
  258. )
  259. {
  260. if (pIniCompGrp->szDomainName) {
  261. FreeADsStr(pIniCompGrp->szDomainName);
  262. }
  263. if (pIniCompGrp->szComputerName) {
  264. FreeADsStr(pIniCompGrp->szComputerName);
  265. }
  266. if (pIniCompGrp->szGroupName) {
  267. FreeADsStr(pIniCompGrp->szGroupName);
  268. }
  269. if (pIniCompGrp->szUncCompName) {
  270. FreeADsStr(pIniCompGrp->szUncCompName);
  271. }
  272. if (pIniCompGrp->_pBuffer) {
  273. NetApiBufferFree(pIniCompGrp->_pBuffer);
  274. }
  275. if (pIniCompGrp) {
  276. FreeADsMem(pIniCompGrp);
  277. }
  278. return;
  279. }
  280. void
  281. FreeIntCompGroup(
  282. LPCOMPUTER_GROUP_MEMBER pCompGroupMember
  283. )
  284. {
  285. if (pCompGroupMember->Parent) {
  286. FreeADsMem(pCompGroupMember->Parent);
  287. }
  288. if (pCompGroupMember->Computer) {
  289. FreeADsStr(pCompGroupMember->Computer);
  290. }
  291. if (pCompGroupMember->Domain) {
  292. FreeADsStr(pCompGroupMember->Domain);
  293. }
  294. if (pCompGroupMember->Name) {
  295. FreeADsStr(pCompGroupMember->Name);
  296. }
  297. if (pCompGroupMember->Sid) {
  298. FreeADsMem(pCompGroupMember->Sid);
  299. }
  300. FreeADsMem(pCompGroupMember);
  301. }
  302. BOOL
  303. ComputeLocalGroupDataSize(
  304. LPCOMPUTER_GROUP_MEMBER * ppGroupMembers,
  305. DWORD dwReturned,
  306. PDWORD pdwSize
  307. )
  308. {
  309. DWORD i = 0;
  310. DWORD cb = 0;
  311. LPCOMPUTER_GROUP_MEMBER pMember = NULL;
  312. for (i = 0; i < dwReturned; i++) {
  313. pMember = *(ppGroupMembers + i);
  314. cb += sizeof(COMPUTER_GROUP_MEMBER);
  315. if (pMember->Parent) {
  316. cb += wcslen(pMember->Parent)*sizeof(WCHAR) + sizeof(WCHAR);
  317. }
  318. if (pMember->Computer) {
  319. cb += wcslen(pMember->Computer)*sizeof(WCHAR) + sizeof(WCHAR);
  320. }
  321. if (pMember->Domain) {
  322. cb += wcslen(pMember->Domain)*sizeof(WCHAR) + sizeof(WCHAR);
  323. }
  324. if (pMember->Name) {
  325. cb += wcslen(pMember->Name)*sizeof(WCHAR) + sizeof(WCHAR);
  326. }
  327. if (pMember->Sid) {
  328. cb += GetLengthSid(pMember->Sid);
  329. }
  330. }
  331. *pdwSize = cb;
  332. return(TRUE);
  333. }
  334. LPBYTE
  335. CopyIniCompGroupToCompGroup(
  336. LPCOMPUTER_GROUP_MEMBER pIntCompGrp,
  337. LPBYTE pExtCompGrp,
  338. LPBYTE pEnd
  339. )
  340. {
  341. LPWSTR SourceStrings[sizeof(COMPUTER_GROUP_MEMBER)/sizeof(LPWSTR)];
  342. LPWSTR *pSourceStrings=SourceStrings;
  343. LPCOMPUTER_GROUP_MEMBER pCompGrpMember = (LPCOMPUTER_GROUP_MEMBER)pExtCompGrp;
  344. DWORD dwSidLength = 0;
  345. memset(SourceStrings, 0, sizeof(COMPUTER_GROUP_MEMBER));
  346. *pSourceStrings++ = pIntCompGrp->Parent;
  347. *pSourceStrings++ = pIntCompGrp->Computer;
  348. *pSourceStrings++ = pIntCompGrp->Domain;
  349. *pSourceStrings++ = pIntCompGrp->Name;
  350. pEnd = PackStrings(
  351. SourceStrings,
  352. pExtCompGrp,
  353. ComputerGrpMemberStrings,
  354. pEnd
  355. );
  356. pCompGrpMember->Type = pIntCompGrp->Type;
  357. pCompGrpMember->ParentType = pIntCompGrp->ParentType;
  358. if (pIntCompGrp->Sid) {
  359. dwSidLength = GetLengthSid(pIntCompGrp->Sid);
  360. pEnd -= dwSidLength;
  361. memcpy(pEnd,
  362. pIntCompGrp->Sid,
  363. dwSidLength
  364. );
  365. pCompGrpMember->Sid = pEnd;
  366. }
  367. return pEnd;
  368. }
  369. BOOL
  370. BuildLocalGroupMember(
  371. HANDLE hGroup,
  372. LPBYTE lpBuffer,
  373. LPCOMPUTER_GROUP_MEMBER * ppGroupMember
  374. )
  375. {
  376. LPINI_COMP_GROUP pGroup = (LPINI_COMP_GROUP)hGroup;
  377. LPCOMPUTER_GROUP_MEMBER pGroupMember = NULL;
  378. LPLOCALGROUP_MEMBERS_INFO_2 pGrpMem = (LPLOCALGROUP_MEMBERS_INFO_2)lpBuffer;
  379. WCHAR szADsParent[MAX_PATH];
  380. LPWSTR pMemberName = NULL;
  381. LPWSTR pszSIDName = NULL;
  382. DWORD cblen = 0, dwLen = 0, dwLenDomAndName = 0;
  383. DWORD dwSidType = 0;
  384. DWORD dwSidLength = 0;
  385. BOOL fRet = FALSE;
  386. BOOL fError = FALSE;
  387. pGroupMember = (LPCOMPUTER_GROUP_MEMBER)AllocADsMem(
  388. sizeof(COMPUTER_GROUP_MEMBER)
  389. );
  390. if (!pGroupMember) {
  391. goto error;
  392. }
  393. dwSidType = pGrpMem->lgrmi2_sidusage;
  394. pMemberName = wcschr(pGrpMem->lgrmi2_domainandname, L'\\');
  395. cblen = wcslen(pGroup->szComputerName);
  396. //
  397. // Check to see if the lengthe of the domain name component in
  398. // lgrmi2_domainandname and the comptuername are the same if not
  399. // it cannot be a computer member object. We do this to catch the case
  400. // where foo.foodom is computer name. foodom\user will incorrectly
  401. // be identified as a local user rather than domain user
  402. //
  403. if (pMemberName) {
  404. *pMemberName = L'\0';
  405. dwLenDomAndName = wcslen(pGrpMem->lgrmi2_domainandname);
  406. *pMemberName = L'\\';
  407. }
  408. else {
  409. dwLenDomAndName = cblen;
  410. }
  411. if ((dwLenDomAndName == cblen) && !_wcsnicmp(pGroup->szComputerName, pGrpMem->lgrmi2_domainandname, cblen)) {
  412. //
  413. // This is the local user case
  414. //
  415. if (pMemberName) {
  416. pMemberName++;
  417. }
  418. else {
  419. pMemberName = pGrpMem->lgrmi2_domainandname ;
  420. }
  421. pGroupMember->Name = AllocADsStr(pMemberName);
  422. pGroupMember->Computer = AllocADsStr(pGroup->szComputerName);
  423. pGroupMember->Domain = AllocADsStr(pGroup->szDomainName);
  424. if (pGroupMember->Domain != NULL) {
  425. wsprintf(
  426. szADsParent,
  427. L"%s://%s/%s",
  428. szProviderName,
  429. pGroup->szDomainName,
  430. pGroup->szComputerName
  431. );
  432. } else {
  433. // Again we may have a null domain name for the case
  434. // where there are no workstations services
  435. wsprintf(
  436. szADsParent,
  437. L"%s://%s",
  438. szProviderName,
  439. pGroup->szComputerName
  440. );
  441. }
  442. pGroupMember->Parent = AllocADsStr(szADsParent);
  443. pGroupMember->ParentType = WINNT_COMPUTER_ID;
  444. //
  445. // Need to look at SID to see if this is a local group
  446. // in which case the sid will be alias.
  447. //
  448. if (dwSidType == SidTypeAlias) {
  449. pGroupMember->Type = WINNT_LOCALGROUP_ID;
  450. }
  451. else if (dwSidType == SidTypeUser) {
  452. pGroupMember->Type = WINNT_USER_ID;
  453. } else {
  454. //
  455. // Unknown ??
  456. //
  457. SetLastError(ERROR_INVALID_SID);
  458. BAIL_ON_FAILURE(E_FAIL);
  459. }
  460. }else {
  461. //
  462. // This is the domain user, domain group case
  463. //
  464. pMemberName = wcschr(pGrpMem->lgrmi2_domainandname, L'\\');
  465. if (pMemberName) {
  466. *pMemberName = L'\0';
  467. pMemberName++;
  468. pGroupMember->Domain = AllocADsStr(pGrpMem->lgrmi2_domainandname);
  469. pGroupMember->Computer = NULL;
  470. wsprintf(
  471. szADsParent,
  472. L"%s://%s",
  473. szProviderName,
  474. pGrpMem->lgrmi2_domainandname
  475. );
  476. }
  477. else {
  478. //
  479. // if name is well name like 'EveryOne' without the domain prefix,
  480. // we end up with using the local computer name
  481. //
  482. pMemberName = pGrpMem->lgrmi2_domainandname ;
  483. pGroupMember->Domain = NULL;
  484. pGroupMember->Computer = AllocADsStr(L"") ;
  485. wsprintf(
  486. szADsParent,
  487. L"WinNT:"
  488. );
  489. }
  490. pGroupMember->Name = AllocADsStr(pMemberName);
  491. pGroupMember->Parent = AllocADsStr(szADsParent);
  492. switch (dwSidType) {
  493. case SidTypeUser:
  494. pGroupMember->Type = WINNT_USER_ID;
  495. break;
  496. case SidTypeGroup:
  497. case SidTypeWellKnownGroup :
  498. case SidTypeAlias :
  499. pGroupMember->Type = WINNT_GROUP_ID;
  500. break;
  501. case SidTypeUnknown:
  502. case SidTypeDeletedAccount:
  503. #if !defined(WIN95)
  504. //
  505. // In this case we want to use the stringized SID.
  506. // We use functions in sddl.h.
  507. //
  508. fRet = ConvertSidToStringSidWrapper(
  509. pGrpMem->lgrmi2_sid,
  510. &pszSIDName
  511. );
  512. if (!fRet || !pszSIDName) {
  513. //
  514. // Not much we can do here
  515. //
  516. SetLastError(ERROR_INVALID_SID);
  517. fError = TRUE;
  518. } else {
  519. //
  520. // We are always going to return just the SID.
  521. //
  522. if (pGroupMember->Name) {
  523. FreeADsStr(pGroupMember->Name);
  524. pGroupMember->Name = NULL;
  525. }
  526. if (pGroupMember->Parent) {
  527. FreeADsStr(pGroupMember->Parent);
  528. pGroupMember->Parent = NULL;
  529. }
  530. if (pGroupMember->Domain) {
  531. FreeADsStr(pGroupMember->Domain);
  532. pGroupMember->Domain = NULL;
  533. }
  534. //
  535. // Got be either user so default to user.
  536. //
  537. pGroupMember->Type = WINNT_USER_ID;
  538. pGroupMember->Name = AllocADsStr(pszSIDName);
  539. pGroupMember->Parent = AllocADsStr(L"WinNT:");
  540. if (!pGroupMember->Name || ! pGroupMember->Parent) {
  541. //
  542. // Not enough mem - rather than ignore like we do
  543. // in the rest of the places in this fn, will
  544. // set the last error and hope we recover.
  545. //
  546. SetLastError(ERROR_INVALID_SID);
  547. fError = TRUE;
  548. }
  549. }
  550. #else
  551. SetLastError(ERROR_INVALID_SID);
  552. fError = TRUE;
  553. #endif
  554. if (pszSIDName) {
  555. LocalFree(pszSIDName);
  556. }
  557. if (fError)
  558. goto error;
  559. break;
  560. default:
  561. SetLastError(ERROR_INVALID_SID);
  562. goto error;
  563. break;
  564. }
  565. //
  566. // Need to special case this as we cannot have a domain
  567. // name that is NULL.
  568. //
  569. if (dwSidType == SidTypeDeletedAccount
  570. || dwSidType == SidTypeUnknown) {
  571. pGroupMember->ParentType = WINNT_COMPUTER_ID;
  572. }
  573. else {
  574. pGroupMember->ParentType = WINNT_DOMAIN_ID;
  575. }
  576. }
  577. //
  578. // Copy the SID
  579. //
  580. if (pGrpMem->lgrmi2_sid) {
  581. //
  582. // On NT4 for some reason GetLengthSID does not set lasterror to 0
  583. //
  584. SetLastError(NO_ERROR);
  585. dwSidLength = GetLengthSid(pGrpMem->lgrmi2_sid);
  586. //
  587. // This is an extra check to make sure that we have the
  588. // correct length.
  589. //
  590. if (GetLastError() != NO_ERROR) {
  591. SetLastError(ERROR_INVALID_SID);
  592. BAIL_ON_FAILURE(E_FAIL);
  593. }
  594. pGroupMember->Sid = AllocADsMem(dwSidLength);
  595. if (!pGroupMember->Sid) {
  596. SetLastError(ERROR_OUTOFMEMORY);
  597. BAIL_ON_FAILURE(E_OUTOFMEMORY);
  598. }
  599. memcpy(pGroupMember->Sid, pGrpMem->lgrmi2_sid, dwSidLength);
  600. }
  601. *ppGroupMember = pGroupMember;
  602. return(TRUE);
  603. error:
  604. if (pGroupMember) {
  605. FreeIntCompGroup(pGroupMember);
  606. }
  607. *ppGroupMember = NULL;
  608. return(FALSE);
  609. }
  610. LPBYTE
  611. PackStrings(
  612. LPWSTR *pSource,
  613. LPBYTE pDest,
  614. DWORD *DestOffsets,
  615. LPBYTE pEnd
  616. )
  617. {
  618. DWORD cbStr;
  619. WORD_ALIGN_DOWN(pEnd);
  620. while (*DestOffsets != -1) {
  621. if (*pSource) {
  622. cbStr = wcslen(*pSource)*sizeof(WCHAR) + sizeof(WCHAR);
  623. pEnd -= cbStr;
  624. CopyMemory( pEnd, *pSource, cbStr);
  625. *(LPWSTR *)(pDest+*DestOffsets) = (LPWSTR)pEnd;
  626. } else {
  627. *(LPWSTR *)(pDest+*DestOffsets)=0;
  628. }
  629. pSource++;
  630. DestOffsets++;
  631. }
  632. return pEnd;
  633. }