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.

1296 lines
30 KiB

  1. //*************************************************************
  2. // File name: delprof.c
  3. //
  4. // Description: Utility to delete user profiles
  5. //
  6. //
  7. // Microsoft Confidential
  8. // Copyright (c) Microsoft Corporation 1996
  9. // All rights reserved
  10. //
  11. //*************************************************************
  12. #include <windows.h>
  13. #include <tchar.h>
  14. #include <stdio.h>
  15. #include <locale.h>
  16. #include <strsafe.h>
  17. #include "delprof.h"
  18. #include "userenv.h"
  19. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  20. #define VALID_COMPUTER_NAME_LENGTH MAX_COMPUTERNAME_LENGTH + 3 // including \\ with Null terminator
  21. //
  22. // Globals
  23. //
  24. BOOL bQuiet;
  25. BOOL bIgnoreErrors;
  26. BOOL bPromptBeforeDelete;
  27. BOOL bLocalComputer = FALSE;
  28. TCHAR szComputerName[MAX_PATH];
  29. TCHAR szSystemRoot[2*MAX_PATH];
  30. TCHAR szSystemDrive[2*MAX_PATH];
  31. LONG lDays;
  32. HINSTANCE hInst;
  33. LPDELETEITEM lpDeleteList;
  34. LONG lCurrentDateInDays;
  35. //*************************************************************
  36. //
  37. // Usage()
  38. //
  39. // Purpose: prints the usage info
  40. //
  41. // Parameters: void
  42. //
  43. // Return: void
  44. //
  45. // Comments:
  46. //
  47. // History: Date Author Comment
  48. // 5/18/96 ericflo Created
  49. //
  50. //*************************************************************
  51. void Usage (void)
  52. {
  53. TCHAR szTemp[200];
  54. LoadString (hInst, IDS_USAGE1, szTemp, ARRAYSIZE(szTemp));
  55. _tprintf(szTemp);
  56. LoadString (hInst, IDS_USAGE2, szTemp, ARRAYSIZE(szTemp));
  57. _tprintf(szTemp);
  58. LoadString (hInst, IDS_USAGE3, szTemp, ARRAYSIZE(szTemp));
  59. _tprintf(szTemp);
  60. LoadString (hInst, IDS_USAGE4, szTemp, ARRAYSIZE(szTemp));
  61. _tprintf(szTemp);
  62. LoadString (hInst, IDS_USAGE5, szTemp, ARRAYSIZE(szTemp));
  63. _tprintf(szTemp);
  64. LoadString (hInst, IDS_USAGE6, szTemp, ARRAYSIZE(szTemp));
  65. _tprintf(szTemp);
  66. LoadString (hInst, IDS_USAGE7, szTemp, ARRAYSIZE(szTemp));
  67. _tprintf(szTemp);
  68. LoadString (hInst, IDS_USAGE8, szTemp, ARRAYSIZE(szTemp));
  69. _tprintf(szTemp);
  70. LoadString (hInst, IDS_USAGE9, szTemp, ARRAYSIZE(szTemp));
  71. _tprintf(szTemp);
  72. }
  73. //*************************************************************
  74. //
  75. // InitializeGlobals()
  76. //
  77. // Purpose: Initializes the global variables
  78. //
  79. // Parameters: void
  80. //
  81. // Return: void
  82. //
  83. // Comments:
  84. //
  85. // History: Date Author Comment
  86. // 5/18/96 ericflo Created
  87. //
  88. //*************************************************************
  89. void InitializeGlobals (void)
  90. {
  91. OSVERSIONINFO ver;
  92. SYSTEMTIME systime;
  93. //
  94. // Initialize global variables
  95. //
  96. bQuiet = FALSE;
  97. bIgnoreErrors = FALSE;
  98. bPromptBeforeDelete = FALSE;
  99. szComputerName[0] = TEXT('\0');
  100. lDays = 0;
  101. lpDeleteList = NULL;
  102. setlocale(LC_ALL,"");
  103. hInst = GetModuleHandle(TEXT("delprof.exe"));
  104. GetLocalTime (&systime);
  105. lCurrentDateInDays = gdate_dmytoday(systime.wYear, systime.wMonth, systime.wDay);
  106. }
  107. //*************************************************************
  108. //
  109. // CheckGlobals()
  110. //
  111. // Purpose: Checks the global variables
  112. //
  113. // Parameters: void
  114. //
  115. // Return: DWORD - ERROR_SUCCESS for success
  116. // win32 error code for failure
  117. //
  118. // Comments:
  119. //
  120. // History: Date Author Comment
  121. // 5/18/96 ericflo Created
  122. //
  123. //*************************************************************
  124. DWORD CheckGlobals (void)
  125. {
  126. DWORD dwSize;
  127. HRESULT hr;
  128. DWORD dwErr = ERROR_SUCCESS;
  129. TCHAR szTemp[MAX_PATH];
  130. //
  131. // If szComputerName is still NULL, fill in the computer name
  132. // we're running on.
  133. //
  134. if (szComputerName[0] == TEXT('\0')) {
  135. szComputerName[0] = TEXT('\\');
  136. szComputerName[1] = TEXT('\\');
  137. dwSize = ARRAYSIZE(szComputerName) - 2;
  138. if (!GetComputerName(szComputerName + 2, &dwSize)) {
  139. return GetLastError();
  140. }
  141. bLocalComputer = TRUE;
  142. } else {
  143. //
  144. // Make sure that the computer name starts with \\
  145. //
  146. if (szComputerName[0] != TEXT('\\')) {
  147. szTemp[0] = TEXT('\\');
  148. szTemp[1] = TEXT('\\');
  149. hr = StringCchCopy(szTemp + 2, ARRAYSIZE(szTemp) - 2, szComputerName);
  150. if (FAILED(hr))
  151. return HRESULT_CODE(hr);
  152. hr = StringCchCopy(szComputerName, ARRAYSIZE(szComputerName), szTemp);
  153. if (FAILED(hr))
  154. return HRESULT_CODE(hr);
  155. }
  156. }
  157. //
  158. // If the user has requested to run in Quiet mode,
  159. // then we turn off the prompt on every delete option.
  160. //
  161. if (bQuiet) {
  162. bPromptBeforeDelete = FALSE;
  163. }
  164. return ERROR_SUCCESS;
  165. }
  166. //*************************************************************
  167. //
  168. // ParseCommandLine()
  169. //
  170. // Purpose: Parses the command line
  171. //
  172. // Parameters: lpCommandLine - Command line
  173. //
  174. // Return: TRUE if successful
  175. // FALSE if an error occurs
  176. //
  177. // Comments:
  178. //
  179. // History: Date Author Comment
  180. // 5/18/96 ericflo Created
  181. //
  182. //*************************************************************
  183. BOOL ParseCommandLine (LPTSTR lpCommandLine)
  184. {
  185. LPTSTR lpTemp;
  186. DWORD cchTemp;
  187. TCHAR szDays[32];
  188. //
  189. // Check for NULL command line
  190. //
  191. if (!lpCommandLine || !*lpCommandLine)
  192. return TRUE;
  193. //
  194. // Find the executable name
  195. //
  196. while (*lpCommandLine && (_tcsncmp(lpCommandLine, TEXT("delprof"), 7) != 0)) {
  197. lpCommandLine++;
  198. }
  199. if (!*lpCommandLine) {
  200. return TRUE;
  201. }
  202. //
  203. // Find the first argument
  204. //
  205. while (*lpCommandLine && ((*lpCommandLine != TEXT(' ')) &&
  206. (*lpCommandLine != TEXT('/')) &&
  207. (*lpCommandLine != TEXT('-')))) {
  208. lpCommandLine++;
  209. }
  210. //
  211. // Skip white space
  212. //
  213. while (*lpCommandLine && (*lpCommandLine == TEXT(' '))) {
  214. lpCommandLine++;
  215. }
  216. if (!*lpCommandLine) {
  217. return TRUE;
  218. }
  219. //
  220. // We should be at the first argument now.
  221. //
  222. if ((*lpCommandLine != TEXT('/')) && (*lpCommandLine != TEXT('-'))) {
  223. Usage();
  224. return FALSE;
  225. }
  226. while (1) {
  227. //
  228. // Increment the pointer and branch to the correct argument.
  229. //
  230. lpCommandLine++;
  231. switch (*lpCommandLine) {
  232. case TEXT('?'):
  233. Usage();
  234. ExitProcess(0);
  235. break;
  236. case TEXT('Q'):
  237. case TEXT('q'):
  238. bQuiet = TRUE;
  239. lpCommandLine++;
  240. break;
  241. case TEXT('I'):
  242. case TEXT('i'):
  243. bIgnoreErrors = TRUE;
  244. lpCommandLine++;
  245. break;
  246. case TEXT('P'):
  247. case TEXT('p'):
  248. bPromptBeforeDelete = TRUE;
  249. lpCommandLine++;
  250. break;
  251. case TEXT('C'):
  252. case TEXT('c'):
  253. //
  254. // Find the colon
  255. //
  256. lpCommandLine++;
  257. if (*lpCommandLine != TEXT(':')) {
  258. Usage();
  259. return FALSE;
  260. }
  261. //
  262. // Find the first character
  263. //
  264. lpCommandLine++;
  265. if (!*lpCommandLine) {
  266. Usage();
  267. return FALSE;
  268. }
  269. //
  270. // Copy the computer name
  271. //
  272. cchTemp = 0;
  273. lpTemp = szComputerName;
  274. while (*lpCommandLine && (cchTemp < ARRAYSIZE(szComputerName) - 1) &&
  275. ((*lpCommandLine != TEXT(' ')) &&
  276. (*lpCommandLine != TEXT('/')))){
  277. *lpTemp++ = *lpCommandLine++;
  278. cchTemp++;
  279. }
  280. if (cchTemp > VALID_COMPUTER_NAME_LENGTH) {
  281. Usage();
  282. return FALSE;
  283. }
  284. *lpTemp = TEXT('\0');
  285. break;
  286. case TEXT('D'):
  287. case TEXT('d'):
  288. //
  289. // Find the colon
  290. //
  291. lpCommandLine++;
  292. if (*lpCommandLine != TEXT(':')) {
  293. Usage();
  294. return FALSE;
  295. }
  296. //
  297. // Find the first character
  298. //
  299. lpCommandLine++;
  300. if (!*lpCommandLine) {
  301. Usage();
  302. return FALSE;
  303. }
  304. //
  305. // Copy the number of days (in characters)
  306. //
  307. lpTemp = szDays;
  308. cchTemp = 0;
  309. while (*lpCommandLine && (cchTemp < ARRAYSIZE(szDays) - 1) &&
  310. ((*lpCommandLine != TEXT(' ')) &&
  311. (*lpCommandLine != TEXT('/')) &&
  312. (*lpCommandLine != TEXT('-')))) {
  313. *lpTemp++ = *lpCommandLine++;
  314. cchTemp++;
  315. }
  316. *lpTemp = TEXT('\0');
  317. //
  318. // Convert the days into a number
  319. //
  320. lDays = _ttol(szDays);
  321. break;
  322. default:
  323. Usage();
  324. return FALSE;
  325. }
  326. //
  327. // Skip white space
  328. //
  329. while (*lpCommandLine && (*lpCommandLine == TEXT(' '))) {
  330. lpCommandLine++;
  331. }
  332. if (!*lpCommandLine) {
  333. return TRUE;
  334. }
  335. //
  336. // We should be at the next argument now.
  337. //
  338. if ((*lpCommandLine != TEXT('/')) && (*lpCommandLine != TEXT('-'))) {
  339. Usage();
  340. return FALSE;
  341. }
  342. }
  343. return TRUE;
  344. }
  345. //*************************************************************
  346. //
  347. // Confirm()
  348. //
  349. // Purpose: Confirm the user really wants to delete the profiles
  350. //
  351. // Parameters: void
  352. //
  353. // Return: TRUE if we should continue
  354. // FALSE if not
  355. //
  356. // Comments:
  357. //
  358. // History: Date Author Comment
  359. // 5/18/96 ericflo Created
  360. //
  361. //*************************************************************
  362. BOOL Confirm ()
  363. {
  364. TCHAR szTemp[200];
  365. TCHAR tChar, tTemp;
  366. //
  367. // If we are prompting for every profile, then don't
  368. // give the general prompt.
  369. //
  370. if (bPromptBeforeDelete) {
  371. return TRUE;
  372. }
  373. //
  374. // If the user is requesting a specific day count,
  375. // give a more appropriate confirmation message.
  376. //
  377. if (lDays > 0) {
  378. LoadString (hInst, IDS_CONFIRMDAYS, szTemp, ARRAYSIZE(szTemp));
  379. _tprintf (szTemp, szComputerName, lDays);
  380. } else {
  381. LoadString (hInst, IDS_CONFIRM, szTemp, ARRAYSIZE(szTemp));
  382. _tprintf (szTemp, szComputerName);
  383. }
  384. tChar = _gettchar();
  385. tTemp = tChar;
  386. while (tTemp != TEXT('\n')) {
  387. tTemp = _gettchar();
  388. }
  389. if ((tChar == TEXT('Y')) || (tChar == TEXT('y'))) {
  390. return TRUE;
  391. }
  392. //
  393. // If the user didn't press Y/y, then we bail.
  394. //
  395. LoadString (hInst, IDS_NO, szTemp, ARRAYSIZE(szTemp));
  396. _tprintf (szTemp);
  397. return FALSE;
  398. }
  399. //*************************************************************
  400. //
  401. // PrintLastError()
  402. //
  403. // Purpose: Displays the last error string to the user
  404. //
  405. // Parameters: lError - error code
  406. //
  407. // Return: void
  408. //
  409. // Comments:
  410. //
  411. // History: Date Author Comment
  412. // 5/18/96 ericflo Created
  413. //
  414. //*************************************************************
  415. void PrintLastError(LONG lError)
  416. {
  417. TCHAR szMessage[MAX_PATH];
  418. FormatMessage(
  419. FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
  420. NULL,
  421. lError,
  422. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  423. szMessage,
  424. ARRAYSIZE(szMessage),
  425. NULL);
  426. _tprintf (szMessage);
  427. }
  428. //*************************************************************
  429. //
  430. // AddNode()
  431. //
  432. // Purpose: Adds a new node to the link list
  433. //
  434. // Parameters: szSubKey - SubKey
  435. // szProfilePath - Profile Path (or NULL)
  436. // bDir - Directory or file
  437. //
  438. // Return: TRUE if successful
  439. // FALSE if an error occurs
  440. //
  441. // Comments: szProfilePath can be NULL. In this case, we
  442. // are just removing the bogus registry entry.
  443. //
  444. // History: Date Author Comment
  445. // 5/18/96 ericflo Created
  446. //
  447. //*************************************************************
  448. BOOL AddNode (LPTSTR szSubKey, LPTSTR szProfilePath, BOOL bDir)
  449. {
  450. LPDELETEITEM lpItem, lpTemp;
  451. UINT uAlloc = 0;
  452. DWORD cchSubKeyWithNull = 0, cchProfilePathWithNull = 0;
  453. HRESULT hr;
  454. //
  455. // Create a new node
  456. //
  457. cchSubKeyWithNull = lstrlen(szSubKey) + 1;
  458. uAlloc = sizeof(DELETEITEM) + cchSubKeyWithNull * sizeof(TCHAR);
  459. if (szProfilePath) {
  460. cchProfilePathWithNull = lstrlen(szProfilePath) + 1;
  461. uAlloc += cchProfilePathWithNull * sizeof(TCHAR);
  462. }
  463. lpItem = LocalAlloc (LPTR, uAlloc);
  464. if (!lpItem) {
  465. return FALSE;
  466. }
  467. lpItem->lpSubKey = (LPTSTR)((LPBYTE)lpItem + sizeof(DELETEITEM));
  468. hr = StringCchCopy(lpItem->lpSubKey, cchSubKeyWithNull, szSubKey);
  469. if (FAILED(hr)) {
  470. LocalFree(lpItem);
  471. return FALSE;
  472. }
  473. if (szProfilePath) {
  474. lpItem->lpProfilePath = lpItem->lpSubKey + lstrlen(szSubKey) + 1;
  475. hr = StringCchCopy(lpItem->lpProfilePath, cchProfilePathWithNull, szProfilePath);
  476. if (FAILED(hr)) {
  477. LocalFree(lpItem);
  478. return FALSE;
  479. }
  480. } else {
  481. lpItem->lpProfilePath = NULL;
  482. }
  483. lpItem->bDir = bDir;
  484. //
  485. // Add this node to the global lpItemList
  486. //
  487. if (lpDeleteList) {
  488. lpTemp = lpDeleteList;
  489. while (lpTemp->pNext) {
  490. lpTemp = lpTemp->pNext;
  491. }
  492. lpTemp->pNext = lpItem;
  493. } else {
  494. lpDeleteList = lpItem;
  495. }
  496. return TRUE;
  497. }
  498. //*************************************************************
  499. //
  500. // GetProfileDateInDays()
  501. //
  502. // Purpose: Gets the profile date in days.
  503. //
  504. // Parameters: szProfilePath - Profile path
  505. // bDir - Directory or file
  506. //
  507. // Return: age in days.
  508. //
  509. // Comments:
  510. //
  511. // History: Date Author Comment
  512. // 5/18/96 ericflo Created
  513. //
  514. //*************************************************************
  515. LONG GetProfileDateInDays(LPTSTR szProfilePath, BOOL bDir)
  516. {
  517. TCHAR szTemp[MAX_PATH];
  518. HANDLE hFile;
  519. WIN32_FIND_DATA fd;
  520. LONG days;
  521. SYSTEMTIME systime;
  522. FILETIME ft;
  523. HRESULT hr;
  524. if (bDir) {
  525. //
  526. // Tack on ntuser.* to find the registry hive.
  527. //
  528. hr = StringCchCopy(szTemp, ARRAYSIZE(szTemp), szProfilePath);
  529. if (FAILED(hr))
  530. return lCurrentDateInDays;
  531. hr = StringCchCat(szTemp, ARRAYSIZE(szTemp), TEXT("\\ntuser.*"));
  532. if (FAILED(hr))
  533. return lCurrentDateInDays;
  534. hFile = FindFirstFile (szTemp, &fd);
  535. } else {
  536. //
  537. // szProfilePath points to a file.
  538. //
  539. hFile = FindFirstFile (szProfilePath, &fd);
  540. }
  541. if (hFile != INVALID_HANDLE_VALUE) {
  542. FindClose (hFile);
  543. FileTimeToLocalFileTime (&fd.ftLastWriteTime, &ft);
  544. FileTimeToSystemTime (&ft, &systime);
  545. days = gdate_dmytoday(systime.wYear, systime.wMonth, systime.wDay);
  546. } else {
  547. days = lCurrentDateInDays;
  548. }
  549. return days;
  550. }
  551. //*************************************************************
  552. //
  553. // CheckProfile()
  554. //
  555. // Purpose: Checks if the given profile should be deleted.
  556. // If so, it is added to the list.
  557. //
  558. // Parameters: hKeyLM - Local Machine key
  559. // hKeyUsers - HKEY_USERS key
  560. // lpSid - Sid string (key name)
  561. //
  562. // Return: TRUE if successful
  563. // FALSE if not
  564. //
  565. // Comments:
  566. //
  567. // History: Date Author Comment
  568. // 5/18/96 ericflo Created
  569. //
  570. //*************************************************************
  571. BOOL CheckProfile (HKEY hKeyLM, HKEY hKeyUsers, LPTSTR lpSid)
  572. {
  573. LONG lResult;
  574. HKEY hkey = NULL;
  575. TCHAR szSubKey[MAX_PATH];
  576. DWORD dwSize, dwType;
  577. TCHAR szTemp[MAX_PATH];
  578. TCHAR szProfilePath[MAX_PATH];
  579. TCHAR szError[200];
  580. DWORD dwAttribs;
  581. BOOL bDir;
  582. LONG lProfileDateInDays;
  583. HRESULT hr;
  584. //
  585. // Check if the profile is in use
  586. //
  587. lResult = RegOpenKeyEx (hKeyUsers, lpSid, 0, KEY_READ, &hkey);
  588. if (lResult == ERROR_SUCCESS) {
  589. RegCloseKey (hkey);
  590. return TRUE;
  591. }
  592. //
  593. // Open the profile information
  594. //
  595. hr = StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey),
  596. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%s"),
  597. lpSid);
  598. if (FAILED(hr)) {
  599. PrintLastError(HRESULT_CODE(hr));
  600. return FALSE;
  601. }
  602. lResult = RegOpenKeyEx (hKeyLM,
  603. szSubKey,
  604. 0,
  605. KEY_READ,
  606. &hkey);
  607. if (lResult != ERROR_SUCCESS) {
  608. LoadString (hInst, IDS_FAILEDOPENPROFILE, szError, ARRAYSIZE(szError));
  609. _tprintf(szError, lpSid);
  610. PrintLastError(lResult);
  611. return FALSE;
  612. }
  613. //
  614. // Query for the ProfileImagePath
  615. //
  616. dwSize = MAX_PATH * sizeof(TCHAR);
  617. lResult = RegQueryValueEx (hkey,
  618. TEXT("ProfileImagePath"),
  619. NULL,
  620. &dwType,
  621. (LPBYTE)szTemp,
  622. &dwSize);
  623. RegCloseKey(hkey);
  624. hkey = NULL;
  625. if (lResult != ERROR_SUCCESS) {
  626. LoadString (hInst, IDS_FAILEDPATHQUERY, szError, ARRAYSIZE(szError));
  627. _tprintf(szError, lpSid);
  628. PrintLastError(lResult);
  629. return FALSE;
  630. }
  631. //
  632. // Expand the path.
  633. //
  634. if (_tcsnicmp(TEXT("%SystemRoot%"), szTemp, 12) == 0) {
  635. hr = StringCchPrintf(szProfilePath, ARRAYSIZE(szProfilePath), TEXT("%s\\%s"), szSystemRoot, szTemp+13);
  636. if (FAILED(hr)) {
  637. PrintLastError(HRESULT_CODE(hr));
  638. return FALSE;
  639. }
  640. }
  641. else if (_tcsnicmp(TEXT("%SystemDrive%"), szTemp, 13) == 0) {
  642. hr = StringCchPrintf(szProfilePath, ARRAYSIZE(szProfilePath), TEXT("%s\\%s"), szSystemDrive, szTemp+14);
  643. if (FAILED(hr)) {
  644. PrintLastError(HRESULT_CODE(hr));
  645. return FALSE;
  646. }
  647. }
  648. else if (NULL == _tcschr(szTemp, TEXT('%')) && !bLocalComputer) {
  649. if (TEXT(':') == szTemp[1])
  650. szTemp[1] = TEXT('$');
  651. hr = StringCchPrintf(szProfilePath, ARRAYSIZE(szProfilePath), TEXT("%s\\%s"), szComputerName, szTemp);
  652. if (FAILED(hr)) {
  653. PrintLastError(HRESULT_CODE(hr));
  654. return FALSE;
  655. }
  656. }
  657. else {
  658. LoadString (hInst, IDS_SKIPPROFILE, szError, ARRAYSIZE(szError));
  659. _tprintf(szError, szTemp);
  660. return TRUE;
  661. }
  662. //
  663. // Is this a directory or a file?
  664. //
  665. dwAttribs = GetFileAttributes (szProfilePath);
  666. if (dwAttribs == -1) {
  667. AddNode (szSubKey, NULL, FALSE);
  668. return TRUE;
  669. }
  670. bDir = (dwAttribs & FILE_ATTRIBUTE_DIRECTORY) ? TRUE : FALSE;
  671. //
  672. // Check Time/Date stamp. If the profile date is older
  673. // than the amount specified, add it to the delete list.
  674. //
  675. lProfileDateInDays = GetProfileDateInDays(szProfilePath, bDir);
  676. if (lCurrentDateInDays >= lProfileDateInDays) {
  677. if ((lCurrentDateInDays - lProfileDateInDays) >= lDays) {
  678. AddNode (szSubKey, szProfilePath, bDir);
  679. }
  680. }
  681. return TRUE;
  682. }
  683. //*************************************************************
  684. //
  685. // DelProfiles()
  686. //
  687. // Purpose: Deletes the user profiles
  688. //
  689. // Parameters: void
  690. //
  691. // Return: TRUE if successful
  692. // FALSE if an error occurs
  693. //
  694. // Comments:
  695. //
  696. // History: Date Author Comment
  697. // 5/18/96 ericflo Created
  698. //
  699. //*************************************************************
  700. BOOL DelProfiles(void)
  701. {
  702. HKEY hKeyLM = NULL, hKeyUsers = NULL, hKeyProfiles = NULL;
  703. HKEY hKeyCurrentVersion = NULL;
  704. LONG lResult;
  705. BOOL bResult = FALSE, bTemp;
  706. TCHAR szError[200];
  707. DWORD dwIndex = 0, dwNameSize;
  708. DWORD dwBufferSize;
  709. TCHAR szName[MAX_PATH];
  710. TCHAR szTemp[MAX_PATH];
  711. TCHAR tChar, tTemp;
  712. FILETIME ft;
  713. LPDELETEITEM lpTemp;
  714. LPTSTR pSid, lpEnd;
  715. DWORD lProfileKeyLen;
  716. HRESULT hr;
  717. lProfileKeyLen = lstrlen(TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"))+1;
  718. //
  719. // Open the registry
  720. //
  721. lResult = RegConnectRegistry(szComputerName, HKEY_LOCAL_MACHINE, &hKeyLM);
  722. if (lResult != ERROR_SUCCESS) {
  723. PrintLastError(lResult);
  724. goto Exit;
  725. }
  726. lResult = RegConnectRegistry(szComputerName, HKEY_USERS, &hKeyUsers);
  727. if (lResult != ERROR_SUCCESS) {
  728. PrintLastError(lResult);
  729. goto Exit;
  730. }
  731. //
  732. // Get the value of %SystemRoot% and %SystemDrive% relative to the computer
  733. //
  734. lResult = RegOpenKeyEx(hKeyLM,
  735. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion"),
  736. 0,
  737. KEY_READ,
  738. &hKeyCurrentVersion);
  739. if (lResult != ERROR_SUCCESS) {
  740. PrintLastError(lResult);
  741. goto Exit;
  742. }
  743. dwBufferSize = sizeof(szTemp);
  744. lResult = RegQueryValueEx(hKeyCurrentVersion,
  745. TEXT("SystemRoot"),
  746. NULL,
  747. NULL,
  748. (BYTE *) szTemp,
  749. &dwBufferSize);
  750. if (lResult != ERROR_SUCCESS) {
  751. PrintLastError(lResult);
  752. goto Exit;
  753. }
  754. if (!bLocalComputer) {
  755. szTemp[1] = TEXT('$');
  756. hr = StringCchCopy(szSystemRoot, ARRAYSIZE(szSystemRoot), szComputerName);
  757. if (FAILED(hr)) {
  758. PrintLastError(HRESULT_CODE(hr));
  759. goto Exit;
  760. }
  761. hr = StringCchCat(szSystemRoot, ARRAYSIZE(szSystemRoot), TEXT("\\"));
  762. if (FAILED(hr)) {
  763. PrintLastError(HRESULT_CODE(hr));
  764. goto Exit;
  765. }
  766. hr = StringCchCat(szSystemRoot, ARRAYSIZE(szSystemRoot), szTemp);
  767. if (FAILED(hr)) {
  768. PrintLastError(HRESULT_CODE(hr));
  769. goto Exit;
  770. }
  771. hr = StringCchCopy(szSystemDrive, ARRAYSIZE(szSystemDrive), szComputerName);
  772. if (FAILED(hr)) {
  773. PrintLastError(HRESULT_CODE(hr));
  774. goto Exit;
  775. }
  776. hr = StringCchCat(szSystemDrive, ARRAYSIZE(szSystemDrive), TEXT("\\"));
  777. if (FAILED(hr)) {
  778. PrintLastError(HRESULT_CODE(hr));
  779. goto Exit;
  780. }
  781. hr = StringCchCatN(szSystemDrive, ARRAYSIZE(szSystemDrive), szTemp, 2);
  782. if (FAILED(hr)) {
  783. PrintLastError(HRESULT_CODE(hr));
  784. goto Exit;
  785. }
  786. }
  787. else {
  788. szSystemDrive[0] = TEXT('\0');
  789. hr = StringCchCatN(szSystemDrive, ARRAYSIZE(szSystemDrive), szTemp, 2);
  790. if (FAILED(hr)) {
  791. PrintLastError(HRESULT_CODE(hr));
  792. goto Exit;
  793. }
  794. hr = StringCchCopy(szSystemRoot, ARRAYSIZE(szSystemRoot), szTemp);
  795. if (FAILED(hr)) {
  796. PrintLastError(HRESULT_CODE(hr));
  797. goto Exit;
  798. }
  799. }
  800. //
  801. // Open the ProfileList key
  802. //
  803. lResult = RegOpenKeyEx (hKeyLM,
  804. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"),
  805. 0,
  806. KEY_ALL_ACCESS,
  807. &hKeyProfiles);
  808. if (lResult != ERROR_SUCCESS) {
  809. LoadString (hInst, IDS_FAILEDPROFILELIST, szError, ARRAYSIZE(szError));
  810. _tprintf(szError);
  811. PrintLastError(lResult);
  812. goto Exit;
  813. }
  814. //
  815. // Enumerate the profiles
  816. //
  817. dwNameSize = ARRAYSIZE(szName);
  818. lResult = RegEnumKeyEx(hKeyProfiles,
  819. dwIndex,
  820. szName,
  821. &dwNameSize,
  822. NULL,
  823. NULL,
  824. NULL,
  825. &ft);
  826. while (lResult == ERROR_SUCCESS) {
  827. //
  828. // Hand the profile info off to CheckProfile
  829. // to determine if the profile should be deleted or not.
  830. //
  831. if (!CheckProfile (hKeyLM, hKeyUsers, szName)) {
  832. if (!bIgnoreErrors) {
  833. goto Exit;
  834. }
  835. }
  836. //
  837. // Reset for the next loop
  838. //
  839. dwIndex++;
  840. dwNameSize = ARRAYSIZE(szName);
  841. lResult = RegEnumKeyEx(hKeyProfiles,
  842. dwIndex,
  843. szName,
  844. &dwNameSize,
  845. NULL,
  846. NULL,
  847. NULL,
  848. &ft);
  849. }
  850. //
  851. // Check for errors
  852. //
  853. if (lResult != ERROR_NO_MORE_ITEMS) {
  854. LoadString (hInst, IDS_FAILEDENUM, szError, ARRAYSIZE(szError));
  855. _tprintf(szError);
  856. PrintLastError(lResult);
  857. goto Exit;
  858. }
  859. //
  860. // Remove profiles
  861. //
  862. lpTemp = lpDeleteList;
  863. while (lpTemp) {
  864. if (lpTemp->lpProfilePath) {
  865. //
  866. // Prompt before deleting the profile (if approp).
  867. //
  868. if (bPromptBeforeDelete) {
  869. while (1) {
  870. LoadString (hInst, IDS_DELETEPROMPT, szError, ARRAYSIZE(szError));
  871. _tprintf (szError, lpTemp->lpProfilePath);
  872. tChar = _gettchar();
  873. tTemp = tChar;
  874. while (tTemp != TEXT('\n')) {
  875. tTemp = _gettchar();
  876. }
  877. if ((tChar == TEXT('N')) || (tChar == TEXT('n'))) {
  878. goto LoopAgain;
  879. }
  880. if ((tChar == TEXT('A')) || (tChar == TEXT('a'))) {
  881. bPromptBeforeDelete = FALSE;
  882. break;
  883. }
  884. if ((tChar == TEXT('Y')) || (tChar == TEXT('y'))) {
  885. break;
  886. }
  887. }
  888. }
  889. //
  890. // Delete the profile
  891. //
  892. LoadString (hInst, IDS_DELETING, szError, ARRAYSIZE(szError));
  893. _tprintf (szError, lpTemp->lpProfilePath);
  894. pSid = lpTemp->lpSubKey+lProfileKeyLen;
  895. bTemp = DeleteProfile(pSid, lpTemp->lpProfilePath, ((bLocalComputer)? NULL:szComputerName));
  896. if (bTemp) {
  897. LoadString (hInst, IDS_SUCCESS, szError, ARRAYSIZE(szError));
  898. _tprintf (szError, lpTemp->lpProfilePath);
  899. } else {
  900. LoadString (hInst, IDS_FAILED, szError, ARRAYSIZE(szError));
  901. _tprintf (szError, lpTemp->lpProfilePath);
  902. PrintLastError(GetLastError());
  903. }
  904. } else {
  905. //
  906. // If there isn't a profile path, then we are just
  907. // cleaning up the bogus registry entry.
  908. //
  909. bTemp = TRUE;
  910. //
  911. // Clean up the registry.
  912. //
  913. RegDeleteKey (hKeyLM, lpTemp->lpSubKey);
  914. }
  915. //
  916. // Did the clean up fail?
  917. //
  918. if (!bTemp) {
  919. if (!bIgnoreErrors) {
  920. goto Exit;
  921. }
  922. }
  923. LoopAgain:
  924. lpTemp = lpTemp->pNext;
  925. }
  926. //
  927. // Success
  928. //
  929. bResult = TRUE;
  930. Exit:
  931. if (hKeyCurrentVersion)
  932. RegCloseKey(hKeyCurrentVersion);
  933. if (hKeyProfiles)
  934. RegCloseKey(hKeyProfiles);
  935. if (hKeyLM)
  936. RegCloseKey(hKeyLM);
  937. if (hKeyUsers)
  938. RegCloseKey(hKeyUsers);
  939. if (lpDeleteList) {
  940. do {
  941. lpTemp = lpDeleteList->pNext;
  942. LocalFree (lpDeleteList);
  943. lpDeleteList = lpTemp;
  944. } while (lpDeleteList);
  945. }
  946. return bResult;
  947. }
  948. //*************************************************************
  949. //
  950. // main()
  951. //
  952. // Purpose: main entry point
  953. //
  954. // Parameters: argc - number of arguments
  955. // argv - arguments
  956. //
  957. // Return: 0 if successful
  958. // 1 if an error occurs
  959. //
  960. // Comments:
  961. //
  962. // History: Date Author Comment
  963. // 5/18/96 ericflo Created
  964. //
  965. //*************************************************************
  966. int __cdecl main( int argc, char *argv[])
  967. {
  968. DWORD dwErr;
  969. //
  970. // Initialize the globals
  971. //
  972. InitializeGlobals();
  973. //
  974. // Parse the command line
  975. //
  976. if (!ParseCommandLine(GetCommandLine())) {
  977. return 1;
  978. }
  979. //
  980. // Check the globals variables
  981. //
  982. dwErr = CheckGlobals();
  983. if (ERROR_SUCCESS != dwErr) {
  984. PrintLastError(dwErr);
  985. return 1;
  986. }
  987. //
  988. // Confirmation
  989. //
  990. if (!bQuiet) {
  991. if (!Confirm()) {
  992. return 1;
  993. }
  994. }
  995. //
  996. // Remove the profiles
  997. //
  998. if (!DelProfiles()) {
  999. return 1;
  1000. }
  1001. return 0;
  1002. }