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.

535 lines
16 KiB

  1. /*---------------------------------------------------------------------------
  2. File: ARUtil.cpp
  3. Comments: Helper functions and command-line parsing for Account Replicator
  4. (c) Copyright 1995-1998, Mission Critical Software, Inc., All Rights Reserved
  5. Proprietary and confidential to Mission Critical Software, Inc.
  6. REVISION LOG ENTRY
  7. Revision By: Christy Boles
  8. Revised on 6/23/98 4:26:54 PM
  9. ---------------------------------------------------------------------------
  10. */
  11. #include "StdAfx.h"
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #define INCL_NETUSER
  17. #define INCL_NETGROUP
  18. #define INCL_NETERRORS
  19. #include <lm.h>
  20. #include "Mcs.h"
  21. #include "Common.hpp"
  22. #include "TNode.hpp"
  23. #include "UString.hpp"
  24. #include "ErrDct.hpp"
  25. //#import "\bin\McsDctWorkerObjects.tlb"
  26. //#import "WorkObj.tlb" //#imported via ARUtil.hpp below
  27. #include "UserCopy.hpp"
  28. #include "ARUtil.hpp"
  29. #include "PWGen.hpp"
  30. #include "ResStr.h"
  31. extern TErrorDct err;
  32. bool bAllowReplicateOnSelf;
  33. extern PSID srcSid; // SID of source domain
  34. /***************************************************************************************************
  35. CompVal: used as a compare function for TANode trees
  36. It compares a UNICODE string, with the name field in the node
  37. Return Values:
  38. 0 tn->acct_name == actname
  39. 1 tn->acct_name < actname
  40. -1 tn->acct_name > actname
  41. /***************************************************************************************************/
  42. int
  43. CompVal(
  44. const TNode * tn, //in -tree node
  45. const void * actname //in -name to look for
  46. )
  47. {
  48. LPWSTR str1 = ((TANode *)tn)->GetName();
  49. LPWSTR str2 = (LPWSTR) actname;
  50. return UStrICmp(str1,str2);
  51. }
  52. /***************************************************************************************************/
  53. /* CompNode: used as a compare function for TANode Trees
  54. It compares the name fields of TANodes
  55. Return Values:
  56. 0 t1->acct_name == t2->acct_name
  57. 1 t1->acct_name > t2->acct_name
  58. -1 t1->acct_name < t2->acct_name
  59. Error Handling:
  60. if given bad inputs, CompN displays an error message and returns 0
  61. /***************************************************************************************************/
  62. int
  63. CompNode(
  64. const TNode * v1, //in -first node to compare
  65. const TNode * v2 //in -second node to compare
  66. )
  67. {
  68. TANode * t1 = (TANode *)v1;
  69. TANode * t2 = (TANode *)v2;
  70. return UStrICmp(t1->GetName(),t2->GetName());
  71. }
  72. int
  73. CompareSid(
  74. PSID const sid1, // in - first SID to compare
  75. PSID const sid2 // in - second SID to compare
  76. )
  77. {
  78. DWORD len1,
  79. len2;
  80. int retval = 0;
  81. len1 = GetLengthSid(sid1);
  82. len2 = GetLengthSid(sid2);
  83. if ( len1 < len2 )
  84. {
  85. retval = -1;
  86. }
  87. if ( len1 > len2 )
  88. {
  89. retval = 1;
  90. }
  91. if ( len1 == len2 )
  92. {
  93. retval = memcmp(sid1,sid2,len1);
  94. }
  95. return retval;
  96. }
  97. int
  98. CompSid(
  99. const TNode * v1, // in -first node to compare
  100. const TNode * v2 // in -second node to compare
  101. )
  102. {
  103. TANode * t1 = (TANode *)v1;
  104. TANode * t2 = (TANode *)v2;
  105. return CompareSid(t1->GetSid(),t2->GetSid());
  106. }
  107. int
  108. CompSidVal(
  109. const TNode * tn, // in -node to compare
  110. const void * pVal // in -value to compare
  111. )
  112. {
  113. TANode * node = (TANode *)tn;
  114. PSID pSid = (PSID)pVal;
  115. return CompareSid(node->GetSid(),pSid);
  116. }
  117. //#pragma page()
  118. //------------------------------------------------------------------------------
  119. // CopyServerName: Ensures that server name is in UNC form and checks its len
  120. //------------------------------------------------------------------------------
  121. DWORD
  122. CopyServerName(
  123. TCHAR * uncServ ,// out-UNC server name
  124. TCHAR const * server // in -\\server or domain name
  125. )
  126. {
  127. short l = (short) UStrLen(server);
  128. WCHAR * uncPDC;
  129. API_RET_TYPE rc;
  130. DWORD retcode = 0;
  131. if ( (server[0] == '\\' && l > UNCLEN )
  132. || (server[0] != '\\' && l > DNLEN) )
  133. {
  134. retcode = NERR_MaxLenExceeded;
  135. }
  136. UStrCpy(uncServ, server, CNLEN+3);
  137. if ( server[0] != '\\' )
  138. {
  139. rc = NetGetDCName(NULL, uncServ, (PBYTE*)&uncPDC);
  140. if ( ! rc )
  141. UStrCpy(uncServ, uncPDC);
  142. retcode = rc;
  143. NetApiBufferFree(uncPDC);
  144. }
  145. return retcode;
  146. }
  147. BOOL // ret-FALSE is addto: is not a group account
  148. AddToGroupResolveType(
  149. Options * options // i/o-options
  150. )
  151. {
  152. DWORD rc = 0;
  153. DWORD lenDomain,
  154. lenSid;
  155. WCHAR wszDomain[DNLEN+1];
  156. SID_NAME_USE sidNameUse; // Type of SID
  157. BYTE sid[LEN_Sid];
  158. WCHAR server[LEN_Computer];
  159. // Target domain AddTo group
  160. if ( *options->addToGroup )
  161. {
  162. safecopy(server,options->tgtComp);
  163. lenSid = sizeof sid;
  164. lenDomain = DIM(wszDomain);
  165. wszDomain[0] = L'\0';
  166. if ( !LookupAccountName(server,
  167. options->addToGroup,
  168. (PSID)sid,
  169. &lenSid,
  170. wszDomain,
  171. &lenDomain,
  172. &sidNameUse ) )
  173. {
  174. rc = GetLastError();
  175. if ( rc == ERROR_NONE_MAPPED )
  176. {
  177. // the add-to group does not exist. Try to create it
  178. LOCALGROUP_INFO_1 lgInfo;
  179. WCHAR comment[LEN_Comment];
  180. swprintf(comment,GET_STRING(IDS_AddToGroupOnTargetDescription_S),options->srcDomain);
  181. lgInfo.lgrpi1_name = options->addToGroup;
  182. lgInfo.lgrpi1_comment = comment;
  183. if (! options->nochange )
  184. {
  185. rc = NetLocalGroupAdd(server,1,(LPBYTE)&lgInfo,NULL);
  186. }
  187. else
  188. {
  189. rc = 0;
  190. }
  191. if ( rc && rc != ERROR_ALIAS_EXISTS )
  192. {
  193. err.SysMsgWrite(ErrW,rc,DCT_MSG_CREATE_ADDTO_GROUP_FAILED_SD,options->addToGroup,rc);
  194. }
  195. }
  196. else
  197. {
  198. err.SysMsgWrite(0, rc, DCT_MSG_RESOLVE_ADDTO_FAILED_SSD, options->addToGroup, server, rc );
  199. }
  200. }
  201. else
  202. {
  203. rc = 0;
  204. if ( sidNameUse == SidTypeAlias )
  205. options->flags |= F_AddToGroupLocal;
  206. else if ( sidNameUse != SidTypeGroup )
  207. {
  208. rc = 1;
  209. err.MsgWrite(0, DCT_MSG_ADDTO_NOT_GROUP_SD, options->addToGroup, sidNameUse );
  210. }
  211. }
  212. }
  213. // Source domain addto group
  214. if ( *options->addToGroupSource )
  215. {
  216. safecopy(server,options->srcComp);
  217. lenSid = sizeof sid;
  218. lenDomain = DIM(wszDomain);
  219. wszDomain[0] = L'\0';
  220. if ( !LookupAccountName(server,
  221. options->addToGroupSource,
  222. (PSID)sid,
  223. &lenSid,
  224. wszDomain,
  225. &lenDomain,
  226. &sidNameUse ) )
  227. {
  228. rc = GetLastError();
  229. if ( rc == ERROR_NONE_MAPPED )
  230. {
  231. // the add-to group does not exist. Try to create it
  232. LOCALGROUP_INFO_1 lgInfo;
  233. WCHAR comment[LEN_Comment];
  234. swprintf(comment,GET_STRING(IDS_AddToGroupOnSourceDescription_S),options->tgtDomain);
  235. lgInfo.lgrpi1_name = options->addToGroupSource;
  236. lgInfo.lgrpi1_comment = comment;
  237. if (! options->nochange )
  238. {
  239. rc = NetLocalGroupAdd(server,1,(LPBYTE)&lgInfo,NULL);
  240. }
  241. else
  242. {
  243. rc = 0;
  244. }
  245. if ( rc && rc != ERROR_ALIAS_EXISTS )
  246. {
  247. err.SysMsgWrite(ErrW,rc,DCT_MSG_CREATE_ADDTO_GROUP_FAILED_SD,options->addToGroupSource,rc);
  248. }
  249. }
  250. else
  251. {
  252. err.SysMsgWrite(0, rc, DCT_MSG_RESOLVE_ADDTO_FAILED_SSD, options->addToGroupSource, server, rc );
  253. }
  254. }
  255. else
  256. {
  257. rc = 0;
  258. if ( sidNameUse == SidTypeAlias )
  259. options->flags |= F_AddToSrcGroupLocal;
  260. else if ( sidNameUse != SidTypeGroup )
  261. {
  262. rc = 1;
  263. err.MsgWrite(0, DCT_MSG_ADDTO_NOT_GROUP_SD, options->addToGroup, sidNameUse );
  264. }
  265. }
  266. }
  267. return rc == 0;
  268. }
  269. BOOL // ret-TRUE if the password is successfully generated
  270. PasswordGenerate(
  271. Options const * options, // in -includes PW Generating options
  272. WCHAR * password, // out -buffer for generated password
  273. DWORD dwPWBufferLength, // in -DIM length of password buffer
  274. BOOL isAdminAccount // in -Whether to use the Admin rules
  275. )
  276. {
  277. DWORD rc = 0;
  278. DWORD dwMinUC; // minimum upper case chars
  279. DWORD dwMinLC; // minimum lower case chars
  280. DWORD dwMinDigit; // minimum numeric digits
  281. DWORD dwMinSpecial; // minimum special chars
  282. DWORD dwMaxConsecutiveAlpha; // maximum consecutive alpha chars
  283. DWORD dwMinLength; // minimum length
  284. WCHAR eaPassword[PWLEN+1]; // EA generated password
  285. DWORD dwEaBufferLength = DIM(eaPassword);// DIM length of newPassword
  286. // default values, if not enforcing PW strength through EA or MS DLL
  287. dwMinUC = 0;
  288. dwMinLC = 0;
  289. dwMinDigit = 1; // if no enforcement, require one digit (this is what the GUI does)
  290. dwMinSpecial = 0;
  291. dwMaxConsecutiveAlpha = 0;
  292. dwMinLength = options->minPwdLength;
  293. // Get password enforcement rules, if in effect
  294. dwMinUC = options->policyInfo.minUpper;
  295. dwMinLC = options->policyInfo.minLower;
  296. dwMinDigit = options->policyInfo.minDigits;
  297. dwMinSpecial = options->policyInfo.minSpecial;
  298. dwMaxConsecutiveAlpha = options->policyInfo.maxConsecutiveAlpha;
  299. rc = EaPasswordGenerate(dwMinUC,dwMinLC,dwMinDigit,dwMinSpecial,
  300. dwMaxConsecutiveAlpha,dwMinLength,eaPassword,dwEaBufferLength);
  301. if ( ! rc )
  302. {
  303. UStrCpy(password,eaPassword,dwPWBufferLength);
  304. }
  305. else
  306. {
  307. if ( dwPWBufferLength )
  308. password[0] = 0;
  309. }
  310. return rc;
  311. }
  312. PSID
  313. GetWellKnownSid(
  314. DWORD wellKnownAccount, // in - constant defined in this file, representing well-known account
  315. Options * opt, // in - migration options
  316. BOOL bTarget // in - flag, whether to use source or target domain information
  317. )
  318. {
  319. PSID pSid = NULL;
  320. PUCHAR numsubs = NULL;
  321. DWORD * rid = NULL;
  322. BOOL error = FALSE;
  323. DWORD rc;
  324. DWORD wellKnownRid = wellKnownAccount;
  325. BOOL bNeedToBuildDomainSid = FALSE;
  326. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  327. SID_IDENTIFIER_AUTHORITY creatorIA = SECURITY_CREATOR_SID_AUTHORITY;
  328. //
  329. // Sid is the same regardless of machine, since the well-known
  330. // BUILTIN domain is referenced.
  331. //
  332. switch ( wellKnownAccount )
  333. {
  334. case CREATOR_OWNER:
  335. if( ! AllocateAndInitializeSid(
  336. &creatorIA,
  337. 2,
  338. SECURITY_BUILTIN_DOMAIN_RID,
  339. SECURITY_CREATOR_OWNER_RID,
  340. 0, 0, 0, 0, 0, 0,
  341. &pSid
  342. ))
  343. {
  344. err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_INITIALIZE_SID_FAILED_D,GetLastError());
  345. }
  346. break;
  347. case ADMINISTRATORS:
  348. if( ! AllocateAndInitializeSid(
  349. &sia,
  350. 2,
  351. SECURITY_BUILTIN_DOMAIN_RID,
  352. DOMAIN_ALIAS_RID_ADMINS,
  353. 0, 0, 0, 0, 0, 0,
  354. &pSid
  355. ))
  356. {
  357. err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_INITIALIZE_SID_FAILED_D,GetLastError());
  358. }
  359. break;
  360. case ACCOUNT_OPERATORS:
  361. if( ! AllocateAndInitializeSid(
  362. &sia,
  363. 2,
  364. SECURITY_BUILTIN_DOMAIN_RID,
  365. DOMAIN_ALIAS_RID_ACCOUNT_OPS,
  366. 0, 0, 0, 0, 0, 0,
  367. &pSid
  368. ))
  369. {
  370. err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_INITIALIZE_SID_FAILED_D,GetLastError());
  371. }
  372. break;
  373. case BACKUP_OPERATORS:
  374. if( ! AllocateAndInitializeSid(
  375. &sia,
  376. 2,
  377. SECURITY_BUILTIN_DOMAIN_RID,
  378. DOMAIN_ALIAS_RID_BACKUP_OPS,
  379. 0, 0, 0, 0, 0, 0,
  380. &pSid
  381. ))
  382. {
  383. err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_INITIALIZE_SID_FAILED_D,GetLastError());
  384. }
  385. break;
  386. case DOMAIN_ADMINS:
  387. wellKnownRid = DOMAIN_GROUP_RID_ADMINS;
  388. bNeedToBuildDomainSid = TRUE;
  389. break;
  390. case DOMAIN_USERS:
  391. wellKnownRid = DOMAIN_GROUP_RID_USERS;
  392. bNeedToBuildDomainSid = TRUE;
  393. break;
  394. case DOMAIN_CONTROLLERS:
  395. wellKnownRid = DOMAIN_GROUP_RID_CONTROLLERS;
  396. bNeedToBuildDomainSid = TRUE;
  397. break;
  398. case DOMAIN_COMPUTERS:
  399. wellKnownRid = DOMAIN_GROUP_RID_COMPUTERS;
  400. bNeedToBuildDomainSid = TRUE;
  401. break;
  402. default:
  403. wellKnownRid = wellKnownAccount;
  404. bNeedToBuildDomainSid = TRUE;
  405. break;
  406. }
  407. if ( bNeedToBuildDomainSid )
  408. {
  409. // For the default case we can return a SID by using the wellKnownAccount parameter as a RID
  410. // this one is based on the sid for the domain
  411. // Get the domain SID
  412. USER_MODALS_INFO_2 * uinf = NULL;
  413. MCSASSERT(opt);
  414. srcSid = bTarget ? opt->tgtSid : opt->srcSid;
  415. if ( ! srcSid )
  416. {
  417. rc = NetUserModalsGet(bTarget ? opt->tgtComp :opt->srcComp,2,(LPBYTE*)&uinf);
  418. if ( rc )
  419. {
  420. err.SysMsgWrite(ErrE,rc,DCT_MSG_NO_DOMAIN_SID_SD,bTarget ? opt->tgtDomain :opt->srcDomain,rc );
  421. error = TRUE;
  422. srcSid = NULL;
  423. }
  424. else
  425. {
  426. srcSid = uinf->usrmod2_domain_id;
  427. // make a copy of the SID to keep in the Options structure for next time
  428. PSID temp = LocalAlloc(LPTR,GetLengthSid(srcSid));
  429. memcpy(temp,srcSid,GetLengthSid(srcSid));
  430. if ( bTarget )
  431. opt->tgtSid = temp;
  432. else
  433. opt->srcSid = temp;
  434. NetApiBufferFree(uinf);
  435. srcSid = temp;
  436. }
  437. }
  438. if ( srcSid )
  439. {
  440. numsubs = GetSidSubAuthorityCount(srcSid);
  441. if (! AllocateAndInitializeSid(
  442. &sia,
  443. (*numsubs)+1,
  444. 0,0,0,0,0,0,0,0,
  445. &pSid) )
  446. {
  447. err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_INITIALIZE_SID_FAILED_D,GetLastError());
  448. }
  449. if ( ! CopySid(GetLengthSid(srcSid), pSid, srcSid) )
  450. {
  451. err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_COPY_SID_FAILED_D,GetLastError());
  452. }
  453. // reset number of subauthorities in pSid, since we just overwrote it with information from srcSid
  454. numsubs = GetSidSubAuthorityCount(pSid);
  455. (*numsubs)++;
  456. rid = GetSidSubAuthority(pSid,(*numsubs)-1);
  457. *rid = wellKnownRid;
  458. }
  459. }
  460. if ( error )
  461. {
  462. LocalFree(pSid);
  463. pSid = NULL;
  464. }
  465. return pSid;
  466. }