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

2841 lines
60 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. namefix.c
  5. Abstract:
  6. This module generates memdb entries for names that are to be used on Windows
  7. NT. All names are validated, and incompatible names are placed in the
  8. NewNames memdb category.
  9. Names are organized into groups; within a group, each name must be unique,
  10. but across groups, duplicate names are allowed. For example, the name
  11. group "UserNames" holds all user names, and each user name must be unique.
  12. The user name can be the same as the computer name, because the computer
  13. name is stored in the "ComputerName" group.
  14. The code here is extendable for other types of name collisions. To add
  15. support for other types of names, simply add the group name to the
  16. NAME_GROUP_LIST macro expansion below, then implement three functions:
  17. pEnumGroupName
  18. pValidateGroupName
  19. pRecommendGroupName
  20. You'll replace GroupName in the function names above with the name of your
  21. actual group.
  22. The code in this module should be the only place where names are validated
  23. on the Win9x side.
  24. Author:
  25. Jim Schmidt (jimschm) 24-Dec-1997
  26. Revision History:
  27. jimschm 21-Jan-1998 Commented macro expansion list, added
  28. g_DisableDomainChecks capability
  29. --*/
  30. #include "pch.h"
  31. #include "cmn9xp.h"
  32. #include <validc.h> // nt\private\inc
  33. #define S_ILLEGAL_CHARS ILLEGAL_NAME_CHARS_STR TEXT("*")
  34. #define DBG_NAMEFIX "NameFix"
  35. #define MIN_UNLEN 20
  36. //
  37. // TEST_ALL_INCOMPATIBLE will force all names to be considered incompatible
  38. // TEST_MANGLE_NAMES will force names to be invalid
  39. //
  40. //#define TEST_ALL_INCOMPATIBLE
  41. //#define TEST_MANGLE_NAMES
  42. /*++
  43. Macro Expansion List Description:
  44. NAME_GROUP_LIST lists each name category, such as computer name, domain name,
  45. user name and so on. The macro expansion list automatically generates
  46. three function prototypes for each name category. Also, the message ID is
  47. used as the category identifier by external callers.
  48. Line Syntax:
  49. DEFMAC(GroupName, Id)
  50. Arguments:
  51. GroupName - Specifies the type of name. Must be a valid C function name.
  52. The macro expansion list will generate prototypes for:
  53. pEnum<GroupName>
  54. pValidate<GroupName>
  55. pRecommend<GroupName>
  56. where, of course, <GroupName> is replaced by the text in the
  57. macro declaration line.
  58. All three functions must be implemented in this source file.
  59. Id - Specifies the message ID giving the display name of the name group.
  60. The name group is displayed in the list box that the user sees when
  61. they are alerted there are some incompatible names on their machine.
  62. Id is also used to uniquely identify a name group in some of the
  63. routines below.
  64. Variables Generated From List:
  65. g_NameGroupRoutines
  66. --*/
  67. #define NAME_GROUP_LIST \
  68. DEFMAC(ComputerDomain, MSG_COMPUTERDOMAIN_CATEGORY) \
  69. DEFMAC(Workgroup, MSG_WORKGROUP_CATEGORY) \
  70. DEFMAC(UserName, MSG_USERNAME_CATEGORY) \
  71. DEFMAC(ComputerName, MSG_COMPUTERNAME_CATEGORY) \
  72. //
  73. // Macro expansion declarations
  74. //
  75. #define MAX_NAME 2048
  76. typedef struct {
  77. //
  78. // The NAME_ENUM structure is passed uninitialized to pEnumGroupName
  79. // function. The same structure is passed unchanged to subsequent
  80. // calls to pEnumGroupName. Each enum function declares its
  81. // params in this struct.
  82. //
  83. union {
  84. struct {
  85. //
  86. // pEnumUser
  87. //
  88. USERENUM UserEnum;
  89. };
  90. };
  91. //
  92. // All enumeration routines must fill in the following if they
  93. // return TRUE:
  94. //
  95. TCHAR Name[MAX_NAME];
  96. } NAME_ENUM, *PNAME_ENUM;
  97. typedef struct {
  98. PCTSTR GroupName;
  99. TCHAR AuthenticatingAgent[MAX_COMPUTER_NAME];
  100. BOOL FromUserInterface;
  101. UINT FailureMsg;
  102. BOOL DomainLogonEnabled;
  103. } NAME_GROUP_CONTEXT, *PNAME_GROUP_CONTEXT;
  104. typedef BOOL (ENUM_NAME_PROTOTYPE)(PNAME_GROUP_CONTEXT Context, PNAME_ENUM EnumPtr, BOOL First);
  105. typedef ENUM_NAME_PROTOTYPE * ENUM_NAME_FN;
  106. typedef BOOL (VALIDATE_NAME_PROTOTYPE)(PNAME_GROUP_CONTEXT Context, PCTSTR NameCandidate);
  107. typedef VALIDATE_NAME_PROTOTYPE * VALIDATE_NAME_FN;
  108. typedef VOID (RECOMMEND_NAME_PROTOTYPE)(PNAME_GROUP_CONTEXT Context, PCTSTR InvalidName, PTSTR RecommendedNameBuf);
  109. typedef RECOMMEND_NAME_PROTOTYPE * RECOMMEND_NAME_FN;
  110. typedef struct {
  111. UINT NameId;
  112. PCTSTR GroupName;
  113. ENUM_NAME_FN Enum;
  114. VALIDATE_NAME_FN Validate;
  115. RECOMMEND_NAME_FN Recommend;
  116. NAME_GROUP_CONTEXT Context;
  117. } NAME_GROUP_ROUTINES, *PNAME_GROUP_ROUTINES;
  118. //
  119. // Automatic arrays and prototypes
  120. //
  121. // The prototoypes
  122. #define DEFMAC(x,id) ENUM_NAME_PROTOTYPE pEnum##x;
  123. NAME_GROUP_LIST
  124. #undef DEFMAC
  125. #define DEFMAC(x,id) VALIDATE_NAME_PROTOTYPE pValidate##x;
  126. NAME_GROUP_LIST
  127. #undef DEFMAC
  128. #define DEFMAC(x,id) RECOMMEND_NAME_PROTOTYPE pRecommend##x;
  129. NAME_GROUP_LIST
  130. #undef DEFMAC
  131. // The array of functions
  132. #define DEFMAC(x,id) {id, TEXT(#x), pEnum##x, pValidate##x, pRecommend##x},
  133. NAME_GROUP_ROUTINES g_NameGroupRoutines[] = {
  134. NAME_GROUP_LIST /* , */
  135. {0, NULL, NULL, NULL, NULL, NULL}
  136. };
  137. //
  138. // Local prototypes
  139. //
  140. BOOL
  141. pDoesNameExistInMemDb (
  142. IN PNAME_GROUP_CONTEXT Context,
  143. IN PCTSTR UserName
  144. );
  145. //
  146. // Implementation
  147. //
  148. PNAME_GROUP_ROUTINES
  149. pGetNameGroupById (
  150. IN UINT MessageId
  151. )
  152. /*++
  153. Routine Description:
  154. pGetNameGroupById finds a group by searching the list for a message ID. The
  155. message ID is the unique identifier for the group.
  156. Arguments:
  157. MessageId - Specifies the unique ID of the group to find
  158. Return Value:
  159. A pointer to the group struct, or NULL if one was not found.
  160. --*/
  161. {
  162. INT i;
  163. for (i = 0 ; g_NameGroupRoutines[i].GroupName ; i++) {
  164. if (g_NameGroupRoutines[i].NameId == MessageId) {
  165. return &g_NameGroupRoutines[i];
  166. }
  167. }
  168. return NULL;
  169. }
  170. PNAME_GROUP_CONTEXT
  171. pGetNameGroupContextById (
  172. IN UINT MessageId
  173. )
  174. /*++
  175. Routine Description:
  176. pGetNameGroupById finds a group by searching the list for a message ID. The
  177. message ID is the unique identifier for the group. The return value is
  178. the context structure used by the group.
  179. Arguments:
  180. MessageId - Specifies the unique ID of the group to find
  181. Return Value:
  182. A pointer to the group's context struct, or NULL if one was not found.
  183. --*/
  184. {
  185. INT i;
  186. for (i = 0 ; g_NameGroupRoutines[i].GroupName ; i++) {
  187. if (g_NameGroupRoutines[i].NameId == MessageId) {
  188. return &g_NameGroupRoutines[i].Context;
  189. }
  190. }
  191. return NULL;
  192. }
  193. BOOL
  194. pEnumComputerName (
  195. IN PNAME_GROUP_CONTEXT Context,
  196. IN OUT PNAME_ENUM EnumPtr,
  197. IN BOOL First
  198. )
  199. /*++
  200. Routine Description:
  201. pEnumComputerName obtains the computer name and returns it
  202. in the EnumPtr struct. If no name is assigned to the computer,
  203. an empty string is returned.
  204. Arguments:
  205. Context - Unused (holds context about name group)
  206. EnumPtr - Receives the computer name
  207. First - Specifies TRUE on the first call to pEnumComputerName,
  208. or FALSE on subseqeuent calls to pEnumComputerName.
  209. Return Value:
  210. If First is TRUE, returns TRUE if a name is enumerated, or FALSE
  211. if the name is not valid.
  212. If First is FALSE, always returns FALSE.
  213. --*/
  214. {
  215. DWORD Size;
  216. if (!First) {
  217. return FALSE;
  218. }
  219. //
  220. // Get the computer name
  221. //
  222. Size = sizeof (EnumPtr->Name) / sizeof (EnumPtr->Name[0]);
  223. if (!GetComputerName (EnumPtr->Name, &Size)) {
  224. EnumPtr->Name[0] = 0;
  225. }
  226. return TRUE;
  227. }
  228. BOOL
  229. pEnumUserName (
  230. IN PNAME_GROUP_CONTEXT Context,
  231. IN OUT PNAME_ENUM EnumPtr,
  232. IN BOOL First
  233. )
  234. /*++
  235. Routine Description:
  236. pEnumUserName enumerates all users on the machine via the EnumFirstUser/
  237. EnumNextUser APIs. It does not enumerate the fixed names.
  238. Like the other enumeration routines, this routine is called until it
  239. returns FALSE, so that all resources are cleaned up correctly.
  240. Arguments:
  241. Context - Unused (holds context about name group)
  242. EnumPtr - Specifies the current enumeration state. Receives the enumerated
  243. user name.
  244. First - Specifies TRUE on the first call to pEnumUserName,
  245. or FALSE on subseqeuent calls to pEnumUserName.
  246. Return Value:
  247. TRUE if a user was enumerated, or FALSE if all users were enumerated.
  248. --*/
  249. {
  250. //
  251. // Enumerate the next user
  252. //
  253. if (First) {
  254. if (!EnumFirstUser (&EnumPtr->UserEnum, ENUMUSER_DO_NOT_MAP_HIVE)) {
  255. LOG ((LOG_ERROR, "No users to enumerate"));
  256. return FALSE;
  257. }
  258. } else {
  259. if (!EnumNextUser (&EnumPtr->UserEnum)) {
  260. return FALSE;
  261. }
  262. }
  263. //
  264. // Special case -- ignore default user
  265. //
  266. while (*EnumPtr->UserEnum.UserName == 0) {
  267. if (!EnumNextUser (&EnumPtr->UserEnum)) {
  268. return FALSE;
  269. }
  270. }
  271. //
  272. // Copy user name to name buffer
  273. //
  274. StringCopy (EnumPtr->Name, EnumPtr->UserEnum.UserName);
  275. return TRUE;
  276. }
  277. BOOL
  278. pEnumWorkgroup (
  279. IN PNAME_GROUP_CONTEXT Context,
  280. IN OUT PNAME_ENUM EnumPtr,
  281. IN BOOL First
  282. )
  283. /*++
  284. Routine Description:
  285. pEnumWorkgroup obtains the workgroup name and returns it
  286. in the EnumPtr struct. If the VNETSUP support is not
  287. installed, or the workgroup name is empty, this routine
  288. returns FALSE.
  289. Arguments:
  290. Context - Receives AuthenticatingAgent value
  291. EnumPtr - Receives the computer domain name
  292. First - Specifies TRUE on the first call to pEnumWorkgroup,
  293. or FALSE on subseqeuent calls to pEnumWorkgroup.
  294. Return Value:
  295. If First is TRUE, returns TRUE if a name is enumerated, or FALSE
  296. if the name is not valid.
  297. If First is FALSE, always returns FALSE.
  298. --*/
  299. {
  300. HKEY VnetsupKey;
  301. PCTSTR StrData;
  302. if (!First) {
  303. return FALSE;
  304. }
  305. EnumPtr->Name[0] = 0;
  306. //
  307. // Obtain the workgroup name into EnumPtr->Name
  308. //
  309. VnetsupKey = OpenRegKeyStr (S_VNETSUP);
  310. if (VnetsupKey) {
  311. StrData = GetRegValueString (VnetsupKey, S_WORKGROUP);
  312. if (StrData) {
  313. _tcssafecpy (EnumPtr->Name, StrData, MAX_COMPUTER_NAME);
  314. MemFree (g_hHeap, 0, StrData);
  315. }
  316. ELSE_DEBUGMSG ((DBG_WARNING, "pEnumWorkgroup: Workgroup value does not exist"));
  317. CloseRegKey (VnetsupKey);
  318. }
  319. ELSE_DEBUGMSG ((DBG_WARNING, "pEnumWorkgroup: VNETSUP key does not exist"));
  320. return EnumPtr->Name[0] != 0;
  321. }
  322. BOOL
  323. pEnumComputerDomain (
  324. IN PNAME_GROUP_CONTEXT Context,
  325. IN OUT PNAME_ENUM EnumPtr,
  326. IN BOOL First
  327. )
  328. /*++
  329. Routine Description:
  330. pEnumComputerDomain obtains the workgroup name and returns it in the EnumPtr
  331. struct. If the MS Networking client is not installed, this routine returns
  332. FALSE.
  333. This routine also obtains the AuthenticatingAgent value, and stores it in
  334. the Context structure for use by pRecommendComputerDomain.
  335. Arguments:
  336. Context - Receives AuthenticatingAgent value
  337. EnumPtr - Receives the computer domain name
  338. First - Specifies TRUE on the first call to pEnumComputerDomain,
  339. or FALSE on subseqeuent calls to pEnumComputerDomain.
  340. Return Value:
  341. If First is TRUE, returns TRUE if a name is enumerated, or FALSE
  342. if the name is not valid.
  343. If First is FALSE, always returns FALSE.
  344. --*/
  345. {
  346. HKEY Key;
  347. HKEY NetLogonKey;
  348. HKEY VnetsupKey;
  349. PBYTE Data;
  350. PCTSTR StrData;
  351. BOOL b = TRUE;
  352. if (!First) {
  353. return FALSE;
  354. }
  355. EnumPtr->Name[0] = 0;
  356. Context->DomainLogonEnabled = FALSE;
  357. //
  358. // Is the MS Networking client installed?
  359. //
  360. Key = OpenRegKeyStr (S_MSNP32);
  361. if (!Key) {
  362. //
  363. // MS Networking client is not installed. Return FALSE
  364. // because any Win9x workgroup name will work with NT.
  365. //
  366. DEBUGMSG ((DBG_NAMEFIX, "pEnumComputerDomain: MS Networking client is not installed."));
  367. return FALSE;
  368. }
  369. __try {
  370. //
  371. // Determine if the domain logon is enabled
  372. //
  373. NetLogonKey = OpenRegKeyStr (S_LOGON_KEY);
  374. if (NetLogonKey) {
  375. Data = (PBYTE) GetRegValueBinary (NetLogonKey, S_LM_LOGON);
  376. if (Data) {
  377. if (*Data) {
  378. Context->DomainLogonEnabled = TRUE;
  379. }
  380. MemFree (g_hHeap, 0, Data);
  381. }
  382. CloseRegKey (NetLogonKey);
  383. }
  384. //
  385. // If no domain logon is enabled, return FALSE, because
  386. // any Win9x workgroup name will work with NT.
  387. //
  388. if (!Context->DomainLogonEnabled) {
  389. DEBUGMSG ((DBG_NAMEFIX, "pEnumComputerDomain: Domain logon is not enabled."));
  390. b = FALSE;
  391. __leave;
  392. }
  393. //
  394. // Obtain the workgroup name into EnumPtr->Name; we will try
  395. // to use this as the NT computer domain.
  396. //
  397. VnetsupKey = OpenRegKeyStr (S_VNETSUP);
  398. if (VnetsupKey) {
  399. StrData = GetRegValueString (VnetsupKey, S_WORKGROUP);
  400. if (StrData) {
  401. _tcssafecpy (EnumPtr->Name, StrData, MAX_COMPUTER_NAME);
  402. MemFree (g_hHeap, 0, StrData);
  403. }
  404. ELSE_DEBUGMSG ((DBG_WARNING, "pEnumComputerDomain: Workgroup value does not exist"));
  405. CloseRegKey (VnetsupKey);
  406. }
  407. ELSE_DEBUGMSG ((DBG_WARNING, "pEnumComputerDomain: VNETSUP key does not exist"));
  408. //
  409. // Obtain the AuthenticatingAgent value from Key and stick it in
  410. // Context->AuthenticatingAgent
  411. //
  412. StrData = GetRegValueString (Key, S_AUTHENTICATING_AGENT);
  413. if (StrData) {
  414. //
  415. // Copy AuthenticatingAgent to enum struct
  416. //
  417. _tcssafecpy (Context->AuthenticatingAgent, StrData, MAX_COMPUTER_NAME);
  418. MemFree (g_hHeap, 0, StrData);
  419. } else {
  420. Context->AuthenticatingAgent[0] = 0;
  421. LOG ((LOG_ERROR,"Domain Logon enabled, but AuthenticatingAgent value is missing"));
  422. }
  423. }
  424. __finally {
  425. CloseRegKey (Key);
  426. }
  427. return b;
  428. }
  429. BOOL
  430. pValidateNetName (
  431. OUT PNAME_GROUP_CONTEXT Context, OPTIONAL
  432. IN PCTSTR NameCandidate,
  433. IN BOOL SpacesAllowed,
  434. IN BOOL DotSpaceCheck,
  435. IN UINT MaxLength,
  436. OUT PCSTR *OffendingChar OPTIONAL
  437. )
  438. /*++
  439. Routine Description:
  440. pValidateNetName performs a check to see if the specified name is valid on
  441. NT 5.
  442. Arguments:
  443. Context - Receives the error message ID, if any error occurred.
  444. NameCandidate - Specifies the name to validate.
  445. SpacesAllowed - Specifies TRUE if spaces are allowed in the name, or FALSE
  446. if not.
  447. MaxLength - Specifies the max characters that can be in the name.
  448. DotSpaceCheck - Specifies TRUE if the name cannot consist only of a dot and
  449. a space, or FALSE if it can.
  450. OffendingChar - Receives the pointer to the character that caused the
  451. problem, or NULL if no error or the error was caused by
  452. something other than a character set mismatch or length test.
  453. Return Value:
  454. TRUE if the name is valid, or FALSE if it is not.
  455. --*/
  456. {
  457. PCTSTR p;
  458. PCTSTR LastNonSpaceChar;
  459. CHARTYPE ch;
  460. BOOL allDigits;
  461. if (OffendingChar) {
  462. *OffendingChar = NULL;
  463. }
  464. //
  465. // Minimum length test
  466. //
  467. if (!NameCandidate[0]) {
  468. if (Context) {
  469. Context->FailureMsg = MSG_INVALID_EMPTY_NAME_POPUP;
  470. }
  471. return FALSE;
  472. }
  473. //
  474. // Maximum length test
  475. //
  476. if (CharCount (NameCandidate) > MaxLength) {
  477. if (Context) {
  478. Context->FailureMsg = MSG_INVALID_COMPUTERNAME_LENGTH_POPUP;
  479. }
  480. if (OffendingChar) {
  481. *OffendingChar = TcharCountToPointer (NameCandidate, MaxLength);
  482. }
  483. return FALSE;
  484. }
  485. //
  486. // No leading spaces allowed
  487. //
  488. if (_tcsnextc (NameCandidate) == TEXT(' ')) {
  489. if (Context) {
  490. Context->FailureMsg = MSG_INVALID_COMPUTERNAME_CHAR_POPUP;
  491. }
  492. if (OffendingChar) {
  493. *OffendingChar = NameCandidate;
  494. }
  495. return FALSE;
  496. }
  497. //
  498. // No invalid characters
  499. //
  500. ch = ' ';
  501. LastNonSpaceChar = NULL;
  502. allDigits = TRUE;
  503. for (p = NameCandidate ; *p ; p = _tcsinc (p)) {
  504. ch = _tcsnextc (p);
  505. if (_tcschr (S_ILLEGAL_CHARS, ch) != NULL ||
  506. (ch == TEXT(' ') && !SpacesAllowed)
  507. ) {
  508. if (OffendingChar) {
  509. *OffendingChar = p;
  510. }
  511. if (Context) {
  512. Context->FailureMsg = MSG_INVALID_COMPUTERNAME_CHAR_POPUP;
  513. }
  514. return FALSE;
  515. }
  516. if (ch != TEXT('.') && ch != TEXT(' ')) {
  517. DotSpaceCheck = FALSE;
  518. }
  519. if (ch != TEXT(' ')) {
  520. LastNonSpaceChar = p;
  521. }
  522. if (allDigits) {
  523. if (ch < TEXT('0') || ch > TEXT('9')) {
  524. allDigits = FALSE;
  525. }
  526. }
  527. }
  528. if (allDigits) {
  529. if (OffendingChar) {
  530. *OffendingChar = NameCandidate;
  531. }
  532. if (Context) {
  533. Context->FailureMsg = MSG_INVALID_COMPUTERNAME_CHAR_POPUP;
  534. }
  535. return FALSE;
  536. }
  537. //
  538. // No trailing dot
  539. //
  540. if (ch == TEXT('.')) {
  541. MYASSERT (LastNonSpaceChar);
  542. if (OffendingChar) {
  543. *OffendingChar = LastNonSpaceChar;
  544. }
  545. if (Context) {
  546. Context->FailureMsg = MSG_INVALID_COMPUTERNAME_CHAR_POPUP;
  547. }
  548. return FALSE;
  549. }
  550. //
  551. // No trailing space
  552. //
  553. if (ch == TEXT(' ')) {
  554. MYASSERT (LastNonSpaceChar);
  555. if (OffendingChar) {
  556. *OffendingChar = _tcsinc (LastNonSpaceChar);
  557. }
  558. if (Context) {
  559. Context->FailureMsg = MSG_INVALID_COMPUTERNAME_CHAR_POPUP;
  560. }
  561. return FALSE;
  562. }
  563. //
  564. // Dot-space only check
  565. //
  566. if (DotSpaceCheck) {
  567. if (OffendingChar) {
  568. *OffendingChar = NameCandidate;
  569. }
  570. if (Context) {
  571. Context->FailureMsg = MSG_INVALID_USERNAME_SPACEDOT_POPUP;
  572. }
  573. return FALSE;
  574. }
  575. return TRUE;
  576. }
  577. BOOL
  578. ValidateDomainNameChars (
  579. IN PCTSTR NameCandidate
  580. )
  581. {
  582. return pValidateNetName (
  583. NULL,
  584. NameCandidate,
  585. FALSE,
  586. FALSE,
  587. min (MAX_SERVER_NAME, DNLEN),
  588. NULL
  589. );
  590. }
  591. BOOL
  592. ValidateUserNameChars (
  593. IN PCTSTR NameCandidate
  594. )
  595. {
  596. return pValidateNetName (
  597. NULL,
  598. NameCandidate,
  599. TRUE,
  600. TRUE,
  601. min (MAX_USER_NAME, MIN_UNLEN),
  602. NULL
  603. );
  604. }
  605. BOOL
  606. pValidateComputerName (
  607. IN PNAME_GROUP_CONTEXT Context,
  608. IN PCTSTR NameCandidate
  609. )
  610. /*++
  611. Routine Description:
  612. pValidateComputerName makes sure the specified name is not
  613. empty, is not longer than 15 characters, and consists only
  614. of characters legal for a computer name. Also, if the name
  615. collides with a user name, then the computer name is invalid.
  616. Arguments:
  617. Context - Unused (holds context about name group)
  618. NameCandidate - Specifies name to validate
  619. Return Value:
  620. TRUE if the name is valid, FALSE otherwise.
  621. --*/
  622. {
  623. BOOL b;
  624. //PNAME_GROUP_CONTEXT UserContext;
  625. //UserContext = pGetNameGroupContextById (MSG_USERNAME_CATEGORY);
  626. //if (pDoesNameExistInMemDb (UserContext, NameCandidate)) {
  627. // return FALSE;
  628. //}
  629. b = pValidateNetName (
  630. Context,
  631. NameCandidate,
  632. FALSE,
  633. FALSE,
  634. MAX_COMPUTER_NAME,
  635. NULL
  636. );
  637. return b;
  638. }
  639. BOOL
  640. pValidateWorkgroup (
  641. IN PNAME_GROUP_CONTEXT Context,
  642. IN PCTSTR NameCandidate
  643. )
  644. /*++
  645. Routine Description:
  646. pValidateWorkgroup makes sure the specified name is not
  647. empty, is not longer than 15 characters, and consists only
  648. of characters legal for a computer name.
  649. If domain logon is enabled, this routine always returns
  650. TRUE.
  651. Arguments:
  652. Context - Unused (holds context about name group)
  653. NameCandidate - Specifies name to validate
  654. Return Value:
  655. TRUE if the name is valid, FALSE otherwise.
  656. --*/
  657. {
  658. PNAME_GROUP_CONTEXT DomainContext;
  659. //
  660. // Return TRUE if domain is enabled
  661. //
  662. DomainContext = pGetNameGroupContextById (MSG_COMPUTERDOMAIN_CATEGORY);
  663. if (DomainContext && DomainContext->DomainLogonEnabled) {
  664. return TRUE;
  665. }
  666. //
  667. // A workgroup name is a domain name, but spaces are allowed.
  668. //
  669. return pValidateNetName (Context, NameCandidate, TRUE, FALSE, DNLEN, NULL);
  670. }
  671. BOOL
  672. pValidateUserName (
  673. IN PNAME_GROUP_CONTEXT Context,
  674. IN PCTSTR NameCandidate
  675. )
  676. /*++
  677. Routine Description:
  678. pValidateUserName makes sure the specified name is not empty,
  679. is not longer than 20 characters, consists only of characters
  680. legal for a user name, and does not exist in memdb's NewName
  681. or InUseName categories.
  682. Arguments:
  683. Context - Specifies context info for the UserName name group,
  684. used for memdb operations.
  685. NameCandidate - Specifies name to validate
  686. Return Value:
  687. TRUE if the name is valid, FALSE otherwise.
  688. --*/
  689. {
  690. BOOL b;
  691. //
  692. // Validate name
  693. //
  694. b = pValidateNetName (Context, NameCandidate, TRUE, TRUE, min (MAX_USER_NAME, MIN_UNLEN), NULL);
  695. if (!b && Context->FailureMsg == MSG_INVALID_COMPUTERNAME_LENGTH_POPUP) {
  696. Context->FailureMsg = MSG_INVALID_USERNAME_LENGTH_POPUP;
  697. }
  698. if (!b) {
  699. return FALSE;
  700. }
  701. //
  702. // Check for existence in memdb
  703. //
  704. if (pDoesNameExistInMemDb (Context, NameCandidate)) {
  705. Context->FailureMsg = MSG_INVALID_USERNAME_DUPLICATE_POPUP;
  706. return FALSE;
  707. }
  708. return TRUE;
  709. }
  710. BOOL
  711. pValidateComputerDomain (
  712. IN PNAME_GROUP_CONTEXT Context,
  713. IN PCTSTR NameCandidate
  714. )
  715. /*++
  716. Routine Description:
  717. pValidateComputerDomain performs the same validatation that
  718. pValidateComputerName performs. Therefore, it simply calls
  719. pValidateComputerName.
  720. If the name comes from the registry, and not the user interface, then we
  721. check to see if the workgroup name actually refers to a domain controller.
  722. If it does, the name is returned as valid; otherwise, the name is returned
  723. as invalid, even though it may consist of valid characters.
  724. If the name comes from the user interface, we assume the UI code will do
  725. the validation to see if the name is an actual server. This allows the UI
  726. to override the API, because the API may not work properly on all networks.
  727. Arguments:
  728. Context - Specifies context of the ComputerDomain name group. In particular,
  729. the FromUserInterface member tells us to ignore validation of the
  730. domain name via the NetServerGetInfo API.
  731. NameCandidate - Specifies domain name to validate
  732. Return Value:
  733. TRUE if the domain name is legal, or FALSE if it is not.
  734. --*/
  735. {
  736. TCHAR NewComputerName[MAX_COMPUTER_NAME];
  737. if (!pValidateNetName (Context, NameCandidate, FALSE, FALSE, DNLEN, NULL)) {
  738. return FALSE;
  739. }
  740. if (!Context->FromUserInterface) {
  741. if (GetUpgradeComputerName (NewComputerName)) {
  742. // 1 == account was found, 0 == account does not exist, -1 == no response
  743. if (1 != DoesComputerAccountExistOnDomain (
  744. NameCandidate,
  745. NewComputerName,
  746. TRUE
  747. )) {
  748. return FALSE;
  749. }
  750. }
  751. }
  752. return TRUE;
  753. }
  754. BOOL
  755. pCleanUpNetName (
  756. IN PNAME_GROUP_CONTEXT Context,
  757. IN OUT PTSTR Name,
  758. IN UINT NameType
  759. )
  760. /*++
  761. Routine Description:
  762. pCleanUpNetName eliminates all characters that are invalid from the
  763. specified name.
  764. NOTE: We could add some smarts here, such as translation of
  765. spaces to dashes, and so on.
  766. Arguments:
  767. Context - Unused; passed along to pValidateComputerName.
  768. Name - Specifies the name containing potentially invalid characters.
  769. Receives the name with all invalid characters removed.
  770. NameType - Specifies the type of name to clean up
  771. Return Value:
  772. TRUE if the resulting name is valid, or FALSE if the resulting
  773. name is still not valid.
  774. --*/
  775. {
  776. TCHAR TempBuf[MAX_COMPUTER_NAME];
  777. PTSTR p;
  778. PTSTR q;
  779. UINT Len;
  780. BOOL b;
  781. //
  782. // Delete all the invalid characters
  783. //
  784. _tcssafecpy (TempBuf, Name, MAX_COMPUTER_NAME);
  785. for (;;) {
  786. p = NULL;
  787. b = FALSE;
  788. switch (NameType) {
  789. case MSG_COMPUTERNAME_CATEGORY:
  790. b = pValidateNetName (Context, TempBuf, TRUE, FALSE, MAX_COMPUTER_NAME, &p);
  791. break;
  792. case MSG_WORKGROUP_CATEGORY:
  793. b = pValidateNetName (Context, TempBuf, TRUE, FALSE, DNLEN, &p);
  794. break;
  795. case MSG_COMPUTERDOMAIN_CATEGORY:
  796. b = pValidateNetName (Context, TempBuf, FALSE, FALSE, DNLEN, &p);
  797. break;
  798. case MSG_USERNAME_CATEGORY:
  799. b = pValidateNetName (Context, TempBuf, TRUE, TRUE, MIN_UNLEN, &p);
  800. break;
  801. }
  802. if (b || !p) {
  803. break;
  804. }
  805. q = _tcsinc (p);
  806. Len = ByteCount (q) + sizeof (TCHAR);
  807. MoveMemory (p, q, Len);
  808. }
  809. if (b) {
  810. //
  811. // Do not allow names that contain a lot of invalid characters
  812. //
  813. if (CharCount (Name) - 3 > CharCount (TempBuf)) {
  814. b = FALSE;
  815. }
  816. }
  817. if (!b) {
  818. // Empty out recommended name
  819. *Name = 0;
  820. }
  821. if (b) {
  822. StringCopy (Name, TempBuf);
  823. switch (NameType) {
  824. case MSG_COMPUTERNAME_CATEGORY:
  825. b = pValidateComputerName (Context, Name);
  826. break;
  827. case MSG_WORKGROUP_CATEGORY:
  828. b = pValidateWorkgroup (Context, Name);
  829. break;
  830. case MSG_COMPUTERDOMAIN_CATEGORY:
  831. b = pValidateComputerDomain (Context, Name);
  832. break;
  833. case MSG_USERNAME_CATEGORY:
  834. b = pValidateUserName (Context, Name);
  835. break;
  836. }
  837. }
  838. return b;
  839. }
  840. VOID
  841. pRecommendComputerName (
  842. IN PNAME_GROUP_CONTEXT Context,
  843. IN PCTSTR InvalidName,
  844. OUT PTSTR RecommendedName
  845. )
  846. /*++
  847. Routine Description:
  848. pRecommendComputerName obtains the current user's name and
  849. returns it for use as a computer name. If the user's name
  850. has characters that cannot be used in a computer name,
  851. the invalid characters are removed. If the name is still
  852. invalid, then a static string is returned.
  853. Arguments:
  854. Context - Unused (holds context about name group)
  855. InvalidName - Specifies the current invalid name, or an empty
  856. string if no name exists.
  857. RecommendedName - Receives the recommended name.
  858. Return Value:
  859. none
  860. --*/
  861. {
  862. DWORD Size;
  863. PCTSTR p;
  864. PCTSTR ArgArray[1];
  865. //
  866. // Try to clean up the invalid name
  867. //
  868. if (*InvalidName) {
  869. _tcssafecpy (RecommendedName, InvalidName, MAX_COMPUTER_NAME);
  870. if (pCleanUpNetName (Context, RecommendedName, MSG_COMPUTERNAME_CATEGORY)) {
  871. return;
  872. }
  873. }
  874. //
  875. // Generate a suggestion from the user name
  876. //
  877. Size = MAX_COMPUTER_NAME;
  878. if (!GetUserName (RecommendedName, &Size)) {
  879. *RecommendedName = 0;
  880. } else {
  881. CharUpper (RecommendedName);
  882. ArgArray[0] = RecommendedName;
  883. p = ParseMessageID (MSG_COMPUTER_REPLACEMENT_NAME, ArgArray);
  884. MYASSERT (p);
  885. if (p) {
  886. _tcssafecpy (RecommendedName, p, MAX_COMPUTER_NAME);
  887. FreeStringResource (p);
  888. }
  889. ELSE_DEBUGMSG ((DBG_ERROR, "Failed to parse message resource for MSG_COMPUTER_REPLACEMENT_NAME. Check localization."));
  890. }
  891. //
  892. // Try to clean up invalid computer name chars in user name
  893. //
  894. if (pCleanUpNetName (Context, RecommendedName, MSG_COMPUTERNAME_CATEGORY)) {
  895. return;
  896. }
  897. //
  898. // All else has failed; obtain static computer name string
  899. //
  900. p = GetStringResource (MSG_RECOMMENDED_COMPUTER_NAME);
  901. MYASSERT (p);
  902. if (p) {
  903. StringCopy (RecommendedName, p);
  904. FreeStringResource (p);
  905. }
  906. ELSE_DEBUGMSG ((DBG_ERROR, "Failed to parse message resource for MSG_RECOMMENDED_COMPUTER_NAME. Check localization."));
  907. }
  908. VOID
  909. pRecommendWorkgroup (
  910. IN PNAME_GROUP_CONTEXT Context,
  911. IN PCTSTR InvalidName,
  912. OUT PTSTR RecommendedName
  913. )
  914. /*++
  915. Routine Description:
  916. pRecommendWorkgroupName tries to clean up the invalid workgroup name, and
  917. only if necessary recommends the name Workgroup.
  918. Arguments:
  919. Context - Unused (holds context about name group)
  920. InvalidName - Specifies the current invalid name, or an empty
  921. string if no name exists.
  922. RecommendedName - Receives the recommended name.
  923. Return Value:
  924. none
  925. --*/
  926. {
  927. PCTSTR p;
  928. //
  929. // Try to clean up the invalid name
  930. //
  931. if (*InvalidName) {
  932. _tcssafecpy (RecommendedName, InvalidName, MAX_COMPUTER_NAME);
  933. if (pCleanUpNetName (Context, RecommendedName, MSG_WORKGROUP_CATEGORY)) {
  934. return;
  935. }
  936. }
  937. //
  938. // All else has failed; obtain static workgroup string
  939. //
  940. p = GetStringResource (MSG_RECOMMENDED_WORKGROUP_NAME);
  941. MYASSERT (p);
  942. StringCopy (RecommendedName, p);
  943. FreeStringResource (p);
  944. }
  945. VOID
  946. pRecommendUserName (
  947. IN PNAME_GROUP_CONTEXT Context,
  948. IN PCTSTR InvalidName,
  949. OUT PTSTR RecommendedName
  950. )
  951. /*++
  952. Routine Description:
  953. pRecommendUserName tries to clean up the specified invalid
  954. user name. If that fails, this routine generates a
  955. generic user name (such as Windows User). If the generic
  956. name is not valid, numbers are appended until a unique,
  957. valid name is found.
  958. Arguments:
  959. Context - Specifies settings for the UserName name group context,
  960. including the group name itself. This context is used
  961. in memdb operations to validate the name.
  962. InvalidName - Specifies the current invalid name, or an empty
  963. string if no name exists.
  964. RecommendedName - Receives the recommended name.
  965. Return Value:
  966. none
  967. --*/
  968. {
  969. PCTSTR p;
  970. UINT Sequencer;
  971. //
  972. // Attempt to clean out invalid characters from the user
  973. // name.
  974. //
  975. _tcssafecpy (RecommendedName, InvalidName, MAX_USER_NAME);
  976. if (pCleanUpNetName (Context, RecommendedName, MSG_USERNAME_CATEGORY)) {
  977. return;
  978. }
  979. //
  980. // If there are some characters left, and there is room for
  981. // a sequencer, just add the sequencer.
  982. //
  983. if (*RecommendedName) {
  984. p = DuplicateText (RecommendedName);
  985. MYASSERT (p);
  986. for (Sequencer = 1 ; Sequencer < 10 ; Sequencer++) {
  987. wsprintf (RecommendedName, TEXT("%s-%u"), p, Sequencer);
  988. if (pValidateUserName (Context, RecommendedName)) {
  989. break;
  990. }
  991. }
  992. FreeText (p);
  993. if (Sequencer < 10) {
  994. return;
  995. }
  996. }
  997. //
  998. // Obtain a generic name
  999. //
  1000. p = GetStringResource (MSG_RECOMMENDED_USER_NAME);
  1001. MYASSERT (p);
  1002. if (p) {
  1003. __try {
  1004. if (pValidateUserName (Context, p)) {
  1005. StringCopy (RecommendedName, p);
  1006. } else {
  1007. for (Sequencer = 2 ; Sequencer < 100000 ; Sequencer++) {
  1008. wsprintf (RecommendedName, TEXT("%s %u"), p, Sequencer);
  1009. if (pValidateUserName (Context, RecommendedName)) {
  1010. break;
  1011. }
  1012. }
  1013. if (Sequencer == 100000) {
  1014. LOG ((LOG_ERROR, "Sequencer hit %u", Sequencer));
  1015. }
  1016. }
  1017. }
  1018. __finally {
  1019. FreeStringResource (p);
  1020. }
  1021. }
  1022. ELSE_DEBUGMSG ((DBG_ERROR, "Could not retrieve string resource MSG_RECOMMENDED_USER_NAME. Check localization."));
  1023. }
  1024. VOID
  1025. pRecommendComputerDomain (
  1026. IN PNAME_GROUP_CONTEXT Context,
  1027. IN PCTSTR InvalidName,
  1028. OUT PTSTR RecommendedName
  1029. )
  1030. /*++
  1031. Routine Description:
  1032. pRecommendComputerDomain returns the value of AuthenticatingAgent
  1033. stored in the Context structure by pEnumComputerDomain.
  1034. Arguments:
  1035. Context - Specifies the name group context structure, which holds
  1036. the computer domain found by pEnumComputerDomain.
  1037. InvalidName - Specifies the current invalid name, or an empty
  1038. string if no name exists.
  1039. RecommendedName - Receives the recommended name.
  1040. Return Value:
  1041. none
  1042. --*/
  1043. {
  1044. StringCopy (RecommendedName, Context->AuthenticatingAgent);
  1045. }
  1046. BOOL
  1047. ValidateName (
  1048. IN HWND ParentWnd, OPTIONAL
  1049. IN PCTSTR NameGroup,
  1050. IN PCTSTR NameCandidate
  1051. )
  1052. /*++
  1053. Routine Description:
  1054. ValidateName is called by the UI to perform validation on the
  1055. specified name.
  1056. Arguments:
  1057. ParentWnd - Specifies the handle used for popups that tell the user
  1058. what is wrong with the name they entered. If NULL, no
  1059. UI is generated.
  1060. NameGroup - Specifies the name group, a static string that defines
  1061. what characters are legal for the name.
  1062. NameCandidate - Specifies the name to validate
  1063. Return Value:
  1064. TRUE if the name is valid, or FALSE if it is not valid.
  1065. --*/
  1066. {
  1067. INT i;
  1068. BOOL b;
  1069. //
  1070. // Scan the g_NameGroupRoutines array for the name grup
  1071. //
  1072. for (i = 0 ; g_NameGroupRoutines[i].GroupName ; i++) {
  1073. if (StringIMatch (g_NameGroupRoutines[i].GroupName, NameGroup)) {
  1074. break;
  1075. }
  1076. }
  1077. if (!g_NameGroupRoutines[i].GroupName) {
  1078. DEBUGMSG ((DBG_WHOOPS, "ValidateName: Don't know how to validate %s names", NameGroup));
  1079. LOG ((LOG_ERROR, "Don't know how to validate %s names", NameGroup));
  1080. return TRUE;
  1081. }
  1082. g_NameGroupRoutines[i].Context.FromUserInterface = TRUE;
  1083. b = g_NameGroupRoutines[i].Validate (&g_NameGroupRoutines[i].Context, NameCandidate);
  1084. if (!b && ParentWnd) {
  1085. OkBox (ParentWnd, g_NameGroupRoutines[i].Context.FailureMsg);
  1086. }
  1087. g_NameGroupRoutines[i].Context.FromUserInterface = FALSE;
  1088. return b;
  1089. }
  1090. BOOL
  1091. pDoesNameExistInMemDb (
  1092. IN PNAME_GROUP_CONTEXT Context,
  1093. IN PCTSTR Name
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. pDoesUserExistInMemDb looks in memdb to see if the specified name
  1098. is listed in either the NewNames category (incompatible names that
  1099. are going to be changed), or the InUseNames category (compatible
  1100. names that cannot be used more than once).
  1101. This routine compares only names in the same name group.
  1102. Arguments:
  1103. Context - Specifies the group context
  1104. Name - Specifies the name to query
  1105. Return Value:
  1106. TRUE if the name is in use, or FALSE if the name is not in use.
  1107. --*/
  1108. {
  1109. TCHAR Node[MEMDB_MAX];
  1110. DEBUGMSG ((DBG_NAMEFIX, "%s: [%s] is compatible", Context->GroupName, Name));
  1111. MemDbBuildKey (
  1112. Node,
  1113. MEMDB_CATEGORY_NEWNAMES,
  1114. Context->GroupName,
  1115. MEMDB_FIELD_NEW,
  1116. Name
  1117. );
  1118. if (MemDbGetValue (Node, NULL)) {
  1119. return TRUE;
  1120. }
  1121. MemDbBuildKey (
  1122. Node,
  1123. MEMDB_CATEGORY_INUSENAMES,
  1124. Context->GroupName,
  1125. NULL,
  1126. Name
  1127. );
  1128. return MemDbGetValue (Node, NULL);
  1129. }
  1130. VOID
  1131. pMemDbSetIncompatibleName (
  1132. IN PCTSTR NameGroup,
  1133. IN PCTSTR OrgName,
  1134. IN PCTSTR NewName
  1135. )
  1136. /*++
  1137. Routine Description:
  1138. pMemDbSetIncompatibleName adds the correct entries to memdb to
  1139. have a name appear in the name collision wizard page.
  1140. Arguments:
  1141. NameGroup - Specifies the name group such as ComputerName, UserName, etc...
  1142. OrgName - Specifies the original name that is invalid
  1143. NewName - Specifies the recommended new name
  1144. Return Value:
  1145. none
  1146. --*/
  1147. {
  1148. DWORD NewNameOffset;
  1149. DEBUGMSG ((DBG_NAMEFIX, "%s: [%s]->[%s]", NameGroup, OrgName, NewName));
  1150. MemDbSetValueEx (
  1151. MEMDB_CATEGORY_NEWNAMES,
  1152. NameGroup,
  1153. NULL,
  1154. NULL,
  1155. 0,
  1156. NULL
  1157. );
  1158. MemDbSetValueEx (
  1159. MEMDB_CATEGORY_NEWNAMES,
  1160. NameGroup,
  1161. MEMDB_FIELD_NEW,
  1162. NewName,
  1163. 0,
  1164. &NewNameOffset
  1165. );
  1166. MemDbSetValueEx (
  1167. MEMDB_CATEGORY_NEWNAMES,
  1168. NameGroup,
  1169. MEMDB_FIELD_OLD,
  1170. OrgName,
  1171. NewNameOffset,
  1172. NULL
  1173. );
  1174. }
  1175. VOID
  1176. pMemDbSetCompatibleName (
  1177. IN PCTSTR NameGroup,
  1178. IN PCTSTR Name
  1179. )
  1180. /*++
  1181. Routine Description:
  1182. pMemDbSetCompatibleName creates the memdb entries necessary
  1183. to store names that are in use and are compatible.
  1184. Arguments:
  1185. NameGroup - Specifies the name group such as ComputerName, UserName, etc...
  1186. Name - Specifies the compatible name
  1187. Return Value:
  1188. none
  1189. --*/
  1190. {
  1191. MemDbSetValueEx (
  1192. MEMDB_CATEGORY_INUSENAMES,
  1193. NameGroup,
  1194. NULL,
  1195. Name,
  1196. 0,
  1197. NULL
  1198. );
  1199. }
  1200. VOID
  1201. CreateNameTables (
  1202. VOID
  1203. )
  1204. /*++
  1205. Routine Description:
  1206. CreateNameTables finds all names on the computer and puts valid names
  1207. into the InUseNames memdb category, and invalid names into the NewNames
  1208. memdb category (including both the invalid name and recommended name).
  1209. A wizard page appears if invalid names are found on the system.
  1210. Arguments:
  1211. none
  1212. Return Value:
  1213. none
  1214. --*/
  1215. {
  1216. INT i;
  1217. NAME_ENUM e;
  1218. PNAME_GROUP_ROUTINES Group;
  1219. TCHAR RecommendedName[MAX_NAME];
  1220. PTSTR p;
  1221. PTSTR DupList;
  1222. static BOOL AlreadyDone = FALSE;
  1223. if (AlreadyDone) {
  1224. return;
  1225. }
  1226. AlreadyDone = TRUE;
  1227. TurnOnWaitCursor();
  1228. //
  1229. // Special case: Add NT group names to InUse list
  1230. //
  1231. p = (PTSTR) GetStringResource (
  1232. *g_ProductFlavor == PERSONAL_PRODUCTTYPE ?
  1233. MSG_NAME_COLLISION_LIST_PER :
  1234. MSG_NAME_COLLISION_LIST
  1235. );
  1236. MYASSERT (p);
  1237. if (p) {
  1238. DupList = DuplicateText (p);
  1239. MYASSERT (DupList);
  1240. FreeStringResource (p);
  1241. p = _tcschr (DupList, TEXT('|'));
  1242. while (p) {
  1243. *p = 0;
  1244. p = _tcschr (_tcsinc (p), TEXT('|'));
  1245. }
  1246. Group = pGetNameGroupById (MSG_USERNAME_CATEGORY);
  1247. MYASSERT (Group);
  1248. if (Group) {
  1249. p = DupList;
  1250. while (*p) {
  1251. pMemDbSetCompatibleName (
  1252. Group->GroupName,
  1253. p
  1254. );
  1255. p = GetEndOfString (p) + 1;
  1256. }
  1257. }
  1258. FreeText (DupList);
  1259. }
  1260. //
  1261. // General case: Enumerate all names, call Validate and add them to memdb
  1262. //
  1263. for (i = 0 ; g_NameGroupRoutines[i].GroupName ; i++) {
  1264. Group = &g_NameGroupRoutines[i];
  1265. //
  1266. // Initialize the context structure
  1267. //
  1268. ZeroMemory (&Group->Context, sizeof (NAME_GROUP_CONTEXT));
  1269. Group->Context.GroupName = Group->GroupName;
  1270. //
  1271. // Call the enum entry point
  1272. //
  1273. ZeroMemory (&e, sizeof (e));
  1274. if (Group->Enum (&Group->Context, &e, TRUE)) {
  1275. do {
  1276. //
  1277. // Determine if this name is valid. If it is valid, add it to the
  1278. // InUseNames memdb category. If it is not valid, get a recommended
  1279. // replacement name, and store the incompatible and recommended
  1280. // names in the NewNames memdb category.
  1281. //
  1282. #ifdef TEST_MANGLE_NAMES
  1283. StringCat (e.Name, TEXT("\"%foo"));
  1284. #endif
  1285. #ifdef TEST_ALL_INCOMPATIBLE
  1286. if (0) {
  1287. #else
  1288. if (Group->Validate (&Group->Context, e.Name)) {
  1289. #endif
  1290. pMemDbSetCompatibleName (
  1291. Group->GroupName,
  1292. e.Name
  1293. );
  1294. } else {
  1295. Group->Recommend (&Group->Context, e.Name, RecommendedName);
  1296. pMemDbSetIncompatibleName (
  1297. Group->GroupName,
  1298. e.Name,
  1299. RecommendedName
  1300. );
  1301. }
  1302. } while (Group->Enum (&Group->Context, &e, FALSE));
  1303. }
  1304. }
  1305. TurnOffWaitCursor();
  1306. }
  1307. BOOL
  1308. IsIncompatibleNamesTableEmpty (
  1309. VOID
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. IsIncompatibleNamesTableEmpty looks at memdb to see if there are any
  1314. names in the NewNames category. This function is used to determine
  1315. if the name collision wizard page should appear.
  1316. Arguments:
  1317. none
  1318. Return Value:
  1319. TRUE if at least one name is invalid, or FALSE if all names are valid.
  1320. --*/
  1321. {
  1322. INVALID_NAME_ENUM e;
  1323. return !EnumFirstInvalidName (&e);
  1324. }
  1325. BOOL
  1326. pEnumInvalidNameWorker (
  1327. IN OUT PINVALID_NAME_ENUM EnumPtr
  1328. )
  1329. /*++
  1330. Routine Description:
  1331. pEnumInvalidNameWorker implements a state machine for invalid
  1332. name enumeration. It returns the group name, original name
  1333. and new name to the caller.
  1334. Arguments:
  1335. EnumPtr - Specifies the enumeration in progress; receives the
  1336. updated fields
  1337. Return Value:
  1338. TRUE if an item was enumerated, or FALSE if no more items exist.
  1339. --*/
  1340. {
  1341. PCTSTR p;
  1342. INT i;
  1343. while (EnumPtr->State != ENUM_STATE_DONE) {
  1344. switch (EnumPtr->State) {
  1345. case ENUM_STATE_INIT:
  1346. if (!MemDbEnumItems (&EnumPtr->NameGroup, MEMDB_CATEGORY_NEWNAMES)) {
  1347. EnumPtr->State = ENUM_STATE_DONE;
  1348. } else {
  1349. EnumPtr->State = ENUM_STATE_ENUM_FIRST_GROUP_ITEM;
  1350. }
  1351. break;
  1352. case ENUM_STATE_ENUM_FIRST_GROUP_ITEM:
  1353. if (!MemDbGetValueEx (
  1354. &EnumPtr->Name,
  1355. MEMDB_CATEGORY_NEWNAMES,
  1356. EnumPtr->NameGroup.szName,
  1357. MEMDB_FIELD_OLD
  1358. )) {
  1359. EnumPtr->State = ENUM_STATE_ENUM_NEXT_GROUP;
  1360. } else {
  1361. EnumPtr->State = ENUM_STATE_RETURN_GROUP_ITEM;
  1362. }
  1363. break;
  1364. case ENUM_STATE_RETURN_GROUP_ITEM:
  1365. //
  1366. // Get the group name
  1367. //
  1368. EnumPtr->GroupName = EnumPtr->NameGroup.szName;
  1369. //
  1370. // Get the display group name from the message resources
  1371. //
  1372. for (i = 0 ; g_NameGroupRoutines[i].GroupName ; i++) {
  1373. if (StringMatch (g_NameGroupRoutines[i].GroupName, EnumPtr->GroupName)) {
  1374. break;
  1375. }
  1376. }
  1377. MYASSERT (g_NameGroupRoutines[i].GroupName);
  1378. if (g_NameGroupRoutines[i].NameId == MSG_COMPUTERDOMAIN_CATEGORY) {
  1379. EnumPtr->State = ENUM_STATE_ENUM_NEXT_GROUP_ITEM;
  1380. break;
  1381. }
  1382. p = GetStringResource (g_NameGroupRoutines[i].NameId);
  1383. MYASSERT (p);
  1384. if (p) {
  1385. _tcssafecpy (EnumPtr->DisplayGroupName, p, (sizeof (EnumPtr->DisplayGroupName) / 2) / sizeof (TCHAR));
  1386. FreeStringResource (p);
  1387. }
  1388. ELSE_DEBUGMSG ((DBG_ERROR, "Unable to get string resource. Check localization."));
  1389. //
  1390. // Get EnumPtr->NewName and EnumPtr->Identifier
  1391. //
  1392. EnumPtr->OriginalName = EnumPtr->Name.szName;
  1393. MemDbBuildKeyFromOffset (
  1394. EnumPtr->Name.dwValue,
  1395. EnumPtr->NewName,
  1396. 3,
  1397. NULL
  1398. );
  1399. MemDbGetOffsetEx (
  1400. MEMDB_CATEGORY_NEWNAMES,
  1401. EnumPtr->GroupName,
  1402. MEMDB_FIELD_OLD,
  1403. EnumPtr->OriginalName,
  1404. &EnumPtr->Identifier
  1405. );
  1406. EnumPtr->State = ENUM_STATE_ENUM_NEXT_GROUP_ITEM;
  1407. return TRUE;
  1408. case ENUM_STATE_ENUM_NEXT_GROUP_ITEM:
  1409. if (!MemDbEnumNextValue (&EnumPtr->Name)) {
  1410. EnumPtr->State = ENUM_STATE_ENUM_NEXT_GROUP;
  1411. } else {
  1412. EnumPtr->State = ENUM_STATE_RETURN_GROUP_ITEM;
  1413. }
  1414. break;
  1415. case ENUM_STATE_ENUM_NEXT_GROUP:
  1416. if (!MemDbEnumNextValue (&EnumPtr->NameGroup)) {
  1417. EnumPtr->State = ENUM_STATE_DONE;
  1418. } else {
  1419. EnumPtr->State = ENUM_STATE_ENUM_FIRST_GROUP_ITEM;
  1420. }
  1421. break;
  1422. }
  1423. }
  1424. return FALSE;
  1425. }
  1426. BOOL
  1427. EnumFirstInvalidName (
  1428. OUT PINVALID_NAME_ENUM EnumPtr
  1429. )
  1430. /*++
  1431. Routine Description:
  1432. EnumFirstInvalidName enumerates the first entry in the memdb NewNames
  1433. category. The caller receives the name group, the old name and
  1434. the new name.
  1435. Arguments:
  1436. none
  1437. Return Value:
  1438. TRUE if at least one name is invalid, or FALSE if all names are valid.
  1439. --*/
  1440. {
  1441. EnumPtr->State = ENUM_STATE_INIT;
  1442. return pEnumInvalidNameWorker (EnumPtr);
  1443. }
  1444. BOOL
  1445. EnumNextInvalidName (
  1446. IN OUT PINVALID_NAME_ENUM EnumPtr
  1447. )
  1448. /*++
  1449. Routine Description:
  1450. EnumNextInvalidName enumerates the first entry in the memdb NewNames
  1451. category. The caller receives the name group, the old name and
  1452. the new name.
  1453. Arguments:
  1454. none
  1455. Return Value:
  1456. TRUE if another invalid name is available, or FALSE if no more names
  1457. can be enumerated.
  1458. --*/
  1459. {
  1460. return pEnumInvalidNameWorker (EnumPtr);
  1461. }
  1462. VOID
  1463. GetNamesFromIdentifier (
  1464. IN DWORD Identifier,
  1465. IN PTSTR NameGroup, OPTIONAL
  1466. IN PTSTR OriginalName, OPTIONAL
  1467. IN PTSTR NewName OPTIONAL
  1468. )
  1469. /*++
  1470. Routine Description:
  1471. GetNamesFromIdentifier copies names to caller-specified buffers, given a
  1472. unique identifier (a memdb offset). The unique identifer is provided
  1473. by enumeration functions.
  1474. Arguments:
  1475. Identifier - Specifies the identifier of the name.
  1476. NameGroup - Receives the text for the name group.
  1477. OriginalName - Receivies the original name.
  1478. NewName - Receives the fixed name that is compatible with NT.
  1479. Return Value:
  1480. none
  1481. --*/
  1482. {
  1483. BOOL b;
  1484. PTSTR p;
  1485. TCHAR NameGroupTemp[MEMDB_MAX];
  1486. TCHAR OrgNameTemp[MEMDB_MAX];
  1487. DWORD NewNameOffset;
  1488. if (NameGroup) {
  1489. *NameGroup = 0;
  1490. }
  1491. if (OriginalName) {
  1492. *OriginalName = 0;
  1493. }
  1494. if (NewName) {
  1495. *NewName = 0;
  1496. }
  1497. //
  1498. // Get NameGroup
  1499. //
  1500. if (!MemDbBuildKeyFromOffset (Identifier, NameGroupTemp, 1, NULL)) {
  1501. return;
  1502. }
  1503. p = _tcschr (NameGroupTemp, TEXT('\\'));
  1504. MYASSERT (p);
  1505. *p = 0;
  1506. if (NameGroup) {
  1507. StringCopy (NameGroup, NameGroupTemp);
  1508. }
  1509. //
  1510. // Get OrgName and NewNameOffset.
  1511. //
  1512. b = MemDbBuildKeyFromOffset (Identifier, OrgNameTemp, 3, &NewNameOffset);
  1513. if (OriginalName) {
  1514. StringCopy (OriginalName, OrgNameTemp);
  1515. }
  1516. //
  1517. // Get NewName
  1518. //
  1519. if (NewName) {
  1520. b &= MemDbBuildKeyFromOffset (NewNameOffset, NewName, 3, NULL);
  1521. }
  1522. MYASSERT (b);
  1523. }
  1524. VOID
  1525. ChangeName (
  1526. IN DWORD Identifier,
  1527. IN PCTSTR NewName
  1528. )
  1529. /*++
  1530. Routine Description:
  1531. ChangeName puts a new name value in memdb for the name indicated by
  1532. Identifier. The Identifier comes from enum functions.
  1533. Arguments:
  1534. Identifier - Specifies the name identifier (a memdb offset), and cannot be
  1535. zero.
  1536. NewName - Specifies the NT-compatible replacement name.
  1537. Return Value:
  1538. none
  1539. --*/
  1540. {
  1541. TCHAR Node[MEMDB_MAX];
  1542. TCHAR NameGroup[MEMDB_MAX];
  1543. TCHAR OrgName[MEMDB_MAX];
  1544. DWORD NewNameOffset;
  1545. PTSTR p, q;
  1546. BOOL b;
  1547. MYASSERT (Identifier);
  1548. if (!Identifier) {
  1549. return;
  1550. }
  1551. //
  1552. // - Obtain the original name
  1553. // - Get the offset to the current new name
  1554. // - Build the full key to the current new name
  1555. // - Delete the current new name
  1556. //
  1557. if (!MemDbBuildKeyFromOffset (Identifier, OrgName, 3, &NewNameOffset)) {
  1558. DEBUGMSG ((DBG_WHOOPS, "Can't obtain original name using offset %u", Identifier));
  1559. LOG ((LOG_ERROR, "Can't obtain original name using offset %u", Identifier));
  1560. return;
  1561. }
  1562. if (!MemDbBuildKeyFromOffset (NewNameOffset, Node, 0, NULL)) {
  1563. DEBUGMSG ((DBG_WHOOPS, "Can't obtain new name key using offset %u", NewNameOffset));
  1564. LOG ((LOG_ERROR, "Can't obtain new name key using offset %u", NewNameOffset));
  1565. return;
  1566. }
  1567. MemDbDeleteValue (Node);
  1568. //
  1569. // Obtain the name group from the key string. It's the second
  1570. // field (separated by backslashes).
  1571. //
  1572. p = _tcschr (Node, TEXT('\\'));
  1573. MYASSERT (p);
  1574. p = _tcsinc (p);
  1575. q = _tcschr (p, TEXT('\\'));
  1576. MYASSERT (q);
  1577. StringCopyAB (NameGroup, p, q);
  1578. //
  1579. // Now set the updated new name, and link the original name
  1580. // to the new name.
  1581. //
  1582. b = MemDbSetValueEx (
  1583. MEMDB_CATEGORY_NEWNAMES,
  1584. NameGroup,
  1585. MEMDB_FIELD_NEW,
  1586. NewName,
  1587. 0,
  1588. &NewNameOffset
  1589. );
  1590. b &= MemDbSetValueEx (
  1591. MEMDB_CATEGORY_NEWNAMES,
  1592. NameGroup,
  1593. MEMDB_FIELD_OLD,
  1594. OrgName,
  1595. NewNameOffset,
  1596. NULL
  1597. );
  1598. if (!b) {
  1599. LOG ((LOG_ERROR, "Failure while attempting to change %s name to %s.",OrgName,NewName));
  1600. }
  1601. }
  1602. BOOL
  1603. GetUpgradeComputerName (
  1604. OUT PTSTR NewName
  1605. )
  1606. /*++
  1607. Routine Description:
  1608. GetUpgradeComputerName obtains the computer name that will be used for
  1609. upgrade.
  1610. Arguments:
  1611. NewName - Receives the name of the computer, as it will be set
  1612. when NT is installed. Must hold at least
  1613. MAX_COMPUTER_NAME characters.
  1614. Return Value:
  1615. TRUE if the name exists, or FALSE if it does not yet exit.
  1616. --*/
  1617. {
  1618. PNAME_GROUP_ROUTINES Group;
  1619. NAME_ENUM e;
  1620. Group = pGetNameGroupById (MSG_COMPUTERNAME_CATEGORY);
  1621. MYASSERT (Group);
  1622. if (!Group)
  1623. return FALSE;
  1624. //
  1625. // Look in MemDb for a replacement name
  1626. //
  1627. if (MemDbGetEndpointValueEx (
  1628. MEMDB_CATEGORY_NEWNAMES,
  1629. Group->GroupName,
  1630. MEMDB_FIELD_NEW,
  1631. NewName
  1632. )) {
  1633. return TRUE;
  1634. }
  1635. //
  1636. // No replacement name; obtain the current name
  1637. //
  1638. ZeroMemory (&e, sizeof (e));
  1639. if (Group->Enum (&Group->Context, &e, TRUE)) {
  1640. StringCopy (NewName, e.Name);
  1641. while (Group->Enum (&Group->Context, &e, FALSE)) {
  1642. // empty
  1643. }
  1644. return TRUE;
  1645. }
  1646. return FALSE;
  1647. }
  1648. DWORD
  1649. GetDomainIdentifier (
  1650. VOID
  1651. )
  1652. /*++
  1653. Routine Description:
  1654. GetDomainIdentifier returns the identifier for the domain name. The
  1655. identifier is a memdb offset.
  1656. Arguments:
  1657. None.
  1658. Return Value:
  1659. A non-zero identifier which can be used with other routines in this file.
  1660. --*/
  1661. {
  1662. PNAME_GROUP_ROUTINES Group;
  1663. MEMDB_ENUM e;
  1664. DWORD Identifier = 0;
  1665. Group = pGetNameGroupById (MSG_COMPUTERDOMAIN_CATEGORY);
  1666. MYASSERT (Group);
  1667. if (Group && MemDbGetValueEx (
  1668. &e,
  1669. MEMDB_CATEGORY_NEWNAMES,
  1670. Group->GroupName,
  1671. MEMDB_FIELD_OLD
  1672. )) {
  1673. MemDbGetOffsetEx (
  1674. MEMDB_CATEGORY_NEWNAMES,
  1675. Group->GroupName,
  1676. MEMDB_FIELD_OLD,
  1677. e.szName,
  1678. &Identifier
  1679. );
  1680. }
  1681. return Identifier;
  1682. }
  1683. BOOL
  1684. pGetUpgradeName (
  1685. IN UINT CategoryId,
  1686. OUT PTSTR NewName
  1687. )
  1688. /*++
  1689. Routine Description:
  1690. pGetUpgradeName returns the NT-compatible name for a given name group. If
  1691. a name group has multiple names, this routine should not be used.
  1692. Arguments:
  1693. CategoryId - Specifies the MSG_* constant for the group (see macro
  1694. expansion list at top of file).
  1695. NewName - Receives the text for the NT-compatible replacement name for
  1696. the group.
  1697. Return Value:
  1698. TRUE if a name is being returned, or FALSE if no replacement name exists.
  1699. --*/
  1700. {
  1701. PNAME_GROUP_ROUTINES Group;
  1702. NAME_ENUM e;
  1703. Group = pGetNameGroupById (CategoryId);
  1704. MYASSERT (Group);
  1705. if (!Group)
  1706. return FALSE;
  1707. //
  1708. // Look in MemDb for a replacement name
  1709. //
  1710. if (MemDbGetEndpointValueEx (
  1711. MEMDB_CATEGORY_NEWNAMES,
  1712. Group->GroupName,
  1713. MEMDB_FIELD_NEW,
  1714. NewName
  1715. )) {
  1716. return TRUE;
  1717. }
  1718. //
  1719. // No replacement name; obtain the current name
  1720. //
  1721. ZeroMemory (&e, sizeof (e));
  1722. if (Group->Enum (&Group->Context, &e, TRUE)) {
  1723. StringCopy (NewName, e.Name);
  1724. while (Group->Enum (&Group->Context, &e, FALSE)) {
  1725. // empty
  1726. }
  1727. return TRUE;
  1728. }
  1729. return FALSE;
  1730. }
  1731. BOOL
  1732. GetUpgradeDomainName (
  1733. OUT PTSTR NewName
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. GetUpgradeDomainName returns the new domain name, if one exists.
  1738. Arguments:
  1739. NewName - Receiveis the new domain name.
  1740. Return Value:
  1741. TRUE if a new name is being returned, or FALSE if no replacement name
  1742. exists.
  1743. --*/
  1744. {
  1745. return pGetUpgradeName (
  1746. MSG_COMPUTERDOMAIN_CATEGORY,
  1747. NewName
  1748. );
  1749. }
  1750. BOOL
  1751. GetUpgradeWorkgroupName (
  1752. OUT PTSTR NewName
  1753. )
  1754. /*++
  1755. Routine Description:
  1756. GetUpgradeWorkgroupName returns the new workgroup name, if one exists.
  1757. Arguments:
  1758. None.
  1759. Return Value:
  1760. TRUE if a new name is being returned, or FALSE if no replacement name
  1761. exists.
  1762. --*/
  1763. {
  1764. return pGetUpgradeName (
  1765. MSG_WORKGROUP_CATEGORY,
  1766. NewName
  1767. );
  1768. }
  1769. BOOL
  1770. GetUpgradeUserName (
  1771. IN PCTSTR User,
  1772. OUT PTSTR NewUserName
  1773. )
  1774. /*++
  1775. Routine Description:
  1776. GetUpgradeUserName returns the fixed user name for the user specified. If
  1777. no fixed name exists, this routine returns the original name.
  1778. Arguments:
  1779. User - Specifies the user to look up. The user name must exist on
  1780. the Win9x configuration.
  1781. NewUserName - Receives the NT-compatible user name, which may or may not be
  1782. the same as User.
  1783. Return Value:
  1784. Always TRUE.
  1785. --*/
  1786. {
  1787. PNAME_GROUP_ROUTINES Group;
  1788. TCHAR Node[MEMDB_MAX];
  1789. DWORD NewOffset;
  1790. Group = pGetNameGroupById (MSG_USERNAME_CATEGORY);
  1791. MYASSERT (Group);
  1792. //
  1793. // Look in MemDb for a replacement name
  1794. //
  1795. if (Group) {
  1796. MemDbBuildKey (
  1797. Node,
  1798. MEMDB_CATEGORY_NEWNAMES,
  1799. Group->GroupName,
  1800. MEMDB_FIELD_OLD,
  1801. User
  1802. );
  1803. if (MemDbGetValue (Node, &NewOffset)) {
  1804. if (MemDbBuildKeyFromOffset (NewOffset, NewUserName, 3, NULL)) {
  1805. return TRUE;
  1806. }
  1807. }
  1808. }
  1809. //
  1810. // No replacement name; use the current name
  1811. //
  1812. StringCopy (NewUserName, User);
  1813. return TRUE;
  1814. }
  1815. BOOL
  1816. WarnAboutBadNames (
  1817. IN HWND PopupParent
  1818. )
  1819. /*++
  1820. Routine Description:
  1821. WarnAboutBadNames adds an incompatibility message whenever domain
  1822. logon is enabled but there is no account set up for the machine. A popup
  1823. is generated if PopupParent is non-NULL.
  1824. Other incompatibility messages are added for each name that will change.
  1825. Arguments:
  1826. Popup - Specifies TRUE if the message should appear in a message box, or
  1827. FALSE if it should be added to the incompatibility report.
  1828. Return Value:
  1829. TRUE if the user wants to continue, or FALSE if the user wants to change
  1830. the domain name.
  1831. --*/
  1832. {
  1833. PCTSTR RootGroup;
  1834. PCTSTR NameSubGroup;
  1835. PCTSTR FullGroupName;
  1836. PCTSTR BaseGroup;
  1837. PNAME_GROUP_CONTEXT Context;
  1838. PCTSTR ArgArray[3];
  1839. INVALID_NAME_ENUM e;
  1840. BOOL b = TRUE;
  1841. TCHAR EncodedName[MEMDB_MAX];
  1842. PCTSTR Blank;
  1843. if (PopupParent) {
  1844. //
  1845. // PopupParent is non-NULL only when the incompatible names wizard page
  1846. // is being deactivated. Here we have a chance to make sure the names
  1847. // specified all work together before proceeding.
  1848. //
  1849. // This functionality has been disabled because domain validation has
  1850. // been moved to a new page. We might re-enable this when another
  1851. // invalid name group comes along.
  1852. //
  1853. return TRUE;
  1854. }
  1855. //
  1856. // Enumerate all bad names
  1857. //
  1858. if (EnumFirstInvalidName (&e)) {
  1859. Blank = GetStringResource (MSG_BLANK_NAME);
  1860. MYASSERT (Blank);
  1861. do {
  1862. //
  1863. // Prepare message
  1864. //
  1865. ArgArray[0] = e.DisplayGroupName;
  1866. ArgArray[1] = e.OriginalName;
  1867. ArgArray[2] = e.NewName;
  1868. if (ArgArray[1][0] == 0) {
  1869. ArgArray[1] = Blank;
  1870. }
  1871. if (ArgArray[2][0] == 0) {
  1872. ArgArray[2] = Blank;
  1873. }
  1874. RootGroup = GetStringResource (MSG_INSTALL_NOTES_ROOT);
  1875. MYASSERT (RootGroup);
  1876. NameSubGroup = ParseMessageID (MSG_NAMECHANGE_WARNING_GROUP, ArgArray);
  1877. MYASSERT (NameSubGroup);
  1878. BaseGroup = JoinPaths (RootGroup, NameSubGroup);
  1879. MYASSERT (BaseGroup);
  1880. FreeStringResource (RootGroup);
  1881. FreeStringResource (NameSubGroup);
  1882. NameSubGroup = ParseMessageID (MSG_NAMECHANGE_WARNING_SUBCOMPONENT, ArgArray);
  1883. MYASSERT (NameSubGroup);
  1884. FullGroupName = JoinPaths (BaseGroup, NameSubGroup);
  1885. MYASSERT (FullGroupName);
  1886. FreePathString (BaseGroup);
  1887. FreeStringResource (NameSubGroup);
  1888. EncodedName[0] = TEXT('|');
  1889. StringCopy (EncodedName + 1, e.OriginalName);
  1890. MsgMgr_ObjectMsg_Add(
  1891. EncodedName, // Object name, prefixed with a pipe symbol
  1892. FullGroupName, // Message title
  1893. S_EMPTY // Message text
  1894. );
  1895. FreePathString (FullGroupName);
  1896. } while (EnumNextInvalidName (&e));
  1897. FreeStringResource (Blank);
  1898. //
  1899. // Save changed user names to FixedUserNames
  1900. //
  1901. Context = pGetNameGroupContextById (MSG_USERNAME_CATEGORY);
  1902. MYASSERT (Context);
  1903. if (EnumFirstInvalidName (&e)) {
  1904. do {
  1905. if (StringMatch (Context->GroupName, e.GroupName)) {
  1906. _tcssafecpy (EncodedName, e.OriginalName, MAX_USER_NAME);
  1907. MemDbMakeNonPrintableKey (
  1908. EncodedName,
  1909. MEMDB_CONVERT_DOUBLEWACKS_TO_ASCII_1|
  1910. MEMDB_CONVERT_WILD_STAR_TO_ASCII_2|
  1911. MEMDB_CONVERT_WILD_QMARK_TO_ASCII_3
  1912. );
  1913. MemDbSetValueEx (
  1914. MEMDB_CATEGORY_FIXEDUSERNAMES,
  1915. EncodedName,
  1916. NULL,
  1917. e.NewName,
  1918. 0,
  1919. NULL
  1920. );
  1921. }
  1922. } while (EnumNextInvalidName (&e));
  1923. }
  1924. }
  1925. return b;
  1926. }
  1927. DWORD
  1928. BadNamesWarning (
  1929. DWORD Request
  1930. )
  1931. {
  1932. switch (Request) {
  1933. case REQUEST_QUERYTICKS:
  1934. return TICKS_BAD_NAMES_WARNING;
  1935. case REQUEST_RUN:
  1936. if (!WarnAboutBadNames (NULL)) {
  1937. return GetLastError ();
  1938. }
  1939. else {
  1940. return ERROR_SUCCESS;
  1941. }
  1942. default:
  1943. DEBUGMSG ((DBG_ERROR, "Bad parameter in BadNamesWarning"));
  1944. }
  1945. return 0;
  1946. }
  1947. //
  1948. // The following flag is no longer in use. It used to be used
  1949. // to disable domain checking (to bypass the block requiring
  1950. // a valid domain). Currently there is no way to get beyond
  1951. // the wizard page that resolved the domain name, except by
  1952. // providing a valid domain or credentials to create a computer
  1953. // account on a domain.
  1954. //
  1955. BOOL g_DisableDomainChecks = FALSE;
  1956. VOID
  1957. DisableDomainChecks (
  1958. VOID
  1959. )
  1960. {
  1961. g_DisableDomainChecks = TRUE;
  1962. }
  1963. VOID
  1964. EnableDomainChecks (
  1965. VOID
  1966. )
  1967. {
  1968. g_DisableDomainChecks = FALSE;
  1969. }
  1970. BOOL
  1971. IsOriginalDomainNameValid (
  1972. VOID
  1973. )
  1974. /*++
  1975. Routine Description:
  1976. IsOriginalDomainNameValid checks to see if there is a replacement domain
  1977. name. If there is, the current domain name must be invalid.
  1978. Arguments:
  1979. None.
  1980. Return Value:
  1981. TRUE - the Win9x domain name is valid, no replacement name exists
  1982. FALSE - the Win9x domain name is invalid
  1983. --*/
  1984. {
  1985. PNAME_GROUP_ROUTINES Group;
  1986. TCHAR NewName[MEMDB_MAX];
  1987. Group = pGetNameGroupById (MSG_COMPUTERDOMAIN_CATEGORY);
  1988. MYASSERT (Group);
  1989. //
  1990. // Look in MemDb for a replacement name
  1991. //
  1992. if (Group && MemDbGetEndpointValueEx (
  1993. MEMDB_CATEGORY_NEWNAMES,
  1994. Group->GroupName,
  1995. MEMDB_FIELD_NEW,
  1996. NewName
  1997. )) {
  1998. return FALSE;
  1999. }
  2000. return TRUE;
  2001. }