Leaked source code of windows server 2003
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.

2927 lines
88 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. user.c
  5. Abstract:
  6. user related option functions
  7. Author:
  8. Xiaofeng Zang (xiaoz) 17-Sep-2001 Created
  9. Revision History:
  10. <alias> <date> <comments>
  11. --*/
  12. #include "StdAfx.h"
  13. #include "clmt.h"
  14. #include <dsrole.h>
  15. #include <Ntdsapi.h>
  16. #include <wtsapi32.h>
  17. #define MAX_FIELD_COUNT 7
  18. #define OP_USER 0
  19. #define OP_GRP 1
  20. #define OP_PROFILE 2
  21. #define OP_DOMAIN_GRP 3
  22. #define TYPE_USER_PROFILE_PATH 1
  23. #define TYPE_USER_SCRIPT_PATH 2
  24. #define TYPE_USER_HOME_DIR 3
  25. #define TYPE_TS_INIT_PROGRAM 4
  26. #define TYPE_TS_WORKING_DIR 5
  27. #define TYPE_TS_PROFILE_PATH 6
  28. #define TYPE_TS_HOME_DIR 7
  29. //
  30. // Function prototypes used in user.c
  31. //
  32. HRESULT RenameDocuments_and_Settings(HINF, BOOL);
  33. HRESULT ChangeUserInfo(LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR, BOOL, BOOL, BOOL);
  34. HRESULT ChangeGroupInfo(LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR, BOOL, BOOL, BOOL);
  35. HRESULT ChangeUserName(LPTSTR, LPTSTR, BOOL, BOOL);
  36. HRESULT ChangeUserDesc(LPTSTR, LPTSTR, LPTSTR, BOOL);
  37. HRESULT ChangeUserFullName(LPTSTR, LPTSTR, LPTSTR, BOOL);
  38. HRESULT SetUserNetworkProfilePath(LPCTSTR, LPCTSTR);
  39. HRESULT SetUserLogOnScriptPath(LPCTSTR, LPCTSTR);
  40. HRESULT SetUserHomeDir(LPCTSTR, LPCTSTR);
  41. HRESULT SetTSUserPath(LPCTSTR, LPCTSTR, WTS_CONFIG_CLASS);
  42. HRESULT ChangeGroupName(LPTSTR, LPTSTR, BOOL, BOOL);
  43. HRESULT ChangeGroupDesc(LPTSTR, LPTSTR, LPTSTR, BOOL, BOOL);
  44. HRESULT ChangeRDN(LPTSTR, LPTSTR, LPTSTR, BOOL);
  45. HRESULT AddProfileChangeItem(DWORD, LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR);
  46. HRESULT PolicyGetPrivilege(LPTSTR, PLSA_HANDLE, PLSA_UNICODE_STRING*, PULONG);
  47. HRESULT PolicySetPrivilege(LPTSTR, LSA_HANDLE, PLSA_UNICODE_STRING, ULONG);
  48. HRESULT PreFixUserProfilePath(LPCTSTR, LPCTSTR, LPTSTR, DWORD);
  49. BOOL IsPathLocal(LPCTSTR);
  50. HRESULT CheckNewBuiltInUserName(LPCTSTR, LPTSTR, DWORD);
  51. HRESULT AddProfilePathItem(LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR, DWORD);
  52. HRESULT AddTSProfilePathItem(LPCTSTR, LPCTSTR, LPCTSTR, WTS_CONFIG_CLASS);
  53. //-----------------------------------------------------------------------------
  54. //
  55. // Function: UsrGrpAndDoc_and_SettingsRename
  56. //
  57. // Descrip: This routine renames user/group name and profile directory
  58. // specified in section [UserGrp.ObjectRename] of the INF file
  59. //
  60. // Returns: TRUE if succeeds, FALSE otherwise
  61. //
  62. // Notes: none
  63. //
  64. // History: 09/17/2001 xiaoz created
  65. //
  66. // Notes: none
  67. //
  68. //-----------------------------------------------------------------------------
  69. HRESULT UsrGrpAndDoc_and_SettingsRename(
  70. HINF hInf, // Handle to INF file
  71. BOOL bTest
  72. )
  73. {
  74. INFCONTEXT InfContext;
  75. LONG nLineCount, nLineIndex;
  76. LONG nFieldCount, nFieldIndex;
  77. TCHAR szType[MAX_PATH];
  78. TCHAR szOldName[MAX_PATH];
  79. TCHAR szNewName[MAX_PATH];
  80. TCHAR szOldFullName[MAX_PATH];
  81. TCHAR szNewFullName[MAX_PATH];
  82. LPTSTR *lplpOldName;
  83. LPTSTR *lplpNewName;
  84. LPTSTR *lplpOldDesc;
  85. LPTSTR *lplpNewDesc;
  86. LPTSTR *lplpOldFullName;
  87. LPTSTR *lplpNewFullName;
  88. LPTSTR lpString[MAX_FIELD_COUNT + 1];
  89. DWORD dwType;
  90. BOOL bRet;
  91. BOOL bCurrentUserRenamed;
  92. HRESULT hr = S_OK;
  93. BOOL bErrorOccured = FALSE;
  94. LPTSTR lpszOldComment,lpszNewComment;
  95. size_t cchMaxFieldLen[MAX_FIELD_COUNT + 1];
  96. DWORD dwErr;
  97. PBYTE pdsInfo;
  98. WCHAR szDomainName[MAX_COMPUTERNAME_LENGTH + 1];
  99. BOOL fIsDC;
  100. lpszOldComment = lpszNewComment = NULL;
  101. for (nFieldIndex = 0 ; nFieldIndex <= MAX_FIELD_COUNT ; nFieldIndex++)
  102. {
  103. cchMaxFieldLen[nFieldIndex] = MAX_PATH;
  104. }
  105. // 1 for type, 2 one old name , 3 for new name
  106. // 4 and 5 are for old and new comments
  107. cchMaxFieldLen[4] = cchMaxFieldLen[5] = 0;
  108. if (hInf == INVALID_HANDLE_VALUE)
  109. {
  110. hr = E_INVALIDARG;
  111. goto Exit;
  112. }
  113. //
  114. // Check if the machine is Domain Controller or not
  115. //
  116. dwErr = DsRoleGetPrimaryDomainInformation(NULL,
  117. DsRolePrimaryDomainInfoBasic,
  118. &pdsInfo);
  119. if (dwErr == ERROR_SUCCESS)
  120. {
  121. DSROLE_MACHINE_ROLE dsMachineRole;
  122. dsMachineRole = ((DSROLE_PRIMARY_DOMAIN_INFO_BASIC *) pdsInfo)->MachineRole;
  123. if (dsMachineRole == DsRole_RoleBackupDomainController ||
  124. dsMachineRole == DsRole_RolePrimaryDomainController)
  125. {
  126. fIsDC = TRUE;
  127. hr = StringCchCopy(szDomainName,
  128. ARRAYSIZE(szDomainName),
  129. ((DSROLE_PRIMARY_DOMAIN_INFO_BASIC *) pdsInfo)->DomainNameFlat);
  130. if (FAILED(hr))
  131. {
  132. goto Exit;
  133. }
  134. }
  135. else
  136. {
  137. fIsDC = FALSE;
  138. }
  139. DsRoleFreeMemory(pdsInfo);
  140. }
  141. else
  142. {
  143. hr = HRESULT_FROM_WIN32(dwErr);
  144. goto Exit;
  145. }
  146. nLineCount = SetupGetLineCount(hInf, USERGRPSECTION);
  147. if (nLineCount < 0)
  148. {
  149. DPF(PROwar, TEXT("section name [%s] is empty !"), USERGRPSECTION);
  150. hr = S_FALSE;
  151. goto Exit;
  152. }
  153. // here we scan the whole section and find out how much space
  154. // needed for comments
  155. for(nLineIndex = 0 ; nLineIndex < nLineCount ; nLineIndex++)
  156. {
  157. if (SetupGetLineByIndex(hInf, USERGRPSECTION, nLineIndex, &InfContext))
  158. {
  159. nFieldCount = SetupGetFieldCount(&InfContext);
  160. // We need at least 3 fields to be valid input
  161. if (nFieldCount < 3)
  162. {
  163. DPF(PROerr, TEXT("section name [%s] line %d error:missing field !"), USERGRPSECTION,nLineIndex);
  164. hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
  165. goto Exit;
  166. }
  167. //if there is no comments field, just skip
  168. if (nFieldCount < 4)
  169. {
  170. continue;
  171. }
  172. for (nFieldIndex = 4 ; nFieldIndex <= 5 ; nFieldIndex++)
  173. {
  174. DWORD cchReqSize;
  175. if (!SetupGetStringField(&InfContext,
  176. nFieldIndex,
  177. NULL,
  178. 0,
  179. &cchReqSize))
  180. {
  181. DPF(PROerr,
  182. TEXT("Failed to get field [%d] from line [%d] in section [%s]"),
  183. nFieldIndex,
  184. nLineIndex,
  185. USERGRPSECTION);
  186. hr = HRESULT_FROM_WIN32(GetLastError());
  187. goto Exit;
  188. }
  189. if (cchMaxFieldLen[nFieldIndex] < cchReqSize)
  190. {
  191. cchMaxFieldLen[nFieldIndex] = cchReqSize;
  192. }
  193. }
  194. }
  195. else
  196. {
  197. DPF(PROerr,
  198. TEXT("can not get line [%d] of section [%s]!"),
  199. nLineIndex,
  200. USERGRPSECTION);
  201. hr = HRESULT_FROM_WIN32(GetLastError());
  202. goto Exit;
  203. }
  204. }
  205. if (cchMaxFieldLen[4])
  206. {
  207. cchMaxFieldLen[4]++;
  208. lpszOldComment = malloc(cchMaxFieldLen[4]*sizeof(TCHAR));
  209. }
  210. if (cchMaxFieldLen[5])
  211. {
  212. cchMaxFieldLen[5]++;
  213. lpszNewComment = malloc(cchMaxFieldLen[5]*sizeof(TCHAR));
  214. }
  215. if ( (!lpszNewComment && lpszOldComment) || (lpszNewComment && !lpszOldComment) )
  216. {
  217. hr = E_OUTOFMEMORY;
  218. goto Exit;
  219. }
  220. //here we do real stuff
  221. for(nLineIndex = 0 ; nLineIndex < nLineCount ; nLineIndex++)
  222. {
  223. // we think user name and full name should not exceed MAX_PATH
  224. // if we meet this, we will just ignored(skipp this line)
  225. // the following variable is used to flag whether we meed
  226. // such field.
  227. BOOL bMeetUnexpectedLongField = FALSE;
  228. lpString[1] = szType;
  229. lpString[2] = szOldName;
  230. lpString[3] = szNewName;
  231. lpString[4] = lpszOldComment;
  232. lpString[5] = lpszNewComment;
  233. lpString[6] = szOldFullName;
  234. lpString[7] = szNewFullName;
  235. lplpOldName = &lpString[2];
  236. lplpNewName = &lpString[3];
  237. lplpOldDesc = &lpString[4];
  238. lplpNewDesc = &lpString[5];
  239. lplpOldFullName = &lpString[6];
  240. lplpNewFullName = &lpString[7];
  241. //
  242. // Fetch data from INF file
  243. //
  244. if (SetupGetLineByIndex(hInf, USERGRPSECTION, nLineIndex, &InfContext))
  245. {
  246. nFieldCount = SetupGetFieldCount(&InfContext);
  247. // We need at least 3 fields to be valid input
  248. if (nFieldCount < 3)
  249. {
  250. DPF(PROerr, TEXT("section name [%s] line %d error:missing field !"), USERGRPSECTION,nLineIndex);
  251. hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
  252. goto Exit;
  253. }
  254. // Read all the fields in INF line
  255. // Field index for values starts from 1, field 0 is key name
  256. for (nFieldIndex = 1 ; nFieldIndex <= nFieldCount ; nFieldIndex++)
  257. {
  258. DWORD cchReqSize;
  259. if (!SetupGetStringField(&InfContext,
  260. nFieldIndex,
  261. lpString[nFieldIndex],
  262. cchMaxFieldLen[nFieldIndex],
  263. &cchReqSize))
  264. {
  265. dwErr = GetLastError();
  266. if (dwErr == ERROR_MORE_DATA)
  267. {
  268. bMeetUnexpectedLongField = TRUE;
  269. continue;
  270. }
  271. else
  272. {
  273. DPF(PROerr,
  274. TEXT("Failed to get field [%d] from line [%d] in section [%s]"),
  275. nFieldIndex,
  276. nLineIndex,
  277. USERGRPSECTION);
  278. hr = HRESULT_FROM_WIN32(GetLastError());
  279. goto Exit;
  280. }
  281. }
  282. }
  283. if (bMeetUnexpectedLongField)
  284. {
  285. DPF(PROwar, TEXT("user name or full name too long in line [%d] in section [%s]"),
  286. nLineIndex,
  287. USERGRPSECTION);
  288. continue;
  289. }
  290. // If INF line does not supply all the field,
  291. // set the pointers to the rest of fields to NULL
  292. for (nFieldIndex = nFieldCount + 1 ; nFieldIndex <= MAX_FIELD_COUNT ; nFieldIndex++)
  293. {
  294. lpString[nFieldIndex] = NULL;
  295. }
  296. }
  297. else
  298. {
  299. DPF(PROerr,
  300. TEXT("can not get line [%d] of section [%s]!"),
  301. nLineIndex,
  302. USERGRPSECTION);
  303. hr = HRESULT_FROM_WIN32(GetLastError());
  304. goto Exit;
  305. }
  306. //
  307. // Process the fetched data
  308. //
  309. dwType = _tstoi(szType);
  310. switch (dwType & 0xFFFF)
  311. {
  312. case OP_USER:
  313. hr = ChangeUserInfo(*lplpOldName,
  314. *lplpNewName,
  315. *lplpOldDesc,
  316. *lplpNewDesc,
  317. *lplpOldFullName,
  318. *lplpNewFullName,
  319. szDomainName,
  320. bTest,
  321. fIsDC,
  322. dwType & 0xFFFF0000 ? TRUE:FALSE);
  323. if (FAILED(hr))
  324. {
  325. DPF(PROerr,
  326. TEXT("UsrGrpAndDoc_and_SettingsRename: Failed to change user info for account <%s>"),
  327. *lplpOldName);
  328. bErrorOccured = TRUE;
  329. }
  330. break;
  331. case OP_GRP:
  332. hr = ChangeGroupInfo(*lplpOldName,
  333. *lplpNewName,
  334. *lplpOldDesc,
  335. *lplpNewDesc,
  336. szDomainName,
  337. bTest,
  338. fIsDC,
  339. FALSE);
  340. if (FAILED(hr))
  341. {
  342. DPF(PROerr,
  343. TEXT("UsrGrpAndDoc_and_SettingsRename: Failed to change group info for account <%s>"),
  344. *lplpOldName);
  345. bErrorOccured = TRUE;
  346. }
  347. break;
  348. case OP_PROFILE:
  349. hr = RenameDocuments_and_Settings(hInf,bTest);
  350. if (FAILED(hr))
  351. {
  352. DPF(PROerr,TEXT("changing profiled directory failed"));
  353. bErrorOccured = TRUE;
  354. }
  355. break;
  356. case OP_DOMAIN_GRP:
  357. if (fIsDC)
  358. {
  359. hr = ChangeGroupInfo(*lplpOldName,
  360. *lplpNewName,
  361. *lplpOldDesc,
  362. *lplpNewDesc,
  363. szDomainName,
  364. bTest,
  365. fIsDC,
  366. TRUE);
  367. if (FAILED(hr))
  368. {
  369. DPF(PROerr,
  370. TEXT("UsrGrpAndDoc_and_SettingsRename: Failed to change group info for account <%s>"),
  371. *lplpOldName);
  372. bErrorOccured = TRUE;
  373. }
  374. }
  375. break;
  376. }
  377. if ((hr == S_OK) && bTest)
  378. {
  379. hr = AddProfileChangeItem(dwType & 0xFFFF,
  380. *lplpOldName,
  381. *lplpNewName,
  382. *lplpOldDesc,
  383. *lplpNewDesc,
  384. *lplpOldFullName,
  385. *lplpNewFullName);
  386. }
  387. }
  388. if (bErrorOccured)
  389. {
  390. hr = E_FAIL;
  391. }
  392. Exit:
  393. FreePointer(lpszOldComment);
  394. FreePointer(lpszNewComment);
  395. return hr;
  396. }
  397. /*++
  398. Routine Description:
  399. This routine renames a user name and updated all related setting(eg user's profile
  400. directory,current logon default name , comments...
  401. Arguments:
  402. szUsrName - original user name
  403. szNewUsrName - the new user name
  404. szComments - comments of new user name
  405. szFullName - Full name of the new user name
  406. Return Value:
  407. TRUE if succeeds
  408. --*/
  409. HRESULT ChangeUserInfo(
  410. LPTSTR lpOldName, // Old user name
  411. LPTSTR lpNewName, // New user name
  412. LPTSTR lpOldDesc, // Old user description
  413. LPTSTR lpNewDesc, // New user description
  414. LPTSTR lpOldFullName, // (optional) Old user full name
  415. LPTSTR lpNewFullName, // (optional) New user full name
  416. LPTSTR lpDomainName, // (optional) Machine domain name
  417. BOOL bTest, // Analyze mode or not
  418. BOOL fIsDC, // Is the machine a Domain Controller
  419. BOOL bCreateHardLink
  420. )
  421. {
  422. HRESULT hr = S_OK;
  423. DWORD dwErr;
  424. NET_API_STATUS status;
  425. USER_INFO_0 usrinfo0;
  426. BOOL bNameChanged = FALSE;
  427. if (lpOldName == NULL || lpNewName == NULL)
  428. {
  429. hr = E_INVALIDARG;
  430. goto Exit;
  431. }
  432. //
  433. // Reset the Comment for the User
  434. //
  435. if (lpOldDesc != NULL && lpNewDesc != NULL)
  436. {
  437. hr = ChangeUserDesc(lpOldName, lpOldDesc, lpNewDesc, bTest);
  438. if (FAILED(hr))
  439. {
  440. DPF(PROerr,
  441. TEXT("ChangerUserInfo: Failed to change description for user <%s>"),
  442. lpOldName);
  443. goto Exit;
  444. }
  445. }
  446. //
  447. // Reset the Full Name of the User
  448. //
  449. if (lpOldFullName != NULL && lpNewFullName != NULL)
  450. {
  451. hr = ChangeUserFullName(lpOldName, lpOldFullName, lpNewFullName, bTest);
  452. if (FAILED(hr))
  453. {
  454. DPF(PROerr,
  455. TEXT("ChangeUserInfo: Failed to change Full Name for user <%s>"),
  456. lpOldName);
  457. goto Exit;
  458. }
  459. }
  460. //
  461. // Reset the user CN name for the user (RDN)
  462. //
  463. if (fIsDC)
  464. {
  465. hr = ChangeRDN(lpOldName, lpNewName, lpDomainName, bTest);
  466. if (FAILED(hr))
  467. {
  468. DPF(PROerr,
  469. TEXT("ChangeUserInfo: Failed to change RDN for user <%s>"),
  470. lpOldName);
  471. goto Exit;
  472. }
  473. }
  474. //
  475. // Reset the user name (SAM account name)
  476. //
  477. if (MyStrCmpI(lpOldName, lpNewName) != LSTR_EQUAL)
  478. {
  479. hr = ChangeUserName(lpOldName, lpNewName, bTest,bCreateHardLink);
  480. if (FAILED(hr))
  481. {
  482. DPF(PROerr,
  483. TEXT("ChangeUserInfo: Failed to change SAM account name for user <%s>"),
  484. lpOldName);
  485. goto Exit;
  486. }
  487. }
  488. Exit:
  489. return hr;
  490. }
  491. //-----------------------------------------------------------------------------
  492. //
  493. // Function: ChangeGroupInfo
  494. //
  495. // Descrip: Chage the local group information
  496. // - Account name (SAM account name)
  497. // - Account RDN
  498. // - Description
  499. //
  500. // Returns: S_OK - Group information is okay to change
  501. // S_FALSE - Group name cannot be changed (not an error)
  502. // otherwise - error occured
  503. //
  504. // Notes: none
  505. //
  506. // History: 09/17/2001 xiaoz created
  507. // 04/25/2002 Rerkboos Modified to work with domain group
  508. //
  509. // Notes: none
  510. //
  511. //-----------------------------------------------------------------------------
  512. HRESULT ChangeGroupInfo(
  513. LPTSTR lpOldName, // Old user name
  514. LPTSTR lpNewName, // New user name
  515. LPTSTR lpOldDesc, // Old user description
  516. LPTSTR lpNewDesc, // New user description
  517. LPTSTR lpDomainName, // (optional) Machine domain name
  518. BOOL bTest, // Analyze mode or not
  519. BOOL fIsDC, // Is the machine a Domain Controller
  520. BOOL bUseDomainAPI // Use domain API or not
  521. )
  522. {
  523. HRESULT hr = S_OK;
  524. if (lpOldName == NULL || lpNewName == NULL)
  525. {
  526. return E_INVALIDARG;
  527. }
  528. //
  529. // Change group description
  530. //
  531. if (lpOldDesc && lpNewDesc)
  532. {
  533. hr = ChangeGroupDesc(lpOldName,
  534. lpOldDesc,
  535. lpNewDesc,
  536. bTest,
  537. bUseDomainAPI);
  538. if (FAILED(hr))
  539. {
  540. DPF(PROerr,
  541. TEXT("ChangeGroupInfo: Failed to change description for group <%s>"),
  542. lpOldName);
  543. goto Exit;
  544. }
  545. }
  546. //
  547. // Change group RDN
  548. //
  549. if (fIsDC)
  550. {
  551. hr = ChangeRDN(lpOldName, lpNewName, lpDomainName, bTest);
  552. if (FAILED(hr))
  553. {
  554. DPF(PROerr,
  555. TEXT("ChangeGroupInfo: Failed to change RDN for group <%s>"),
  556. lpOldName);
  557. goto Exit;
  558. }
  559. }
  560. //
  561. // Change group name (SAM)
  562. //
  563. if (MyStrCmpI(lpOldName, lpNewName) != LSTR_EQUAL)
  564. {
  565. hr = ChangeGroupName(lpOldName, lpNewName, bTest, bUseDomainAPI);
  566. if (FAILED(hr))
  567. {
  568. DPF(PROerr,
  569. TEXT("ChangeGroupInfo: Failed to change SAM account name for group <%s>"),
  570. lpOldName);
  571. goto Exit;
  572. }
  573. }
  574. Exit:
  575. return hr;
  576. }
  577. //-----------------------------------------------------------------------------
  578. //
  579. // Function: ChangeUserName
  580. //
  581. // Descrip: Chage the User name (SAM account name)
  582. //
  583. // Returns: S_OK - User name is okay to change
  584. // S_FALSE - User name cannot be changed (not an error)
  585. // otherwise - error occured
  586. //
  587. // Notes: none
  588. //
  589. // History: 09/17/2001 xiaoz created
  590. // 04/25/2002 Rerkboos Modified to work with domain group
  591. //
  592. // Notes: none
  593. //
  594. //-----------------------------------------------------------------------------
  595. HRESULT ChangeUserName(
  596. LPTSTR lpOldName, // Old user name
  597. LPTSTR lpNewName, // New user name
  598. BOOL bTest, // Analyze mode or not
  599. BOOL bCreateHardLink
  600. )
  601. {
  602. LPUSER_INFO_0 lpUsrInfo0;
  603. USER_INFO_1052 usrinfo1052;
  604. USER_INFO_0 usrinfo0New;
  605. NET_API_STATUS nStatus;
  606. DWORD dwErr, dwLen;
  607. HRESULT hr;
  608. TCHAR szProfilePath[MAX_PATH],szNewProfilePath[MAX_PATH];
  609. TCHAR szExpProfilePath[MAX_PATH],szExpNewProfilePath[MAX_PATH];
  610. TCHAR szLogonName[MAX_PATH];
  611. LPTSTR lpCurrProfileDir;
  612. LPTSTR lpCurrUsername;
  613. BOOL bCheckRegistry = TRUE;
  614. if (lpOldName == NULL || lpNewName == NULL)
  615. {
  616. hr = E_INVALIDARG;
  617. goto Exit;
  618. }
  619. if (MyStrCmpI(lpOldName, lpNewName) == 0)
  620. {
  621. hr = S_OK;
  622. goto Exit;
  623. }
  624. hr = GetSetUserProfilePath(lpOldName,
  625. szProfilePath,
  626. MAX_PATH,
  627. PROFILE_PATH_READ,
  628. REG_EXPAND_SZ);
  629. if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND)
  630. {
  631. bCheckRegistry = FALSE;
  632. }
  633. else if (FAILED(hr))
  634. {
  635. goto Exit;
  636. }
  637. if (bCheckRegistry)
  638. {
  639. // Compute a new unique profile directory name
  640. if ( !ComputeLocalProfileName(lpOldName,
  641. lpNewName,
  642. szNewProfilePath,
  643. ARRAYSIZE(szNewProfilePath),
  644. REG_EXPAND_SZ) )
  645. {
  646. hr = E_FAIL;
  647. goto Exit;
  648. }
  649. }
  650. if (bTest)
  651. {
  652. lpCurrProfileDir = szProfilePath;
  653. lpCurrUsername = lpOldName;
  654. }
  655. else
  656. {
  657. lpCurrProfileDir = szNewProfilePath;
  658. lpCurrUsername = lpNewName;
  659. }
  660. // Search for the old user name in the system
  661. nStatus = NetUserGetInfo(NULL,
  662. lpOldName,
  663. 0,
  664. (LPBYTE *) &lpUsrInfo0);
  665. switch (nStatus)
  666. {
  667. case NERR_Success:
  668. // user name found, reset the name to new one
  669. usrinfo0New.usri0_name = lpCurrUsername;
  670. nStatus = NetUserSetInfo(NULL,
  671. lpOldName,
  672. 0,
  673. (LPBYTE) &usrinfo0New,
  674. &dwErr);
  675. if (nStatus == NERR_Success)
  676. {
  677. hr = S_OK;
  678. }
  679. else
  680. {
  681. hr = HRESULT_FROM_WIN32(nStatus);
  682. }
  683. NetApiBufferFree(lpUsrInfo0);
  684. break;
  685. case NERR_UserNotFound:
  686. // user name is not found on the system
  687. hr = S_FALSE;
  688. break;
  689. default:
  690. // error occured
  691. hr = HRESULT_FROM_WIN32(nStatus);
  692. break;
  693. }
  694. if (hr != S_OK)
  695. {
  696. goto Exit;
  697. }
  698. //here it means we succeeded change (or test changing) the user name
  699. //change user profile path through netapi if necessary
  700. if (bCheckRegistry)
  701. {
  702. //Expand the original and new profile path
  703. if (!ExpandEnvironmentStrings(szProfilePath, szExpProfilePath, MAX_PATH))
  704. {
  705. goto Exit;
  706. }
  707. if (!ExpandEnvironmentStrings(szNewProfilePath, szExpNewProfilePath, MAX_PATH))
  708. {
  709. goto Exit;
  710. }
  711. //If it's not test, we do real renaming)
  712. if (!bTest)
  713. {
  714. }
  715. else
  716. {
  717. LPTSTR lpOld,lpNew;
  718. hr = MyMoveDirectory(szExpProfilePath,szExpNewProfilePath,TRUE,bTest,FALSE,0);
  719. if(FAILED(hr))
  720. {
  721. DPF (APPerr, L"Move Dir from %s to %s failed ! Error Code %d (%#x)",
  722. szExpProfilePath,szExpNewProfilePath,hr, hr);
  723. goto Exit;
  724. }
  725. if (bCreateHardLink)
  726. {
  727. TCHAR szCommonPerfix[MAX_PATH+1];
  728. TCHAR szLinkName[2 * MAX_PATH], szLinkValue[2 * MAX_PATH];
  729. if (PathCommonPrefix(szExpProfilePath,szExpNewProfilePath,szCommonPerfix))
  730. {
  731. LPTSTR lpszOlduserName = szExpProfilePath,lpszNewuserName = szExpNewProfilePath;
  732. lpszOlduserName += lstrlen(szCommonPerfix);
  733. lpszNewuserName += lstrlen(szCommonPerfix);
  734. szCommonPerfix[1] = TEXT('\0');
  735. if (lpszOlduserName && lpszNewuserName)
  736. {
  737. HRESULT myhr, myhr1;
  738. myhr = StringCchCopy(szLinkName,ARRAYSIZE(szLinkName),szCommonPerfix);
  739. myhr = StringCchCat(szLinkName,ARRAYSIZE(szLinkName),TEXT(":\\Documents and Settings\\"));
  740. myhr = StringCchCopy(szLinkValue,ARRAYSIZE(szLinkValue),szCommonPerfix);
  741. myhr = StringCchCat(szLinkValue,ARRAYSIZE(szLinkValue),TEXT(":\\Documents and Settings\\"));
  742. myhr = StringCchCat(szLinkName,ARRAYSIZE(szLinkName),lpszOlduserName);
  743. myhr1 = StringCchCat(szLinkValue,ARRAYSIZE(szLinkValue),lpszNewuserName);
  744. if ( (myhr == S_OK) && (myhr1 == S_OK) )
  745. {
  746. hr = AddHardLinkEntry(szLinkName,szLinkValue,TEXT("0"),NULL,NULL,NULL);
  747. }
  748. }
  749. }
  750. }
  751. AddUserNameChangeLog(lpOldName, lpNewName);
  752. lpOld = StrRChrI(szExpProfilePath,NULL,TEXT('\\'));
  753. lpNew = StrRChrI(szExpNewProfilePath,NULL,TEXT('\\'));
  754. if (lpOld && lpNew)
  755. {
  756. if (!AddItemToStrRepaceTable((LPTSTR) lpOldName,
  757. (LPTSTR) lpOld+1,
  758. (LPTSTR) lpNew+1,
  759. szExpProfilePath,
  760. CSIDL_USERNAME_IN_USERPROFILE,
  761. &g_StrReplaceTable))
  762. {
  763. hr = E_OUTOFMEMORY;
  764. goto Exit;
  765. }
  766. }
  767. }
  768. //Get current login user name
  769. dwLen = ARRAYSIZE(szLogonName);
  770. if (!GetUserName(szLogonName, &dwLen))
  771. {
  772. hr = HRESULT_FROM_WIN32(GetLastError());
  773. goto Exit;
  774. }
  775. // rename the profile path, if the current user profile path needs to be changed
  776. // we have to do a delayed renaming
  777. if (!MyStrCmpI(szLogonName,lpOldName))
  778. {
  779. #define DEFAULT_USERNAME_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
  780. hr = RegResetValue(HKEY_LOCAL_MACHINE,
  781. DEFAULT_USERNAME_KEY,
  782. TEXT("DefaultUserName"),
  783. REG_SZ,
  784. lpOldName,
  785. lpCurrUsername,
  786. 0,
  787. NULL);
  788. if(FAILED(hr))
  789. {
  790. goto Exit;
  791. }
  792. hr = RegResetValue(HKEY_LOCAL_MACHINE,
  793. DEFAULT_USERNAME_KEY,
  794. TEXT("AltDefaultUserName"),
  795. REG_SZ,
  796. lpOldName,
  797. lpCurrUsername,
  798. 0,
  799. NULL);
  800. if(FAILED(hr))
  801. {
  802. goto Exit;
  803. }
  804. }
  805. }
  806. hr = S_OK;
  807. Exit:
  808. return hr;
  809. }
  810. //-----------------------------------------------------------------------------
  811. //
  812. // Function: ChangeGroupName
  813. //
  814. // Descrip: Chage the Group name (SAM account name)
  815. //
  816. // Returns: S_OK - group name is okay to change
  817. // S_FALSE - group name cannot be changed (not an error)
  818. // otherwise - error occured
  819. //
  820. // Notes: none
  821. //
  822. // History: 09/17/2001 xiaoz created
  823. // 04/25/2002 Rerkboos Modified to work with domain group
  824. //
  825. // Notes: none
  826. //
  827. //-----------------------------------------------------------------------------
  828. HRESULT ChangeGroupName(
  829. LPTSTR lpOldName, // Old user name
  830. LPTSTR lpNewName, // New user name
  831. BOOL bTest, // Analyze mode or not
  832. BOOL bDomainAPI // Local group API or not
  833. )
  834. {
  835. HRESULT hr = S_OK;
  836. NET_API_STATUS nStatus;
  837. DWORD dwErr;
  838. PLOCALGROUP_INFO_1 plgrpi1LocalGroup = NULL;
  839. PGROUP_INFO_1 pgrpi1DomainGroup = NULL;
  840. LOCALGROUP_INFO_0 lgrpi0NewName;
  841. GROUP_INFO_0 grpi0NewName;
  842. PPVOID ppvGroupInfo;
  843. PPVOID ppvNewGroupInfo;
  844. LPTSTR lpCurrentName;
  845. PVOID pvNewGroupNameInfo;
  846. LSA_HANDLE PolicyHandle;
  847. PLSA_UNICODE_STRING pPrivileges;
  848. ULONG CountOfRights;
  849. BOOL bGotGP = FALSE;
  850. DWORD (*pfnGroupGetInfo)(LPCWSTR, LPCWSTR, DWORD, LPBYTE *);
  851. DWORD (*pfnGroupSetInfo)(LPCWSTR, LPCWSTR, DWORD, LPBYTE, LPDWORD);
  852. if (lpOldName == NULL || lpNewName == NULL)
  853. {
  854. return E_INVALIDARG;
  855. }
  856. //
  857. // Choose which set of APIs/variables we will use
  858. //
  859. if (bDomainAPI)
  860. {
  861. // Domain group
  862. ppvGroupInfo = &pgrpi1DomainGroup;
  863. ppvNewGroupInfo = &pgrpi1DomainGroup;
  864. pvNewGroupNameInfo = &grpi0NewName;
  865. pfnGroupGetInfo = &NetGroupGetInfo;
  866. pfnGroupSetInfo = &NetGroupSetInfo;
  867. }
  868. else
  869. {
  870. // Local group
  871. ppvGroupInfo = &plgrpi1LocalGroup;
  872. ppvNewGroupInfo = &plgrpi1LocalGroup;
  873. pvNewGroupNameInfo = &lgrpi0NewName;
  874. pfnGroupGetInfo = &NetLocalGroupGetInfo;
  875. pfnGroupSetInfo = &NetLocalGroupSetInfo;
  876. }
  877. //
  878. // Check whether the new group name has already been used in the system or not
  879. //
  880. nStatus = (*pfnGroupGetInfo)(NULL,
  881. lpNewName,
  882. 1,
  883. (LPBYTE *) ppvNewGroupInfo);
  884. if (nStatus == NERR_Success)
  885. {
  886. // New group name already exists in the system,
  887. // don't change the group name
  888. NetApiBufferFree(*ppvNewGroupInfo);
  889. return S_FALSE;
  890. }
  891. //
  892. // Check wheter the old user name exists in the system or not
  893. //
  894. nStatus = (*pfnGroupGetInfo)(NULL,
  895. lpOldName,
  896. 1,
  897. (LPBYTE *) ppvGroupInfo);
  898. switch (nStatus)
  899. {
  900. case NERR_Success:
  901. if (bDomainAPI)
  902. {
  903. lpCurrentName = pgrpi1DomainGroup->grpi1_name ;
  904. }
  905. else
  906. {
  907. lpCurrentName = plgrpi1LocalGroup->lgrpi1_name;
  908. }
  909. if (bTest)
  910. {
  911. // in analyzing mode, use the old group name
  912. lgrpi0NewName.lgrpi0_name = lpCurrentName;
  913. grpi0NewName.grpi0_name = lpCurrentName;
  914. }
  915. else
  916. {
  917. // in modifying mode, use the new group name from INF
  918. lgrpi0NewName.lgrpi0_name = lpNewName;
  919. grpi0NewName.grpi0_name = lpNewName;
  920. }
  921. if (!bTest)
  922. {
  923. HRESULT hrGP = PolicyGetPrivilege(lpOldName,
  924. &PolicyHandle,
  925. &pPrivileges,
  926. &CountOfRights);
  927. if (hrGP == S_OK)
  928. {
  929. bGotGP = TRUE;
  930. }
  931. }
  932. //
  933. // Set the new group name (SAM account name)
  934. //
  935. nStatus = (*pfnGroupSetInfo)(NULL,
  936. lpOldName,
  937. 0,
  938. (LPBYTE) pvNewGroupNameInfo,
  939. &dwErr);
  940. if (nStatus == NERR_Success)
  941. {
  942. hr = S_OK;
  943. }
  944. else
  945. {
  946. hr = HRESULT_FROM_WIN32(nStatus);
  947. }
  948. if (bGotGP)
  949. {
  950. if (SUCCEEDED(hr))
  951. {
  952. // Reset the policy
  953. hr = PolicySetPrivilege(lpNewName,
  954. PolicyHandle,
  955. pPrivileges,
  956. CountOfRights);
  957. }
  958. LsaFreeMemory(pPrivileges);
  959. LsaClose(PolicyHandle);
  960. }
  961. NetApiBufferFree(*ppvGroupInfo);
  962. break;
  963. case ERROR_NO_SUCH_ALIAS:
  964. case NERR_GroupNotFound:
  965. hr = S_FALSE;
  966. break;
  967. default:
  968. hr = HRESULT_FROM_WIN32(nStatus);
  969. }
  970. return hr;
  971. }
  972. //-----------------------------------------------------------------------------
  973. //
  974. // Function: ChangeUserDesc
  975. //
  976. // Descrip: Chage the User description
  977. //
  978. // Returns: S_OK - User description is okay to change
  979. // S_FALSE - User description cannot be changed (not an error)
  980. // otherwise - error occured
  981. //
  982. // Notes: none
  983. //
  984. // History: 09/17/2001 xiaoz created
  985. // 04/25/2002 Rerkboos Modified to work with domain group
  986. //
  987. // Notes: none
  988. //
  989. //-----------------------------------------------------------------------------
  990. HRESULT ChangeUserDesc(
  991. LPTSTR lpUserName, // User name
  992. LPTSTR lpOldDesc, // Old user description
  993. LPTSTR lpNewDesc, // New user description
  994. BOOL bTest // Anylyze mode or not
  995. )
  996. {
  997. LPUSER_INFO_10 lpUsrInfo10;
  998. USER_INFO_1007 usri1007New;
  999. NET_API_STATUS nStatus;
  1000. DWORD dwErr;
  1001. HRESULT hr;
  1002. if (lpUserName == NULL || lpOldDesc == NULL || lpNewDesc == NULL)
  1003. {
  1004. return E_INVALIDARG;
  1005. }
  1006. if (MyStrCmpI(lpOldDesc, lpNewDesc) == LSTR_EQUAL)
  1007. {
  1008. return S_OK;
  1009. }
  1010. // Get the current comment for user
  1011. nStatus = NetUserGetInfo(NULL,
  1012. lpUserName,
  1013. 10,
  1014. (LPBYTE *) &lpUsrInfo10);
  1015. switch (nStatus)
  1016. {
  1017. case NERR_Success:
  1018. // old comment found
  1019. if (MyStrCmpI(lpUsrInfo10->usri10_comment, lpOldDesc) == 0)
  1020. {
  1021. if (bTest)
  1022. {
  1023. usri1007New.usri1007_comment = lpOldDesc;
  1024. }
  1025. else
  1026. {
  1027. usri1007New.usri1007_comment = lpNewDesc;
  1028. }
  1029. nStatus = NetUserSetInfo(NULL,
  1030. lpUserName,
  1031. 1007,
  1032. (LPBYTE) &usri1007New,
  1033. &dwErr);
  1034. if (nStatus == NERR_Success)
  1035. {
  1036. hr = S_OK;
  1037. }
  1038. else
  1039. {
  1040. hr = HRESULT_FROM_WIN32(nStatus);
  1041. }
  1042. }
  1043. else
  1044. {
  1045. hr = S_OK;
  1046. }
  1047. NetApiBufferFree(lpUsrInfo10);
  1048. break;
  1049. case NERR_UserNotFound:
  1050. hr = S_FALSE;
  1051. break;
  1052. default:
  1053. // error occured
  1054. hr = HRESULT_FROM_WIN32(nStatus);
  1055. break;
  1056. }
  1057. return hr;
  1058. }
  1059. //-----------------------------------------------------------------------------
  1060. //
  1061. // Function: ChangeGroupDesc
  1062. //
  1063. // Descrip: Chage the group description
  1064. //
  1065. // Returns: S_OK - Group description is okay to change
  1066. // S_FALSE - Group description cannot be changed (not an error)
  1067. // otherwise - error occured
  1068. //
  1069. // Notes: none
  1070. //
  1071. // History: 09/17/2001 xiaoz created
  1072. // 04/25/2002 Rerkboos Modified to work with domain group
  1073. //
  1074. // Notes: We will change commments first if we meet following 3 conditions
  1075. // 1. Both old and new comments are present
  1076. // 2. Old description (from INF file which is OS default) is same as
  1077. // current group's comment
  1078. // 3. Old and new comments are different
  1079. //
  1080. //-----------------------------------------------------------------------------
  1081. HRESULT ChangeGroupDesc(
  1082. LPTSTR lpGroupName, // User name
  1083. LPTSTR lpOldDesc, // Old description
  1084. LPTSTR lpNewDesc, // New description
  1085. BOOL bTest, // Anylyze mode or not
  1086. BOOL bDomainAPI // Is Domain Net API
  1087. )
  1088. {
  1089. HRESULT hr;
  1090. NET_API_STATUS nStatus;
  1091. PLOCALGROUP_INFO_1 plgrpi1LocalGroup = NULL;
  1092. PGROUP_INFO_1 pgrpi1DomainGroup = NULL;
  1093. LOCALGROUP_INFO_1 lgrpi1NewComment;
  1094. GROUP_INFO_1 grpi1NewComment;
  1095. PPVOID ppvGroupInfo;
  1096. PVOID pvNewGroupCommentInfo;
  1097. LPTSTR lpCurrentComment;
  1098. DWORD dwErr;
  1099. DWORD (*pfnGroupGetInfo)(LPCWSTR, LPCWSTR, DWORD, LPBYTE *);
  1100. DWORD (*pfnGroupSetInfo)(LPCWSTR, LPCWSTR, DWORD, LPBYTE, LPDWORD);
  1101. if (lpGroupName == NULL || lpOldDesc == NULL || lpNewDesc == NULL)
  1102. {
  1103. return E_INVALIDARG;
  1104. }
  1105. if (MyStrCmpI(lpOldDesc, lpNewDesc) == LSTR_EQUAL)
  1106. {
  1107. // Default group description are the same, do nothing
  1108. return S_FALSE;
  1109. }
  1110. //
  1111. // Choose which set of APIs/variables we will use
  1112. //
  1113. if (bDomainAPI)
  1114. {
  1115. // Domain group
  1116. ppvGroupInfo = &pgrpi1DomainGroup;
  1117. pvNewGroupCommentInfo = &grpi1NewComment;
  1118. pfnGroupGetInfo = &NetGroupGetInfo;
  1119. pfnGroupSetInfo = &NetGroupSetInfo;
  1120. }
  1121. else
  1122. {
  1123. // Local group
  1124. ppvGroupInfo = &plgrpi1LocalGroup;
  1125. pvNewGroupCommentInfo = &lgrpi1NewComment;
  1126. pfnGroupGetInfo = &NetLocalGroupGetInfo;
  1127. pfnGroupSetInfo = &NetLocalGroupSetInfo;
  1128. }
  1129. // Get the current group description
  1130. nStatus = (*pfnGroupGetInfo)(NULL,
  1131. lpGroupName,
  1132. 1,
  1133. (LPBYTE *) ppvGroupInfo);
  1134. switch (nStatus)
  1135. {
  1136. case NERR_Success:
  1137. if (bDomainAPI)
  1138. {
  1139. lpCurrentComment = pgrpi1DomainGroup->grpi1_comment ;
  1140. }
  1141. else
  1142. {
  1143. lpCurrentComment = plgrpi1LocalGroup->lgrpi1_comment;
  1144. }
  1145. if (bTest)
  1146. {
  1147. //In analyzing mode , we do a reset old value to see whether we will succeed
  1148. lgrpi1NewComment.lgrpi1_comment = lpCurrentComment;
  1149. grpi1NewComment.grpi1_comment = lpCurrentComment;
  1150. }
  1151. else
  1152. {
  1153. // in modifying mode, use the new group comment from INF
  1154. lgrpi1NewComment.lgrpi1_comment = lpNewDesc;
  1155. grpi1NewComment.grpi1_comment = lpNewDesc;
  1156. }
  1157. //
  1158. // Set the new group comment
  1159. //
  1160. nStatus = (*pfnGroupSetInfo)(NULL,
  1161. lpGroupName,
  1162. 1,
  1163. (LPBYTE) pvNewGroupCommentInfo,
  1164. &dwErr);
  1165. if (nStatus == NERR_Success)
  1166. {
  1167. hr = S_OK;
  1168. }
  1169. else
  1170. {
  1171. hr = HRESULT_FROM_WIN32(nStatus);
  1172. }
  1173. NetApiBufferFree(*ppvGroupInfo);
  1174. break;
  1175. case ERROR_NO_SUCH_ALIAS:
  1176. case NERR_GroupNotFound:
  1177. hr = S_FALSE;
  1178. break;
  1179. default:
  1180. hr = HRESULT_FROM_WIN32(nStatus);
  1181. }
  1182. return hr;
  1183. }
  1184. //-----------------------------------------------------------------------------
  1185. //
  1186. // Function: ChangeUserFullName
  1187. //
  1188. // Descrip: Chage the User full name
  1189. //
  1190. // Returns: S_OK - User full name is okay to change
  1191. // S_FALSE - User full name cannot be changed (not an error)
  1192. // otherwise - error occured
  1193. //
  1194. // Notes: none
  1195. //
  1196. // History: 09/17/2001 xiaoz created
  1197. // 04/25/2002 Rerkboos Modified to work with domain group
  1198. //
  1199. // Notes: none
  1200. //
  1201. //-----------------------------------------------------------------------------
  1202. HRESULT ChangeUserFullName(
  1203. LPTSTR lpUserName, // User name
  1204. LPTSTR lpOldFullName, // Old full name
  1205. LPTSTR lpNewFullName, // New full name
  1206. BOOL bTest // Anylyze mode or not
  1207. )
  1208. {
  1209. LPUSER_INFO_10 lpUsrInfo10;
  1210. USER_INFO_1011 usri1011New;
  1211. NET_API_STATUS nStatus;
  1212. DWORD dwErr;
  1213. HRESULT hr;
  1214. if (lpUserName == NULL || lpOldFullName == NULL || lpNewFullName == NULL)
  1215. {
  1216. return E_INVALIDARG;
  1217. }
  1218. if (MyStrCmpI(lpOldFullName, lpNewFullName) == 0)
  1219. {
  1220. return S_OK;
  1221. }
  1222. // Get the current comment for user
  1223. nStatus = NetUserGetInfo(NULL,
  1224. lpUserName,
  1225. 10,
  1226. (LPBYTE *) &lpUsrInfo10);
  1227. switch (nStatus)
  1228. {
  1229. case NERR_Success:
  1230. // old comment found
  1231. if (MyStrCmpI(lpUsrInfo10->usri10_full_name, lpOldFullName) == 0)
  1232. {
  1233. if (bTest)
  1234. {
  1235. usri1011New.usri1011_full_name = lpOldFullName;
  1236. }
  1237. else
  1238. {
  1239. usri1011New.usri1011_full_name = lpNewFullName;
  1240. }
  1241. nStatus = NetUserSetInfo(NULL,
  1242. lpUserName,
  1243. 1011,
  1244. (LPBYTE) &usri1011New,
  1245. &dwErr);
  1246. if (nStatus == NERR_Success)
  1247. {
  1248. hr = S_OK;
  1249. }
  1250. else
  1251. {
  1252. hr = HRESULT_FROM_WIN32(nStatus);
  1253. }
  1254. }
  1255. else
  1256. {
  1257. hr = S_OK;
  1258. }
  1259. NetApiBufferFree(lpUsrInfo10);
  1260. break;
  1261. case NERR_UserNotFound:
  1262. hr = S_FALSE;
  1263. break;
  1264. default:
  1265. // error occured
  1266. hr = HRESULT_FROM_WIN32(nStatus);
  1267. break;
  1268. }
  1269. return hr;
  1270. }
  1271. //-----------------------------------------------------------------------------
  1272. //
  1273. // Function: SetUserNetworkProfilePath
  1274. //
  1275. // Descrip: Set the path to network user's profile.
  1276. //
  1277. // Returns: S_OK - profile path is changed correctly
  1278. //
  1279. // History: 05/20/2002 Rerkboos Created
  1280. //
  1281. // Notes: none
  1282. //
  1283. //-----------------------------------------------------------------------------
  1284. HRESULT SetUserNetworkProfilePath(
  1285. LPCTSTR lpUserName, // User Name
  1286. LPCTSTR lpNewPath // New Path
  1287. )
  1288. {
  1289. HRESULT hr = S_OK;
  1290. NET_API_STATUS nStatus;
  1291. USER_INFO_1052 usri1052;
  1292. if (lpNewPath == NULL || *lpNewPath == TEXT('\0'))
  1293. {
  1294. return S_FALSE;
  1295. }
  1296. usri1052.usri1052_profile = (LPTSTR) lpNewPath;
  1297. nStatus = NetUserSetInfo(NULL,
  1298. lpUserName,
  1299. 1052,
  1300. (LPBYTE) &usri1052,
  1301. NULL);
  1302. if (nStatus != NERR_Success)
  1303. {
  1304. hr = HRESULT_FROM_WIN32(nStatus);
  1305. }
  1306. return hr;
  1307. }
  1308. //-----------------------------------------------------------------------------
  1309. //
  1310. // Function: SetUserLogOnScriptPath
  1311. //
  1312. // Descrip: Set the path to users's logon script file.
  1313. //
  1314. // Returns: S_OK - profile path is changed correctly
  1315. //
  1316. // History: 05/20/2002 Rerkboos Created
  1317. //
  1318. // Notes: none
  1319. //
  1320. //-----------------------------------------------------------------------------
  1321. HRESULT SetUserLogOnScriptPath(
  1322. LPCTSTR lpUserName, // User Name
  1323. LPCTSTR lpNewPath // New path
  1324. )
  1325. {
  1326. HRESULT hr = S_OK;
  1327. NET_API_STATUS nStatus;
  1328. USER_INFO_1009 usri1009;
  1329. if (lpNewPath == NULL || *lpNewPath == TEXT('\0'))
  1330. {
  1331. return S_FALSE;
  1332. }
  1333. usri1009.usri1009_script_path = (LPTSTR) lpNewPath;
  1334. nStatus = NetUserSetInfo(NULL,
  1335. lpUserName,
  1336. 1009,
  1337. (LPBYTE) &usri1009,
  1338. NULL);
  1339. if (nStatus != NERR_Success)
  1340. {
  1341. hr = HRESULT_FROM_WIN32(nStatus);
  1342. }
  1343. return hr;
  1344. }
  1345. //-----------------------------------------------------------------------------
  1346. //
  1347. // Function: SetUserHomeDir
  1348. //
  1349. // Descrip: Set the path of the home directory for the user
  1350. //
  1351. // Returns: S_OK - profile path is changed correctly
  1352. //
  1353. // History: 05/20/2002 Rerkboos Created
  1354. //
  1355. // Notes: none
  1356. //
  1357. //-----------------------------------------------------------------------------
  1358. HRESULT SetUserHomeDir(
  1359. LPCTSTR lpUserName, // User Name
  1360. LPCTSTR lpNewPath // New path
  1361. )
  1362. {
  1363. HRESULT hr = S_OK;
  1364. NET_API_STATUS nStatus;
  1365. USER_INFO_1006 usri1006;
  1366. if (lpNewPath == NULL || *lpNewPath == TEXT('\0'))
  1367. {
  1368. return S_FALSE;
  1369. }
  1370. usri1006.usri1006_home_dir = (LPTSTR) lpNewPath;
  1371. nStatus = NetUserSetInfo(NULL,
  1372. lpUserName,
  1373. 1006,
  1374. (LPBYTE) &usri1006,
  1375. NULL);
  1376. if (nStatus != NERR_Success)
  1377. {
  1378. hr = HRESULT_FROM_WIN32(nStatus);
  1379. }
  1380. return hr;
  1381. }
  1382. //-----------------------------------------------------------------------------
  1383. //
  1384. // Function: SetTSUserPath
  1385. //
  1386. // Descrip: Set the Terminal Services related profile path. The type of
  1387. // profile path is determined by WTSConfigClass parameter.
  1388. //
  1389. // Returns: S_OK - profile path is changed correctly
  1390. //
  1391. // History: 05/20/2002 Rerkboos Created
  1392. //
  1393. // Notes: none
  1394. //
  1395. //-----------------------------------------------------------------------------
  1396. HRESULT SetTSUserPath(
  1397. LPCTSTR lpUserName, // User Name
  1398. LPCTSTR lpNewProfilePath, // New path
  1399. WTS_CONFIG_CLASS WTSConfigClass // TS configuration class
  1400. )
  1401. {
  1402. HRESULT hr = S_OK;
  1403. BOOL bRet;
  1404. DWORD cbNewProfilePath;
  1405. cbNewProfilePath = lstrlen(lpNewProfilePath) * sizeof(TCHAR);
  1406. bRet = WTSSetUserConfig(WTS_CURRENT_SERVER_NAME,
  1407. (LPTSTR) lpUserName,
  1408. WTSConfigClass,
  1409. (LPTSTR) lpNewProfilePath,
  1410. cbNewProfilePath);
  1411. if (!bRet)
  1412. {
  1413. hr = HRESULT_FROM_WIN32(GetLastError());
  1414. }
  1415. return hr;
  1416. }
  1417. //-----------------------------------------------------------------------------
  1418. //
  1419. // Function: PreFixUserProfilePath
  1420. //
  1421. // Descrip: Replace the "%documents_and_settings%\OldUserName\..." to
  1422. // "%documents_and_settings%\NewUserName\...". The function will
  1423. // not fix the paths after "%documents_and_settings%\OldUserName",
  1424. // they will just get append to the new profile path.
  1425. //
  1426. // Returns: S_OK - Path has been fixed
  1427. // S_FALSE - Path does not need the fix
  1428. // Else - error occurred
  1429. //
  1430. // History: 05/20/2002 Rerkboos Created
  1431. // 06/16/2002 Rerkboos Change to return HRESULT
  1432. //
  1433. // Notes: none
  1434. //
  1435. //-----------------------------------------------------------------------------
  1436. HRESULT PreFixUserProfilePath(
  1437. LPCTSTR lpOldPath, // Old path
  1438. LPCTSTR lpNewProfilePath, // Expected new profile path (with unloc user name)
  1439. LPTSTR lpPath, // Buffer to store new profile path
  1440. DWORD cchPath // Size of buffer (in TCHAR)
  1441. )
  1442. {
  1443. HRESULT hr = S_OK;
  1444. BOOL bRet;
  1445. TCHAR szNewPath[MAX_PATH];
  1446. DWORD cchNewProfilePath;
  1447. TCHAR chEnd;
  1448. cchNewProfilePath = lstrlen(lpNewProfilePath);
  1449. if (StrCmpNI(lpNewProfilePath, lpOldPath, cchNewProfilePath) == LSTR_EQUAL)
  1450. {
  1451. chEnd = *(lpOldPath + cchNewProfilePath);
  1452. if (chEnd == TEXT('\\'))
  1453. {
  1454. hr = StringCchCopy(szNewPath, ARRAYSIZE(szNewPath), lpNewProfilePath);
  1455. if (SUCCEEDED(hr))
  1456. {
  1457. bRet = ConcatenatePaths(szNewPath,
  1458. (lpOldPath + cchNewProfilePath + 1),
  1459. ARRAYSIZE(szNewPath));
  1460. if (bRet)
  1461. {
  1462. if ((DWORD) lstrlen(szNewPath) < cchPath)
  1463. {
  1464. hr = StringCchCopy(lpPath, cchPath, szNewPath);
  1465. }
  1466. }
  1467. else
  1468. {
  1469. hr = E_FAIL;
  1470. }
  1471. }
  1472. }
  1473. else if (chEnd == TEXT('\0'))
  1474. {
  1475. if ((DWORD) lstrlen(lpNewProfilePath) < cchPath)
  1476. {
  1477. hr = StringCchCopy(lpPath, cchPath, lpNewProfilePath);
  1478. }
  1479. }
  1480. }
  1481. else
  1482. {
  1483. hr = StringCchCopy(lpPath, cchPath, lpOldPath);
  1484. hr = (FAILED(hr) ? hr : S_FALSE);
  1485. }
  1486. return hr;
  1487. }
  1488. //-----------------------------------------------------------------------------
  1489. //
  1490. // Function: ReplaceLocStringInPath
  1491. //
  1492. // Descrip: This is a simplify version of ReplaceSingleString() from utils.c
  1493. // The function will replace all localized strings in path without
  1494. // checking that the path is valid or not. As we are already know
  1495. // that the input path MUST be valid one.
  1496. //
  1497. // Returns: Address to newly allocated string buffer if the function does
  1498. // replace localized string(s).
  1499. // NULL otherwise.
  1500. //
  1501. // History: 05/22/2002 rerkboos created
  1502. //
  1503. // Notes: Caller must free the allocated memory using HeapFree() API or
  1504. // MEMFREE() macro.
  1505. //
  1506. //-----------------------------------------------------------------------------
  1507. LPTSTR ReplaceLocStringInPath(
  1508. LPCTSTR lpOldString,
  1509. BOOL bVerifyPath
  1510. )
  1511. {
  1512. LPTSTR lpNewString = NULL;
  1513. DWORD cchNewString;
  1514. DWORD dwMatchNum;
  1515. DWORD dwNumReplaced;
  1516. BOOL bRet;
  1517. if (lpOldString == NULL || *lpOldString == TEXT('\0'))
  1518. {
  1519. return NULL;
  1520. }
  1521. dwMatchNum = GetMaxMatchNum((LPTSTR) lpOldString, &g_StrReplaceTable);
  1522. if (dwMatchNum > 0)
  1523. {
  1524. cchNewString = lstrlen(lpOldString)
  1525. + (g_StrReplaceTable.cchMaxStrLen * dwMatchNum);
  1526. lpNewString = (LPTSTR) MEMALLOC(cchNewString * sizeof(TCHAR));
  1527. if (lpNewString != NULL)
  1528. {
  1529. bRet = ReplaceMultiMatchInString((LPTSTR) lpOldString,
  1530. lpNewString,
  1531. cchNewString,
  1532. dwMatchNum,
  1533. &g_StrReplaceTable,
  1534. &dwNumReplaced,
  1535. bVerifyPath);
  1536. if (!bRet)
  1537. {
  1538. MEMFREE(lpNewString);
  1539. lpNewString = NULL;
  1540. }
  1541. }
  1542. }
  1543. return lpNewString;
  1544. }
  1545. //-----------------------------------------------------------------------------
  1546. //
  1547. // Function: ChangeRDN
  1548. //
  1549. // Descrip: Chage the User/group RDN
  1550. //
  1551. // Returns: S_OK - User/group RDN is okay to change
  1552. // S_FALSE - User/group RDN cannot be changed (not an error)
  1553. // otherwise - error occured
  1554. //
  1555. // History: 09/17/2001 xiaoz created
  1556. // 04/25/2002 Rerkboos Modified to work with domain group
  1557. //
  1558. // Notes: none
  1559. //
  1560. //-----------------------------------------------------------------------------
  1561. HRESULT ChangeRDN(
  1562. LPTSTR lpOldRDN, // Old user/group RDN
  1563. LPTSTR lpNewRDN, // New user/group RDN
  1564. LPTSTR lpDomainName, // Machine domain name
  1565. BOOL bTest // Analyze mode or not
  1566. )
  1567. {
  1568. HRESULT hr;
  1569. LPTSTR lpOldFQDN;
  1570. BOOL bRDNChangeNeeded = FALSE;
  1571. LPTSTR lpNewRDNWithCN = NULL;
  1572. DWORD cchNewRDNWithCN;
  1573. LPTSTR lpOldFQDNWithLDAP = NULL;
  1574. DWORD cchOldFQDNWithLDAP;
  1575. LPTSTR lpContainerPathWithLDAP = NULL;
  1576. DWORD cchContainerPathWithLDAP;
  1577. LPTSTR lpContainerPath;
  1578. //
  1579. // First, try to get a FQDN of the old RDN
  1580. //
  1581. hr = GetFQDN(lpOldRDN, lpDomainName, &lpOldFQDN);
  1582. if (hr == S_OK)
  1583. {
  1584. // Old RDN exists in the system, find out more if we should rename it
  1585. hr = GetFQDN(lpNewRDN, lpDomainName, NULL);
  1586. if (hr == S_FALSE)
  1587. {
  1588. // New name doesn't exits, we are ok to rename old RDN
  1589. bRDNChangeNeeded = TRUE;
  1590. }
  1591. }
  1592. if (!bRDNChangeNeeded)
  1593. {
  1594. goto EXIT;
  1595. }
  1596. //
  1597. // Next, if the old RDN exists then we prepare some value to use in next step
  1598. //
  1599. lpContainerPath = StrStrI(lpOldFQDN, TEXT("=Users"));
  1600. if (lpContainerPath)
  1601. {
  1602. // Make container path points to "CN=Users, CN=...., CN=com"
  1603. lpContainerPath -= 2;
  1604. cchContainerPathWithLDAP = lstrlen(lpContainerPath) + lstrlen(TEXT("LDAP://")) + 1;
  1605. lpContainerPathWithLDAP = (LPTSTR) MEMALLOC(cchContainerPathWithLDAP * sizeof(TCHAR));
  1606. if (lpContainerPathWithLDAP)
  1607. {
  1608. hr = StringCchPrintf(lpContainerPathWithLDAP,
  1609. cchContainerPathWithLDAP,
  1610. TEXT("LDAP://%s"),
  1611. lpContainerPath);
  1612. if (FAILED(hr))
  1613. {
  1614. goto EXIT;
  1615. }
  1616. }
  1617. else
  1618. {
  1619. hr = E_OUTOFMEMORY;
  1620. goto EXIT;
  1621. }
  1622. }
  1623. else
  1624. {
  1625. hr = S_FALSE;
  1626. goto EXIT;
  1627. }
  1628. // Compose the string "CN=new RDN name"
  1629. cchNewRDNWithCN = lstrlen(lpNewRDN) + lstrlen(lpOldRDN)
  1630. + lstrlen(TEXT("CN=")) + 1;
  1631. lpNewRDNWithCN = (LPTSTR) MEMALLOC(cchNewRDNWithCN * sizeof(TCHAR));
  1632. if (lpNewRDNWithCN)
  1633. {
  1634. if (bTest)
  1635. {
  1636. hr = StringCchPrintf(lpNewRDNWithCN,
  1637. cchNewRDNWithCN,
  1638. TEXT("CN=%s"),
  1639. lpOldRDN);
  1640. }
  1641. else
  1642. {
  1643. hr = StringCchPrintf(lpNewRDNWithCN,
  1644. cchNewRDNWithCN,
  1645. TEXT("CN=%s"),
  1646. lpNewRDN);
  1647. }
  1648. if (FAILED(hr))
  1649. {
  1650. goto EXIT;
  1651. }
  1652. }
  1653. else
  1654. {
  1655. hr = E_OUTOFMEMORY;
  1656. goto EXIT;
  1657. }
  1658. // Compose the string "LDAP://CN=Old RDN, OU=Users, ...."
  1659. cchOldFQDNWithLDAP = lstrlen(lpOldFQDN) + lstrlen(TEXT("LDAP://")) + 1;
  1660. lpOldFQDNWithLDAP = (LPTSTR) MEMALLOC(cchOldFQDNWithLDAP * sizeof(TCHAR));
  1661. if (lpOldFQDNWithLDAP)
  1662. {
  1663. hr = StringCchPrintf(lpOldFQDNWithLDAP,
  1664. cchOldFQDNWithLDAP,
  1665. TEXT("LDAP://%s"),
  1666. lpOldFQDN);
  1667. if (FAILED(hr))
  1668. {
  1669. goto EXIT;
  1670. }
  1671. }
  1672. else
  1673. {
  1674. hr = E_OUTOFMEMORY;
  1675. goto EXIT;
  1676. }
  1677. //
  1678. // Now, this is the part to do an RDN renaming
  1679. //
  1680. hr = RenameRDN(lpContainerPathWithLDAP, lpOldFQDNWithLDAP, lpNewRDNWithCN);
  1681. if (FAILED(hr))
  1682. {
  1683. DPF(PROerr, TEXT("ChangeDomainGroupName: Unable to change RDN name for %s"), lpOldRDN);
  1684. }
  1685. EXIT:
  1686. if (lpNewRDNWithCN)
  1687. {
  1688. MEMFREE(lpNewRDNWithCN);
  1689. }
  1690. if (lpOldFQDNWithLDAP)
  1691. {
  1692. MEMFREE(lpOldFQDNWithLDAP);
  1693. }
  1694. if (lpContainerPathWithLDAP)
  1695. {
  1696. MEMFREE(lpContainerPathWithLDAP);
  1697. }
  1698. return hr;
  1699. }
  1700. //-----------------------------------------------------------------------------
  1701. //
  1702. // Function: GetFQDN
  1703. //
  1704. // Descrip: Get Fully Qualified Domain Name
  1705. //
  1706. // Returns: S_OK - Successfully get FQDN
  1707. // S_FALSE - FQDN for the account not found
  1708. // otherwise - error occured
  1709. //
  1710. // History: 04/25/2002 Rerkboos Created
  1711. //
  1712. // Notes: none
  1713. //
  1714. //-----------------------------------------------------------------------------
  1715. HRESULT GetFQDN(
  1716. LPTSTR lpAccountName, // Account name
  1717. LPTSTR lpDomainName, // Machine domain name
  1718. LPTSTR *plpFQDN // Address of the pointer to FQDN of the account
  1719. )
  1720. {
  1721. HRESULT hr = E_FAIL;
  1722. HANDLE hDS;
  1723. DWORD dwErr;
  1724. LPTSTR lpFQDN = NULL;
  1725. LPTSTR lpOldSamAccount = NULL;
  1726. DWORD cchOldSamAccount;
  1727. dwErr = DsBind(NULL, lpDomainName, &hDS);
  1728. if (dwErr == NO_ERROR)
  1729. {
  1730. cchOldSamAccount = lstrlen(lpDomainName) + lstrlen(lpAccountName) + 2;
  1731. lpOldSamAccount = (LPTSTR) MEMALLOC(cchOldSamAccount * sizeof(TCHAR));
  1732. if (lpOldSamAccount)
  1733. {
  1734. // Compose a SAM account name DOMAIN\USERNAME
  1735. hr = StringCchPrintf(lpOldSamAccount,
  1736. cchOldSamAccount,
  1737. TEXT("%s\\%s"),
  1738. lpDomainName,
  1739. lpAccountName);
  1740. if (SUCCEEDED(hr))
  1741. {
  1742. PDS_NAME_RESULT pdsName;
  1743. // Get an FQDN name of a specified SAM account name
  1744. dwErr = DsCrackNames(hDS,
  1745. DS_NAME_NO_FLAGS,
  1746. DS_NT4_ACCOUNT_NAME,
  1747. DS_FQDN_1779_NAME,
  1748. 1,
  1749. &lpOldSamAccount,
  1750. &pdsName);
  1751. if (dwErr == DS_NAME_NO_ERROR)
  1752. {
  1753. if (pdsName->rItems->status == DS_NAME_NO_ERROR)
  1754. {
  1755. if (plpFQDN)
  1756. {
  1757. *plpFQDN = pdsName->rItems->pName;
  1758. }
  1759. hr = S_OK;
  1760. }
  1761. else if (pdsName->rItems->status == DS_NAME_ERROR_NOT_FOUND)
  1762. {
  1763. hr = S_FALSE;
  1764. }
  1765. else
  1766. {
  1767. hr = HRESULT_FROM_WIN32(pdsName->rItems->status);
  1768. }
  1769. }
  1770. }
  1771. MEMFREE(lpOldSamAccount);
  1772. }
  1773. DsUnBind(&hDS);
  1774. }
  1775. if (dwErr != NO_ERROR)
  1776. {
  1777. hr = HRESULT_FROM_WIN32(dwErr);
  1778. }
  1779. return hr;
  1780. }
  1781. HRESULT RenameDocuments_and_Settings(
  1782. HINF hInf,
  1783. BOOL bTest)
  1784. {
  1785. const FOLDER_INFO *pfi;
  1786. HRESULT hr = S_OK;
  1787. TCHAR szSection[MAX_PATH];
  1788. INFCONTEXT context ;
  1789. int nOriIndexFldr, nNewIndexFldr;
  1790. TCHAR szOriFld[MAX_PATH], szNewFld[MAX_PATH];
  1791. if (!bTest)
  1792. {
  1793. return S_OK;
  1794. }
  1795. for (pfi = c_rgFolderInfo; pfi->id != -1; pfi++)
  1796. {
  1797. if (pfi->id == CSIDL_PROFILES_DIRECTORY)
  1798. {
  1799. break;
  1800. }
  1801. }
  1802. if (pfi->id == -1 )
  1803. {
  1804. hr = E_FAIL;
  1805. goto Cleanup;
  1806. }
  1807. //Get the folder Line for the section just found
  1808. if (FAILED(hr = StringCchCopy(szSection,MAX_PATH,SHELL_FOLDER_PREFIX)))
  1809. {
  1810. goto Cleanup;
  1811. }
  1812. if (FAILED(hr = StringCchCat(szSection,MAX_PATH,pfi->pszIdInString)))
  1813. {
  1814. goto Cleanup;
  1815. }
  1816. if (!SetupFindFirstLine(hInf, szSection,SHELL_FOLDER_FOLDER,&context))
  1817. {
  1818. hr = E_FAIL;
  1819. goto Cleanup;
  1820. }
  1821. nOriIndexFldr = 3;
  1822. nNewIndexFldr = 4;
  1823. if (!SetupGetStringField(&context,nOriIndexFldr,szOriFld,MAX_PATH,NULL)
  1824. || !SetupGetStringField(&context,nNewIndexFldr,szNewFld,MAX_PATH,NULL))
  1825. {
  1826. hr = E_FAIL;
  1827. goto Cleanup;
  1828. }
  1829. if (!MyStrCmpI(szOriFld,szNewFld))
  1830. {
  1831. hr = S_FALSE;
  1832. goto Cleanup;
  1833. }
  1834. hr = FixFolderPath(pfi->id, NULL,hInf,TEXT("System"),FALSE);
  1835. Cleanup:
  1836. return hr;
  1837. }
  1838. HRESULT AddProfileChangeItem(
  1839. DWORD dwType,
  1840. LPTSTR lpOldName,
  1841. LPTSTR lpNewName,
  1842. LPTSTR lpOldDesc,
  1843. LPTSTR lpNewDesc,
  1844. LPTSTR lpOldFullName,
  1845. LPTSTR lpNewFullName)
  1846. {
  1847. LPTSTR lpszOneline = NULL;
  1848. size_t ccbOneline;
  1849. TCHAR szIndex[MAX_PATH];
  1850. HRESULT hr;
  1851. if (lpOldName == NULL || lpNewName == NULL)
  1852. {
  1853. hr = E_INVALIDARG;
  1854. goto Cleanup;
  1855. }
  1856. if ( (dwType != OP_USER)
  1857. && (dwType != OP_GRP)
  1858. && (dwType != OP_PROFILE)
  1859. && (dwType != OP_DOMAIN_GRP) )
  1860. {
  1861. hr = E_INVALIDARG;
  1862. goto Cleanup;
  1863. }
  1864. if ( (!lpOldDesc && lpNewDesc )||(lpOldDesc && !lpNewDesc) )
  1865. {
  1866. hr = E_INVALIDARG;
  1867. goto Cleanup;
  1868. }
  1869. if ( (!lpOldFullName && lpNewFullName )||(lpOldFullName && !lpNewFullName) )
  1870. {
  1871. hr = E_INVALIDARG;
  1872. goto Cleanup;
  1873. }
  1874. ccbOneline = lstrlen(lpOldName) + lstrlen(lpNewName)+ MAX_PATH;
  1875. if (lpOldDesc)
  1876. {
  1877. ccbOneline += (lstrlen(lpOldDesc) + lstrlen(lpNewDesc));
  1878. }
  1879. if (lpOldFullName)
  1880. {
  1881. ccbOneline += (lstrlen(lpOldFullName)+ lstrlen(lpNewFullName));
  1882. }
  1883. if (!(lpszOneline = malloc(ccbOneline * sizeof(TCHAR))))
  1884. {
  1885. hr = E_OUTOFMEMORY;
  1886. goto Cleanup;
  1887. }
  1888. switch (dwType)
  1889. {
  1890. case OP_USER://fall through, no break here
  1891. case OP_GRP:
  1892. case OP_DOMAIN_GRP:
  1893. if (lpOldDesc && lpOldFullName)
  1894. { // if comments and fill name are both presented
  1895. if (FAILED(StringCchPrintf(lpszOneline,ccbOneline,TEXT("%d,\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\""),
  1896. dwType,lpOldName,lpNewName,lpOldDesc,lpNewDesc,lpOldFullName,lpNewFullName)))
  1897. {
  1898. hr = E_FAIL;
  1899. goto Cleanup;
  1900. }
  1901. }
  1902. else if (!lpOldDesc && !lpOldFullName)
  1903. {
  1904. // if comments and fill name are both not presented
  1905. if (FAILED(StringCchPrintf(lpszOneline,ccbOneline,TEXT("%d,\"%s\",\"%s\""),dwType,lpOldName,lpNewName)))
  1906. {
  1907. hr = E_FAIL;
  1908. goto Cleanup;
  1909. }
  1910. }
  1911. else if (lpOldDesc)
  1912. {
  1913. // if only comments are there
  1914. if (FAILED(StringCchPrintf(lpszOneline,ccbOneline,TEXT("%d,\"%s\",\"%s\",\"%s\",\"%s\""),
  1915. dwType,lpOldName,lpNewName,lpOldDesc,lpNewDesc)))
  1916. {
  1917. hr = E_FAIL;
  1918. goto Cleanup;
  1919. }
  1920. }
  1921. else
  1922. { // if only full name are there
  1923. if (FAILED(StringCchPrintf(lpszOneline,ccbOneline,TEXT("%d,\"%s\",\"%s\",\"\",\"\",\"%s\",\"%s\""),dwType,
  1924. lpOldName,lpNewName,lpOldFullName,lpNewFullName)))
  1925. {
  1926. hr = E_FAIL;
  1927. goto Cleanup;
  1928. }
  1929. }
  1930. break;
  1931. case OP_PROFILE:
  1932. if (FAILED(StringCchPrintf(lpszOneline,ccbOneline,TEXT("%d,\"%s\",\"%s\""),dwType,
  1933. lpOldName,lpNewName)))
  1934. {
  1935. hr = E_FAIL;
  1936. goto Cleanup;
  1937. }
  1938. break;
  1939. }
  1940. g_dwKeyIndex++;
  1941. _itot(g_dwKeyIndex,szIndex,16);
  1942. if (!WritePrivateProfileString(USERGRPSECTION,szIndex,lpszOneline,g_szToDoINFFileName))
  1943. {
  1944. hr = HRESULT_FROM_WIN32(GetLastError());
  1945. goto Cleanup;
  1946. }
  1947. hr = S_OK;
  1948. Cleanup:
  1949. FreePointer(lpszOneline);
  1950. return hr;
  1951. }
  1952. HRESULT
  1953. PolicyGetPrivilege(
  1954. LPTSTR userName,
  1955. PLSA_HANDLE pPolicyHandle,
  1956. PLSA_UNICODE_STRING *ppPrivileges,
  1957. PULONG pCountOfRights)
  1958. {
  1959. LSA_OBJECT_ATTRIBUTES ObjectAttributes ;
  1960. NTSTATUS status;
  1961. PSID psid = NULL;
  1962. HRESULT hr;
  1963. hr = GetSIDFromName(userName,&psid);
  1964. if (hr != S_OK)
  1965. {
  1966. goto cleanup;
  1967. }
  1968. ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
  1969. status = LsaOpenPolicy(NULL,&ObjectAttributes, POLICY_ALL_ACCESS,pPolicyHandle);
  1970. if (STATUS_SUCCESS != status)
  1971. {
  1972. hr = HRESULT_FROM_WIN32(LsaNtStatusToWinError(status));
  1973. goto cleanup;
  1974. }
  1975. status = LsaEnumerateAccountRights(*pPolicyHandle,psid,ppPrivileges,pCountOfRights);
  1976. if (STATUS_SUCCESS != status)
  1977. {
  1978. hr = HRESULT_FROM_WIN32(LsaNtStatusToWinError(status));
  1979. goto cleanup;
  1980. }
  1981. cleanup:
  1982. if (psid)
  1983. {
  1984. free(psid);
  1985. }
  1986. return hr;
  1987. }
  1988. HRESULT
  1989. PolicySetPrivilege(
  1990. LPTSTR userName,
  1991. LSA_HANDLE PolicyHandle,
  1992. PLSA_UNICODE_STRING pPrivileges,
  1993. ULONG CountOfRights)
  1994. {
  1995. NTSTATUS status;
  1996. PSID psid = NULL;
  1997. HRESULT hr;
  1998. hr = GetSIDFromName(userName,&psid);
  1999. if (hr != S_OK)
  2000. {
  2001. goto cleanup;
  2002. }
  2003. status = LsaAddAccountRights(PolicyHandle,psid,pPrivileges,CountOfRights);
  2004. if (STATUS_SUCCESS != status)
  2005. {
  2006. hr = HRESULT_FROM_WIN32(LsaNtStatusToWinError(status));
  2007. goto cleanup;
  2008. }
  2009. cleanup:
  2010. if (psid)
  2011. {
  2012. free(psid);
  2013. }
  2014. return hr;
  2015. }
  2016. //-----------------------------------------------------------------------------
  2017. //
  2018. // Function: IsPathLocal
  2019. //
  2020. // Descrip: Check if the path is a local system drive, not UNC.
  2021. //
  2022. // Returns: TRUE - Path is on local system drive
  2023. // FALSE - otherwise
  2024. //
  2025. // History: 04/25/2002 Rerkboos Created
  2026. //
  2027. // Notes: none
  2028. //
  2029. //-----------------------------------------------------------------------------
  2030. BOOL IsPathLocal(
  2031. LPCTSTR lpPath
  2032. )
  2033. {
  2034. BOOL bIsPathLocal = FALSE;
  2035. TCHAR szSysWinDir[MAX_PATH];
  2036. TCHAR szExpPath[MAX_PATH];
  2037. UINT uRet;
  2038. if (lpPath == NULL || *lpPath == TEXT('\0'))
  2039. {
  2040. return FALSE;
  2041. }
  2042. ExpandEnvironmentStrings(lpPath, szExpPath, ARRAYSIZE(szExpPath));
  2043. uRet = GetSystemWindowsDirectory(szSysWinDir, ARRAYSIZE(szSysWinDir));
  2044. if (uRet > 0)
  2045. {
  2046. // Compare the first 2 characters for a Drive letter
  2047. if (StrCmpNI(szSysWinDir, szExpPath, 2) == LSTR_EQUAL)
  2048. {
  2049. bIsPathLocal = TRUE;
  2050. }
  2051. }
  2052. return bIsPathLocal;
  2053. }
  2054. HRESULT EnumUserProfile(PROFILEENUMPROC pfnProfileProc)
  2055. {
  2056. HRESULT hr = S_FALSE;
  2057. BOOL bRet;
  2058. LPUSER_INFO_0 lpusri0 = NULL;
  2059. LPUSER_INFO_0 lpTmp;
  2060. NET_API_STATUS nStatus;
  2061. DWORD dwEntriesRead = 0;
  2062. DWORD dwTotalEntries = 0;
  2063. DWORD dwResumeHandle = 0;
  2064. LPVOID lpSid = NULL;
  2065. DWORD cbSid;
  2066. LPTSTR lpStringSid = NULL;
  2067. TCHAR szDomain[MAX_PATH];
  2068. DWORD cbDomain;
  2069. SID_NAME_USE SidUse;
  2070. DWORD i;
  2071. DWORD dwLevel = 0;
  2072. cbSid = SECURITY_MAX_SID_SIZE;
  2073. lpSid = MEMALLOC(cbSid);
  2074. if (lpSid == NULL)
  2075. {
  2076. return E_OUTOFMEMORY;
  2077. }
  2078. do
  2079. {
  2080. nStatus = NetUserEnum(NULL, // This server
  2081. 0,
  2082. FILTER_NORMAL_ACCOUNT,
  2083. (LPBYTE *) &lpusri0,
  2084. MAX_PREFERRED_LENGTH,
  2085. &dwEntriesRead,
  2086. &dwTotalEntries,
  2087. &dwResumeHandle);
  2088. if (nStatus == NERR_Success || nStatus == ERROR_MORE_DATA)
  2089. {
  2090. lpTmp = lpusri0;
  2091. if (lpTmp != NULL)
  2092. {
  2093. // Loop through all entries
  2094. for (i = 0 ; i < dwEntriesRead ; i++)
  2095. {
  2096. cbDomain = ARRAYSIZE(szDomain) * sizeof(TCHAR);
  2097. bRet = LookupAccountName(NULL,
  2098. lpTmp->usri0_name,
  2099. (PSID) lpSid,
  2100. &cbSid,
  2101. szDomain,
  2102. &cbDomain,
  2103. &SidUse);
  2104. if (bRet)
  2105. {
  2106. bRet = ConvertSidToStringSid((PSID) lpSid, &lpStringSid);
  2107. if (bRet)
  2108. {
  2109. hr = pfnProfileProc(lpTmp->usri0_name, lpStringSid);
  2110. LocalFree(lpStringSid);
  2111. if (FAILED(hr))
  2112. {
  2113. goto EXIT;
  2114. }
  2115. }
  2116. }
  2117. if (!bRet)
  2118. {
  2119. hr = HRESULT_FROM_WIN32(GetLastError());
  2120. goto EXIT;
  2121. }
  2122. lpTmp++;
  2123. }
  2124. NetApiBufferFree(lpusri0);
  2125. lpusri0 = NULL;
  2126. }
  2127. }
  2128. else
  2129. {
  2130. hr = HRESULT_FROM_WIN32(nStatus);
  2131. goto EXIT;
  2132. }
  2133. }
  2134. while (nStatus == ERROR_MORE_DATA);
  2135. EXIT:
  2136. if (lpusri0 != NULL)
  2137. {
  2138. NetApiBufferFree(lpusri0);
  2139. }
  2140. if (lpSid != NULL)
  2141. {
  2142. MEMFREE(lpSid);
  2143. }
  2144. return hr;
  2145. }
  2146. //-----------------------------------------------------------------------------
  2147. //
  2148. // Function: AnalyzeMiscProfilePathPerUser
  2149. //
  2150. // Synopsis: Analyze the user's profile path. If the profile paths need to
  2151. // be changed, the function will add entries to CLMTDO.INF. These
  2152. // entries will be set by ResetMiscProfilePathPerUser() function
  2153. // later in the DoCritical state.
  2154. //
  2155. // Returns: S_OK, we don't care the error
  2156. //
  2157. // History: 06/03/2002 Rerkboos Created
  2158. //
  2159. // Notes: This is a call-back function for LoopUser() function.
  2160. //
  2161. //-----------------------------------------------------------------------------
  2162. HRESULT AnalyzeMiscProfilePathPerUser(
  2163. LPCTSTR lpUserName, // User name
  2164. LPCTSTR lpUserSid // User's SID
  2165. )
  2166. {
  2167. HRESULT hr;
  2168. BOOL bRet;
  2169. NET_API_STATUS nStatus;
  2170. LPUSER_INFO_3 lpusri3;
  2171. TCHAR szNewUserName[MAX_PATH];
  2172. TCHAR szNewProfilePath[MAX_PATH * 2];
  2173. TCHAR szNewEngProfilePath[MAX_PATH * 2];
  2174. LPTSTR lpNewEngProfilePath = NULL;
  2175. DWORD cchNewEngProfilePath;
  2176. DPF(APPmsg, TEXT("Enter AnalyzeMiscProfilePathPerUser:"));
  2177. // If lpUserName is built-in account, we will get the unlocalized name
  2178. // from INF file
  2179. hr = CheckNewBuiltInUserName(lpUserName,
  2180. szNewUserName,
  2181. ARRAYSIZE(szNewUserName));
  2182. if (SUCCEEDED(hr))
  2183. {
  2184. if (hr == S_FALSE)
  2185. {
  2186. // Username is not built-in account,
  2187. // we will not change the account name.
  2188. hr = StringCchCopy(szNewUserName,
  2189. ARRAYSIZE(szNewUserName),
  2190. lpUserName);
  2191. if (FAILED(hr))
  2192. {
  2193. goto EXIT;
  2194. }
  2195. }
  2196. // Compute a new unique profile directory for the new unlocalized name
  2197. // we don't want the new profile directory to duplicate.
  2198. bRet = ComputeLocalProfileName(lpUserName,
  2199. szNewUserName,
  2200. szNewProfilePath,
  2201. ARRAYSIZE(szNewProfilePath),
  2202. REG_SZ);
  2203. if (!bRet)
  2204. {
  2205. // This user does not have profile path set in the registry
  2206. // Assume it is %documents and settings%\user name
  2207. DWORD cchNewProfilePath = ARRAYSIZE(szNewProfilePath);
  2208. bRet = GetProfilesDirectory(szNewProfilePath,
  2209. &cchNewProfilePath);
  2210. if (bRet)
  2211. {
  2212. bRet = ConcatenatePaths(szNewProfilePath,
  2213. lpUserName,
  2214. ARRAYSIZE(szNewProfilePath));
  2215. if (bRet)
  2216. {
  2217. if (IsDirExisting(szNewProfilePath))
  2218. {
  2219. // %documents and settings%\user name dir alreay exists,
  2220. // cannot use this dir, we just ignore this user
  2221. hr = S_FALSE;
  2222. goto EXIT;
  2223. }
  2224. }
  2225. }
  2226. if (!bRet)
  2227. {
  2228. hr = E_FAIL;
  2229. goto EXIT;
  2230. }
  2231. }
  2232. // szNewProfilePath should be "%Loc_documents_and_settings%\NewUser"
  2233. // We have to fix it to "%Eng_documents_and_settings%\NewUser"
  2234. lpNewEngProfilePath = ReplaceLocStringInPath(szNewProfilePath, TRUE);
  2235. if (lpNewEngProfilePath == NULL)
  2236. {
  2237. // If Loc string and Eng string are the same,
  2238. // duplicate the old string to new string
  2239. hr = DuplicateString(&lpNewEngProfilePath,
  2240. &cchNewEngProfilePath,
  2241. szNewProfilePath);
  2242. if (FAILED(hr))
  2243. {
  2244. goto EXIT;
  2245. }
  2246. }
  2247. }
  2248. else
  2249. {
  2250. goto EXIT;
  2251. }
  2252. // Get current information of current user name,
  2253. // and we will add entries to CLMTDO.INF if the change is needed.
  2254. nStatus = NetUserGetInfo(NULL, lpUserName, 3, (LPBYTE *) &lpusri3);
  2255. if (nStatus == NERR_Success)
  2256. {
  2257. // Check the User's Profile path
  2258. hr = AddProfilePathItem(lpUserName,
  2259. lpUserSid,
  2260. lpusri3->usri3_profile,
  2261. lpNewEngProfilePath,
  2262. TYPE_USER_PROFILE_PATH);
  2263. hr = AddProfilePathItem(lpUserName,
  2264. lpUserSid,
  2265. lpusri3->usri3_script_path,
  2266. lpNewEngProfilePath,
  2267. TYPE_USER_SCRIPT_PATH);
  2268. hr = AddProfilePathItem(lpUserName,
  2269. lpUserSid,
  2270. lpusri3->usri3_home_dir,
  2271. lpNewEngProfilePath,
  2272. TYPE_USER_HOME_DIR);
  2273. NetApiBufferFree(lpusri3);
  2274. }
  2275. hr = AddTSProfilePathItem(lpUserName,
  2276. lpUserSid,
  2277. lpNewEngProfilePath,
  2278. WTSUserConfigInitialProgram);
  2279. hr = AddTSProfilePathItem(lpUserName,
  2280. lpUserSid,
  2281. lpNewEngProfilePath,
  2282. WTSUserConfigWorkingDirectory);
  2283. hr = AddTSProfilePathItem(lpUserName,
  2284. lpUserSid,
  2285. lpNewEngProfilePath,
  2286. WTSUserConfigTerminalServerProfilePath);
  2287. hr = AddTSProfilePathItem(lpUserName,
  2288. lpUserSid,
  2289. lpNewEngProfilePath,
  2290. WTSUserConfigTerminalServerHomeDir);
  2291. DPF(APPmsg, TEXT("Exit AnalyzeMiscProfilePathPerUser:"));
  2292. EXIT:
  2293. if (lpNewEngProfilePath != NULL)
  2294. {
  2295. MEMFREE(lpNewEngProfilePath);
  2296. }
  2297. return S_OK;
  2298. }
  2299. //-----------------------------------------------------------------------------
  2300. //
  2301. // Function: ResetMiscProfilePathPerUser
  2302. //
  2303. // Synopsis: Reset the profile paths for the user. The function will read
  2304. // the entries for each user from CLMTDO.INF. The entries were
  2305. // added by AnalyzeMiscProfilePathPerUser() function.
  2306. //
  2307. // Returns: S_OK if function succeeded
  2308. //
  2309. // History: 06/03/2002 Rerkboos Created
  2310. //
  2311. // Notes: This is a call-back function for LoopUser() function.
  2312. //
  2313. //-----------------------------------------------------------------------------
  2314. HRESULT ResetMiscProfilePathPerUser(
  2315. LPCTSTR lpUserName, // User Name
  2316. LPCTSTR lpUserSid // User's SID
  2317. )
  2318. {
  2319. HRESULT hr = S_OK;
  2320. BOOL bRet;
  2321. TCHAR szSectionName[MAX_PATH];
  2322. TCHAR szProfilePath[MAX_PATH];
  2323. LONG lLineCount;
  2324. LONG lLineIndex;
  2325. INT iType;
  2326. INFCONTEXT context;
  2327. DPF(APPmsg, TEXT("Enter ResetProfilePathPerUser:"));
  2328. hr = StringCchPrintf(szSectionName,
  2329. ARRAYSIZE(szSectionName),
  2330. TEXT("PROFILE.UPDATE.%s"),
  2331. lpUserSid);
  2332. if (FAILED(hr))
  2333. {
  2334. goto EXIT;
  2335. }
  2336. lLineCount = SetupGetLineCount(g_hInfDoItem, szSectionName);
  2337. for (lLineIndex = 0 ; lLineIndex < lLineCount ; lLineIndex++)
  2338. {
  2339. bRet = SetupGetLineByIndex(g_hInfDoItem,
  2340. szSectionName,
  2341. lLineIndex,
  2342. &context);
  2343. if (bRet)
  2344. {
  2345. bRet = SetupGetIntField(&context, 0, &iType)
  2346. && SetupGetStringField(&context,
  2347. 1,
  2348. szProfilePath,
  2349. ARRAYSIZE(szProfilePath),
  2350. NULL);
  2351. if (bRet)
  2352. {
  2353. switch (iType)
  2354. {
  2355. case TYPE_USER_PROFILE_PATH:
  2356. hr = SetUserNetworkProfilePath(lpUserName, szProfilePath);
  2357. break;
  2358. case TYPE_USER_SCRIPT_PATH:
  2359. hr = SetUserLogOnScriptPath(lpUserName, szProfilePath);
  2360. break;
  2361. case TYPE_USER_HOME_DIR:
  2362. hr = SetUserHomeDir(lpUserName, szProfilePath);
  2363. break;
  2364. case TYPE_TS_INIT_PROGRAM:
  2365. hr = SetTSUserPath(lpUserName,
  2366. szProfilePath,
  2367. WTSUserConfigInitialProgram);
  2368. break;
  2369. case TYPE_TS_WORKING_DIR:
  2370. hr = SetTSUserPath(lpUserName,
  2371. szProfilePath,
  2372. WTSUserConfigWorkingDirectory);
  2373. break;
  2374. case TYPE_TS_PROFILE_PATH:
  2375. hr = SetTSUserPath(lpUserName,
  2376. szProfilePath,
  2377. WTSUserConfigTerminalServerProfilePath);
  2378. break;
  2379. case TYPE_TS_HOME_DIR:
  2380. hr = SetTSUserPath(lpUserName,
  2381. szProfilePath,
  2382. WTSUserConfigTerminalServerHomeDir);
  2383. break;
  2384. }
  2385. }
  2386. }
  2387. if (!bRet)
  2388. {
  2389. hr = HRESULT_FROM_WIN32(GetLastError());
  2390. goto EXIT;
  2391. }
  2392. }
  2393. DPF(APPmsg, TEXT("Exit ResetProfilePathPerUser:"));
  2394. EXIT:
  2395. return hr;
  2396. }
  2397. //-----------------------------------------------------------------------------
  2398. //
  2399. // Function: CheckNewBuiltInUserName
  2400. //
  2401. // Synopsis: Check the user name with the built-in accounts listed in
  2402. // CLMT.INF. If the user name matches, the function will return
  2403. // the associaged English user name.
  2404. //
  2405. // Returns: S_OK if the user name is built-in account
  2406. // S_FALSE if the user name is not built-in account
  2407. // Otherwise, error occurred
  2408. //
  2409. // History: 06/03/2002 Rerkboos Created
  2410. //
  2411. // Notes: None.
  2412. //
  2413. //-----------------------------------------------------------------------------
  2414. HRESULT CheckNewBuiltInUserName(
  2415. LPCTSTR lpUserName, // Localized User name
  2416. LPTSTR lpNewUserName, // Buffer to store associated English User name
  2417. DWORD cchNewUserName // Size of the buffer (in TCHAR)
  2418. )
  2419. {
  2420. HRESULT hr = S_FALSE;
  2421. BOOL bRet;
  2422. LONG lLineCount;
  2423. LONG lLineIndex;
  2424. INT iType;
  2425. INFCONTEXT context;
  2426. TCHAR szOldUserName[MAX_PATH];
  2427. lLineCount = SetupGetLineCount(g_hInf, USERGRPSECTION);
  2428. for (lLineIndex = 0 ; lLineIndex < lLineCount ; lLineIndex++)
  2429. {
  2430. SetupGetLineByIndex(g_hInf, USERGRPSECTION, lLineIndex, &context);
  2431. bRet = SetupGetIntField(&context, 1, &iType);
  2432. if (iType == OP_USER)
  2433. {
  2434. bRet = SetupGetStringField(&context,
  2435. 2,
  2436. szOldUserName,
  2437. ARRAYSIZE(szOldUserName),
  2438. NULL);
  2439. if (bRet)
  2440. {
  2441. if (MyStrCmpI(szOldUserName, lpUserName) == LSTR_EQUAL)
  2442. {
  2443. bRet = SetupGetStringField(&context,
  2444. 3,
  2445. lpNewUserName,
  2446. cchNewUserName,
  2447. NULL);
  2448. if (bRet)
  2449. {
  2450. hr = S_OK;
  2451. goto EXIT;
  2452. }
  2453. }
  2454. }
  2455. if (!bRet)
  2456. {
  2457. hr = HRESULT_FROM_WIN32(GetLastError());
  2458. goto EXIT;
  2459. }
  2460. }
  2461. }
  2462. EXIT:
  2463. return hr;
  2464. }
  2465. //-----------------------------------------------------------------------------
  2466. //
  2467. // Function: AddProfilePathItem
  2468. //
  2469. // Synopsis: Add the user's path that needs to be changed to CLMTDO.INF
  2470. //
  2471. // Returns: S_OK if the path needs to be changed, and added to CLMTDO.INF
  2472. // S_FALSE if it's not neccessary to change the path
  2473. // otherwise, error occurred
  2474. //
  2475. // History: 06/03/2002 Rerkboos Created
  2476. //
  2477. // Notes: None.
  2478. //
  2479. //-----------------------------------------------------------------------------
  2480. HRESULT AddProfilePathItem(
  2481. LPCTSTR lpUserName, // User name
  2482. LPCTSTR lpUserSid, // User's SID
  2483. LPCTSTR lpOldLocProfilePath, // Current path
  2484. LPCTSTR lpNewEngProfilePath, // New English profile path
  2485. DWORD dwType)
  2486. {
  2487. HRESULT hr = S_FALSE;
  2488. BOOL bRet;
  2489. LPTSTR lpOldEngProfilePath;
  2490. TCHAR szFinalPath[MAX_PATH];
  2491. TCHAR szSectionName[MAX_PATH];
  2492. TCHAR szType[4];
  2493. TCHAR szExpandedOldLocPath[MAX_PATH];
  2494. TCHAR szExpandedNewEngPath[MAX_PATH];
  2495. if (lpUserName == NULL || *lpUserName == TEXT('\0')
  2496. || lpOldLocProfilePath == NULL || *lpOldLocProfilePath == TEXT('\0')
  2497. || lpNewEngProfilePath == NULL || *lpNewEngProfilePath == TEXT('\0'))
  2498. {
  2499. return S_FALSE;
  2500. }
  2501. ExpandEnvironmentStrings(lpOldLocProfilePath,
  2502. szExpandedOldLocPath,
  2503. ARRAYSIZE(szExpandedOldLocPath));
  2504. ExpandEnvironmentStrings(lpNewEngProfilePath,
  2505. szExpandedNewEngPath,
  2506. ARRAYSIZE(szExpandedNewEngPath));
  2507. if (IsPathLocal(szExpandedOldLocPath))
  2508. {
  2509. // szExpandedOldLocPath should be "%Loc_documents_and_settings%\OldUser"
  2510. // We have to fix it to "%Eng_documents_and_settings%\OldUser"
  2511. lpOldEngProfilePath = ReplaceLocStringInPath(szExpandedOldLocPath, TRUE);
  2512. if (lpOldEngProfilePath != NULL)
  2513. {
  2514. // Loc path is NOT the same as Eng path
  2515. hr = PreFixUserProfilePath(lpOldEngProfilePath,
  2516. szExpandedNewEngPath,
  2517. szFinalPath,
  2518. ARRAYSIZE(szFinalPath));
  2519. MEMFREE(lpOldEngProfilePath);
  2520. if (SUCCEEDED(hr))
  2521. {
  2522. hr = StringCchPrintf(szSectionName,
  2523. ARRAYSIZE(szSectionName),
  2524. TEXT("PROFILE.UPDATE.%s"),
  2525. lpUserSid);
  2526. if (SUCCEEDED(hr))
  2527. {
  2528. _ultot(dwType, szType, 10);
  2529. // Add entry to CLMTDO.INF
  2530. WritePrivateProfileString(szSectionName,
  2531. szType,
  2532. szFinalPath,
  2533. g_szToDoINFFileName);
  2534. }
  2535. }
  2536. }
  2537. }
  2538. return hr;
  2539. }
  2540. //-----------------------------------------------------------------------------
  2541. //
  2542. // Function: AddTSProfilePathItem
  2543. //
  2544. // Synopsis: Add the Terminal Services Realted user's path that needs to be
  2545. // changed to CLMTDO.INF
  2546. //
  2547. // Returns: S_OK if the path needs to be changed, and added to CLMTDO.INF
  2548. // S_FALSE if it's not neccessary to change the path
  2549. // otherwise, error occurred
  2550. //
  2551. // History: 06/03/2002 Rerkboos Created
  2552. //
  2553. // Notes: None.
  2554. //
  2555. //-----------------------------------------------------------------------------
  2556. HRESULT AddTSProfilePathItem(
  2557. LPCTSTR lpUserName, // User name
  2558. LPCTSTR lpUserSid, // User's SID
  2559. LPCTSTR lpNewEngProfilePath, // New English profile path
  2560. WTS_CONFIG_CLASS WTSConfigClass // TS Path config class
  2561. )
  2562. {
  2563. HRESULT hr = S_FALSE;
  2564. BOOL bRet;
  2565. LPTSTR lpTSDir;
  2566. DWORD cbTSDir;
  2567. DWORD dwType;
  2568. bRet = WTSQueryUserConfig(WTS_CURRENT_SERVER_NAME,
  2569. (LPTSTR) lpUserName,
  2570. WTSConfigClass,
  2571. &lpTSDir,
  2572. &cbTSDir);
  2573. if (bRet)
  2574. {
  2575. switch (WTSConfigClass)
  2576. {
  2577. case WTSUserConfigInitialProgram:
  2578. dwType = TYPE_TS_INIT_PROGRAM;
  2579. break;
  2580. case WTSUserConfigWorkingDirectory:
  2581. dwType = TYPE_TS_WORKING_DIR;
  2582. break;
  2583. case WTSUserConfigTerminalServerProfilePath:
  2584. dwType = TYPE_TS_PROFILE_PATH;
  2585. break;
  2586. case WTSUserConfigTerminalServerHomeDir:
  2587. dwType = TYPE_TS_HOME_DIR;
  2588. break;
  2589. }
  2590. hr = AddProfilePathItem(lpUserName,
  2591. lpUserSid,
  2592. lpTSDir,
  2593. lpNewEngProfilePath,
  2594. dwType);
  2595. WTSFreeMemory(lpTSDir);
  2596. }
  2597. return hr;
  2598. }