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.

548 lines
13 KiB

  1. /*++
  2. DOMAIN.CXX
  3. Copyright (C) 1999 Microsoft Corporation, all rights reserved.
  4. DESCRIPTION:
  5. Created, May 21, 1999 by DavidCHR.
  6. CONTENTS: GetComputerRoleInformation
  7. DoItAnyway
  8. --*/
  9. #include "everything.hxx"
  10. extern "C" {
  11. #include "..\keytab2\keytab\ldlib\delegtools.h"
  12. #include <dsgetdc.h>
  13. #include <lm.h>
  14. }
  15. PLDAP GlobalLdap = NULL;
  16. LPWSTR GlobalClientName = NULL;
  17. LPWSTR GlobalDomainSetting = NULL; /* if NULL, we're not doing anything
  18. in the domain. if Nonnull, this
  19. is the DNS domain we want. */
  20. BOOL
  21. ConnectedToDsa( VOID ) {
  22. BOOL ret = ( GlobalLdap != NULL );
  23. LPWSTR TargetComputer = NULL;
  24. DWORD dwErr;
  25. PLDAP pLdap;
  26. if ( !ret ) {
  27. if ( GlobalDomainSetting ) {
  28. PDOMAIN_CONTROLLER_INFOW pDcInfo;
  29. dwErr = DsGetDcNameW( NULL, // computername (don't care)
  30. GlobalDomainSetting,
  31. NULL, // guid (don't care)
  32. NULL, // site (don't care)
  33. DS_DIRECTORY_SERVICE_REQUIRED |
  34. DS_IP_REQUIRED |
  35. DS_ONLY_LDAP_NEEDED,
  36. &pDcInfo );
  37. if ( ERROR_SUCCESS == dwErr ) {
  38. TargetComputer = pDcInfo->DomainControllerName;
  39. DEBUGPRINT( DEBUG_DOMAIN,
  40. ( "Found Domain Controller: %ws\n",
  41. TargetComputer ) );
  42. /* Sometimes, inexplicably, DsGetDcName returns
  43. a DC name that starts with "\\\\". It doesn't
  44. seem to happen all the time, so I'll workaround. */
  45. while ( TargetComputer[ 0 ] == L'\\' ) {
  46. TargetComputer++;
  47. DEBUGPRINT( DEBUG_DOMAIN,
  48. ( "Changed to %ws...\n",
  49. TargetComputer ) );
  50. /* assert that we were not given a DCname that's just
  51. a bunch of slashes. */
  52. ASSERT( TargetComputer[ 0 ] != L'\0' );
  53. }
  54. /* WASBUG 73940: leaks, but we don't care. it's an app, so
  55. any leaked memory will be short-lived. */
  56. } else {
  57. printf( "Failed to locate a DC for %ws: 0x%x.\n",
  58. GlobalDomainSetting,
  59. dwErr );
  60. return FALSE;
  61. }
  62. }
  63. pLdap = ldap_openW( TargetComputer,
  64. LDAP_PORT );
  65. if ( pLdap ) {
  66. dwErr = ldap_bind_s( pLdap,
  67. NULL,
  68. NULL,
  69. LDAP_AUTH_NEGOTIATE );
  70. if ( LDAP_SUCCESS == dwErr ) {
  71. GlobalLdap = pLdap;
  72. ret = TRUE;
  73. } else {
  74. ldap_unbind( pLdap );
  75. printf( "Ldap bind failed for %ws: 0x%x\n",
  76. TargetComputer ? TargetComputer : L"default DC",
  77. dwErr );
  78. }
  79. } else {
  80. printf( "Ldap open failed for %ws: 0x%x.\n",
  81. TargetComputer ? TargetComputer : L"default DC",
  82. GetLastError() );
  83. }
  84. }
  85. if ( !ret ) {
  86. GlobalLdap = NULL;
  87. }
  88. return ret;
  89. }
  90. NTSTATUS
  91. AssignUnicodeStringToWideString( IN PUNICODE_STRING pString,
  92. OUT LPWSTR *Buffer ) {
  93. LPWSTR p;
  94. p = (LPWSTR) malloc( pString->Length + sizeof( WCHAR ) );
  95. if ( p ) {
  96. memcpy( p,
  97. pString->Buffer,
  98. pString->Length );
  99. p[ pString->Length / sizeof( WCHAR ) ] = L'\0';
  100. *Buffer = p;
  101. return STATUS_SUCCESS;
  102. } else {
  103. printf( "unable to allocate string copy of %wZ.\n",
  104. pString );
  105. return STATUS_NO_MEMORY;
  106. }
  107. }
  108. /*++**************************************************************
  109. NAME: ChooseDomain
  110. specifies to use either the given domain (if Parameter 0 is
  111. nonnull) or the caller's domain.
  112. MODIFIES: the global UserDomain variable (above)
  113. TAKES: Parameters -- ripped from argv
  114. RETURNS: a status code indicating success or failure
  115. LOGGING: printf on failure
  116. CREATED: Apr 23, 1999
  117. LOCKING: none
  118. CALLED BY: main
  119. FREE WITH: n/a -- no resources are allocated
  120. **************************************************************--*/
  121. NTSTATUS
  122. ChooseDomain( LPWSTR *Parameters ) {
  123. NTSTATUS ret = STATUS_UNSUCCESSFUL;
  124. KERB_QUERY_TKT_CACHE_REQUEST TicketRequest = {
  125. KerbRetrieveTicketMessage
  126. };
  127. PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse;
  128. ULONG cbTicketResponse;
  129. if ( Parameters[ 0 ] ) {
  130. GlobalDomainSetting = Parameters[ 0 ];
  131. printf( "Connecting to specified domain %ws...\n",
  132. GlobalDomainSetting );
  133. }
  134. // first, bind to the default DSA for this realm.
  135. if ( TRUE ) { /* 73944: this was ConnectedToDsa(), but we don't
  136. necessarily have to connect to a DSA before
  137. calling the package. */
  138. // now, determine who we are.
  139. ret = CallAuthPackage( &TicketRequest,
  140. sizeof( TicketRequest ),
  141. (PVOID *) &pTicketResponse,
  142. &cbTicketResponse );
  143. if ( NT_SUCCESS( ret ) ) {
  144. /* WASBUG 73946: leaks, but the app doesn't run for more
  145. than a second. "Leaked" memory goes away on exit, so we
  146. don't care. */
  147. if ( !GlobalDomainSetting ) {
  148. /* only set this if we haven't set it ourselves.
  149. The reason being that the specified domain (above)
  150. is NOT the same as this one, which came from the cache. */
  151. AssignUnicodeStringToWideString(
  152. &pTicketResponse->Ticket.DomainName,
  153. &GlobalDomainSetting
  154. );
  155. }
  156. ASSERT( pTicketResponse->Ticket.ClientName->NameCount == 1 );
  157. AssignUnicodeStringToWideString(
  158. &pTicketResponse->Ticket.ClientName->Names[ 0 ],
  159. &GlobalClientName
  160. );
  161. ret = STATUS_SUCCESS;
  162. } else {
  163. printf( "Ticket cache query failed. Error 0x%x\n",
  164. ret );
  165. }
  166. }
  167. if ( NT_SUCCESS( ret ) ) {
  168. ASSERT( GlobalDomainSetting != NULL );
  169. printf( "Using domain %ws.\n",
  170. GlobalDomainSetting );
  171. } else {
  172. printf( "Could not guess user's domain.\n"
  173. " Please specify domain on command line and try again.\n" );
  174. }
  175. return ret;
  176. }
  177. /*++**************************************************************
  178. NAME: GetComputerRoleInformation
  179. Queries the target server for its role information-- basically,
  180. we use this to determine whether the machine is a domain
  181. controller.
  182. MODIFIES: pulRoleData
  183. RETURNS: a status code indicating success or failure
  184. LOGGING:
  185. CREATED: Jan 25, 2000
  186. LOCKING:
  187. CALLED BY: anyone
  188. FREE WITH: n/a -- no resources are allocated
  189. **************************************************************--*/
  190. NTSTATUS
  191. GetComputerRoleInformation( PULONG pulRoleData ) {
  192. NTSTATUS N;
  193. NET_API_STATUS NetStatus;
  194. PSERVER_INFO_101 pServerInfo;
  195. NetStatus = NetServerGetInfo( ServerName, // global.
  196. 101, // level
  197. (LPBYTE *) &pServerInfo );
  198. if ( NetStatus != STATUS_SUCCESS ) {
  199. printf( "Cannot determine %ws's Server Role: 0x%x.\n",
  200. ServerName ? ServerName : L"this computer",
  201. NetStatus );
  202. N = STATUS_UNSUCCESSFUL;
  203. } else {
  204. N = STATUS_SUCCESS;
  205. if ( pulRoleData ) *pulRoleData = pServerInfo->sv101_type;
  206. NetApiBufferFree( pServerInfo );
  207. }
  208. return N;
  209. }
  210. /*++**************************************************************
  211. NAME: DoItAnyway
  212. prompts the user-- "Do it anyway?"
  213. MODIFIES: nothing
  214. RETURNS: TRUE if the user decided to do it anyway
  215. FALSE if the user decided to abort.
  216. CREATED: Jan 25, 2000
  217. CALLED BY: anyone (most notably SetDnsDomain)
  218. FREE WITH: n/a -- no resources are allocated
  219. **************************************************************--*/
  220. BOOL
  221. DoItAnyway( VOID ) {
  222. int Response;
  223. while ( TRUE ) {
  224. printf( "Do it anyway [y/n]? " );
  225. Response = '\0';
  226. do {
  227. Response = getchar();
  228. } while ( isspace( Response ) );
  229. switch( Response ) {
  230. case 'Y':
  231. case 'y':
  232. return TRUE;
  233. break;
  234. case 'N':
  235. case 'n':
  236. return FALSE;
  237. break;
  238. case EOF:
  239. printf( "EOF at console. Assuming no.\n" );
  240. return FALSE;
  241. break;
  242. default:
  243. printf( "[unknown: %02x '%c']\n",
  244. Response,
  245. Response );
  246. break;
  247. }
  248. }
  249. // NOTREACHED
  250. }
  251. NTSTATUS
  252. SetDnsDomain( LPWSTR * Parameter)
  253. {
  254. NTSTATUS Status;
  255. POLICY_DNS_DOMAIN_INFO DnsDomainInformation = {0};
  256. LPSTR Description;
  257. ULONG Index, Role;
  258. BOOL PromptTheUser = FALSE;
  259. LPWSTR Arg;
  260. //
  261. // If no parameter is passed, prepare to unjoin from all domains/realms.
  262. // Print a scary message, but don't give the user a chance to abort.
  263. //
  264. if( Parameter[0] == NULL )
  265. {
  266. Arg = L"WORKGROUP";
  267. fprintf( stderr, "No parameter to /SetRealm - unjoining computer from all domains/realms.\n" );
  268. }
  269. else
  270. {
  271. Arg = Parameter[0];
  272. }
  273. if( !CheckUppercase( Arg ) )
  274. {
  275. return STATUS_UNSUCCESSFUL;
  276. }
  277. /* 453781: don't fiddle with DNS domain information if the
  278. machine is a Domain Controller -- results in a dead machine. */
  279. Status = GetComputerRoleInformation( &Role );
  280. if ( !NT_SUCCESS( Status ) ) {
  281. Description = "Cannot verify. If %ws is a domain controller, ";
  282. PromptTheUser = TRUE;
  283. goto WarnMe;
  284. } else if ( Role & ( SV_TYPE_DOMAIN_CTRL |
  285. SV_TYPE_DOMAIN_BAKCTRL ) ) {
  286. Description = "%ws is a domain controller-- ";
  287. WarnMe:
  288. printf( "*** WARNING! ***\n" );
  289. printf( Description,
  290. ServerName ? ServerName : L"this computer" );
  291. printf( "resetting its\n"
  292. "DNS Domain Information may render it unusable.\n" );
  293. if ( !PromptTheUser ) {
  294. printf( "This operation is not supported.\n" );
  295. return EPT_NT_CANT_PERFORM_OP; // cannot perform.
  296. } else if ( !DoItAnyway() ) {
  297. return Status;
  298. }
  299. }
  300. Status = STATUS_SUCCESS; // by default
  301. printf("Setting Dns Domain\n");
  302. //
  303. // set the netbios name to be the portion before the first '.' and
  304. // truncate to 14 characters
  305. //
  306. RtlInitUnicodeString(
  307. &DnsDomainInformation.Name,
  308. Arg
  309. );
  310. for (Index = 0; Index < DnsDomainInformation.Name.Length/sizeof(WCHAR) ; Index++ )
  311. {
  312. if (DnsDomainInformation.Name.Buffer[Index] == L'.')
  313. {
  314. DnsDomainInformation.Name.Length = (USHORT) (Index * sizeof(WCHAR));
  315. break;
  316. }
  317. }
  318. if (DnsDomainInformation.Name.Length > DNLEN * sizeof(WCHAR))
  319. {
  320. DnsDomainInformation.Name.Length = DNLEN * sizeof(WCHAR);
  321. }
  322. RtlInitUnicodeString(
  323. &DnsDomainInformation.DnsDomainName,
  324. Arg
  325. );
  326. Status = LsaSetInformationPolicy(
  327. LsaHandle,
  328. PolicyDnsDomainInformation,
  329. (PVOID) &DnsDomainInformation
  330. );
  331. if (!NT_SUCCESS(Status))
  332. {
  333. printf("Failed to set dns domain info: 0x%x\n",Status);
  334. return(Status);
  335. }
  336. //
  337. // Set the value in tcpip
  338. //
  339. if (!SetComputerNameEx(
  340. ComputerNamePhysicalDnsDomain,
  341. Arg))
  342. {
  343. printf("Failed to update host dns domain: %d (0x%x) \n",
  344. GetLastError(), GetLastError() );
  345. return(STATUS_UNSUCCESSFUL);
  346. }
  347. return(Status);
  348. }
  349. BOOL CheckUppercase( LPWSTR wszRealmName )
  350. {
  351. PWCHAR c = wszRealmName;
  352. while( *c != L'\0' )
  353. {
  354. if( iswalpha(*c) && !iswupper(*c) )
  355. {
  356. fprintf( stderr, "Your realm name \"%ws\" has lowercase letters.\nTraditionally, Kerberos Realms are in UPPERCASE. Please verify.\n", wszRealmName );
  357. if( DoItAnyway() )
  358. {
  359. return TRUE;
  360. }
  361. else
  362. {
  363. return FALSE;
  364. }
  365. }
  366. c++;
  367. }
  368. return TRUE;
  369. }