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.

437 lines
11 KiB

  1. /*++
  2. Copyright (c) 1987-1992 Microsoft Corporation
  3. Module Name:
  4. getdclst.c
  5. Abstract:
  6. I_NetGetDCList API
  7. Author:
  8. 04-Feb-1992 (CliffV)
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. --*/
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <rpc.h>
  19. #include <logon_c.h>// includes lmcons.h, lmaccess.h, netlogon.h, ssi.h, windef.h
  20. #include <debuglib.h> // IF_DEBUG()
  21. #include <lmapibuf.h>
  22. #include <lmerr.h>
  23. #include <lmserver.h> // SV_TYPE_* defines
  24. #include <netdebug.h> // NetpKdPrint
  25. #include <netlib.h> // NetpGetDomainName
  26. #include <ntlsa.h> // LsaTrust list
  27. #include <tstring.h> // STRLEN
  28. #include <stdlib.h> // wcslen
  29. DBGSTATIC NET_API_STATUS
  30. InternalNetGetDCList (
  31. IN LPWSTR ServerName OPTIONAL,
  32. IN LPWSTR TrustedDomainName,
  33. OUT PULONG DCCount,
  34. OUT PUNICODE_STRING * DCNames
  35. )
  36. /*++
  37. Routine Description:
  38. Get the names of the NT Domain Controllers in a domain. The information
  39. is returned in a form suitable for storing in the LSA's
  40. TRUSTED_CONTROLLERS_INFO structure.
  41. Ideally, ServerName should be the name of a Domain Controller in the
  42. specified domain. However, one should first try specifying ServerName
  43. as the name of the PDC in the trusting domain. If that fails,
  44. the UI can prompt for the name of a DC in the domain.
  45. Arguments:
  46. ServerName - name of remote server (null for local).
  47. TrustedDomainName - name of domain.
  48. DCCount - Returns the number of entries in the DCNames array.
  49. DCNames - Returns a pointer to an array of names of NT Domain Controllers
  50. in the specified domain. The first entry is the name of the NT PDC.
  51. The first entry will be NULL if the PDC cannot be found.
  52. The buffer should be deallocated using NetApiBufferFree.
  53. Return Value:
  54. NERR_Success - Success.
  55. ERROR_INVALID_NAME Badly formed domain name
  56. NERR_DCNotFound - No DC's were found in the domain
  57. --*/
  58. {
  59. NET_API_STATUS NetStatus;
  60. PSERVER_INFO_101 ServerInfo101 = NULL;
  61. DWORD EntriesRead;
  62. DWORD TotalEntries;
  63. DWORD Size = 0;
  64. BOOLEAN PdcFound = FALSE;
  65. PUNICODE_STRING ReturnBuffer = NULL;
  66. ULONG ReturnCount = 0;
  67. PUNICODE_STRING CurrentBuffer;
  68. ULONG CurrentIndex;
  69. LPWSTR Where;
  70. DWORD i;
  71. //
  72. // Enumerate ALL PDCs and BDCs in the domain.
  73. // We'll filter out NT DC's ourselves.
  74. //
  75. *DCCount = 0;
  76. NetStatus = NetServerEnum( ServerName,
  77. 101,
  78. (LPBYTE *) &ServerInfo101,
  79. MAX_PREFERRED_LENGTH,
  80. &EntriesRead,
  81. &TotalEntries,
  82. SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL,
  83. TrustedDomainName,
  84. NULL ); // Resume Handle
  85. if ( NetStatus != NERR_Success ) {
  86. IF_DEBUG( LOGON ) {
  87. NetpKdPrint((
  88. "InternalNetGetDCList: cannot NetServerEnum '%ws': %ld 0X%lx\n",
  89. ServerName, NetStatus, NetStatus));
  90. }
  91. goto Cleanup;
  92. }
  93. //
  94. // Compute the size of the information to return.
  95. //
  96. for ( i=0; i<EntriesRead; i++ ) {
  97. IF_DEBUG( LOGON ) {
  98. NetpKdPrint((
  99. "InternalNetGetDCList: '%ws': enumerated %ws\n",
  100. ServerName,
  101. ServerInfo101[i].sv101_name ));
  102. }
  103. //
  104. // Skip non-NT entries
  105. //
  106. if ( (ServerInfo101[i].sv101_type & SV_TYPE_NT) == 0 ) {
  107. IF_DEBUG( LOGON ) {
  108. NetpKdPrint((
  109. "InternalNetGetDCList: '%ws': %ws is not NT\n",
  110. ServerName,
  111. ServerInfo101[i].sv101_name ));
  112. }
  113. continue;
  114. }
  115. //
  116. // Remember whether the PDC was found
  117. //
  118. if ( ServerInfo101[i].sv101_type & SV_TYPE_DOMAIN_CTRL ) {
  119. IF_DEBUG( LOGON ) {
  120. NetpKdPrint((
  121. "InternalNetGetDCList: '%ws': %ws is the PDC\n",
  122. ServerName,
  123. ServerInfo101[i].sv101_name ));
  124. }
  125. PdcFound = TRUE;
  126. }
  127. //
  128. // Leave room for for the UNICODE_STRING structure and the string
  129. // itself (including leadind \\'s.
  130. //
  131. (*DCCount) ++;
  132. Size += sizeof(UNICODE_STRING) +
  133. (STRLEN(ServerInfo101[i].sv101_name) + 3) * sizeof(WCHAR);
  134. }
  135. //
  136. // We must find at least one NT server.
  137. //
  138. if ( *DCCount == 0 ) {
  139. NetStatus = NERR_DCNotFound;
  140. goto Cleanup;
  141. }
  142. if ( !PdcFound ) {
  143. IF_DEBUG( LOGON ) {
  144. NetpKdPrint((
  145. "InternalNetGetDCList: '%ws': PDC not found\n",
  146. ServerName ));
  147. }
  148. (*DCCount) ++;
  149. Size += sizeof(UNICODE_STRING);
  150. }
  151. //
  152. // Allocate the return buffer.
  153. //
  154. NetStatus = NetApiBufferAllocate( Size, (LPVOID *) &ReturnBuffer );
  155. if ( NetStatus != NERR_Success ) {
  156. goto Cleanup;
  157. }
  158. Where = (LPWSTR) (ReturnBuffer + *DCCount);
  159. //
  160. // Fill in the return buffer.
  161. //
  162. CurrentIndex = 1; // The first (zeroeth) entry is for the PDC.
  163. RtlInitUnicodeString( ReturnBuffer, NULL );
  164. for ( i=0; i<EntriesRead; i++ ) {
  165. //
  166. // Skip non-NT entries
  167. //
  168. if ( (ServerInfo101[i].sv101_type & SV_TYPE_NT) == 0 ) {
  169. continue;
  170. }
  171. //
  172. // Determine which entry to fill in.
  173. //
  174. // If multiple PDC's were found, the first one is assumed
  175. // to be the real PDC>
  176. //
  177. if ( (ServerInfo101[i].sv101_type & SV_TYPE_DOMAIN_CTRL) &&
  178. ReturnBuffer->Buffer == NULL ) {
  179. CurrentBuffer = ReturnBuffer;
  180. } else {
  181. NetpAssert( CurrentIndex < *DCCount );
  182. CurrentBuffer = &ReturnBuffer[CurrentIndex];
  183. CurrentIndex++;
  184. }
  185. //
  186. // Copy the string itself to the return buffer
  187. //
  188. NetpAssert( ServerInfo101[i].sv101_name[0] != L'\\' );
  189. *(Where) = '\\';
  190. *(Where+1) = '\\';
  191. NetpCopyTStrToWStr( Where+2, ServerInfo101[i].sv101_name );
  192. //
  193. // Set the UNICODE_STRING to point to it.
  194. //
  195. RtlInitUnicodeString( CurrentBuffer, Where );
  196. Where += (wcslen(Where) + 1);
  197. }
  198. NetpAssert( CurrentIndex == *DCCount );
  199. NetStatus = NERR_Success;
  200. //
  201. // Cleanup locally used resources
  202. //
  203. Cleanup:
  204. if ( ServerInfo101 != NULL ) {
  205. NetApiBufferFree( ServerInfo101 );
  206. }
  207. if ( NetStatus != NERR_Success ) {
  208. if ( ReturnBuffer != NULL ) {
  209. NetApiBufferFree( ReturnBuffer );
  210. ReturnBuffer = NULL;
  211. }
  212. *DCCount = 0;
  213. }
  214. //
  215. // Return the information to the caller.
  216. //
  217. *DCNames = ReturnBuffer;
  218. return NetStatus;
  219. }
  220. NET_API_STATUS NET_API_FUNCTION
  221. I_NetGetDCList (
  222. IN LPWSTR ServerName OPTIONAL,
  223. IN LPWSTR TrustedDomainName,
  224. OUT PULONG DCCount,
  225. OUT PUNICODE_STRING * DCNames
  226. )
  227. /*++
  228. Routine Description:
  229. Get the names of the NT Domain Controllers in a domain. The information
  230. is returned in a form suitable for storing in the LSA's
  231. TRUSTED_CONTROLLERS_INFO structure.
  232. Ideally, ServerName should be the name of a Domain Controller in the
  233. specified domain. However, one should first try specifying ServerName
  234. as NULL in which case this API will try the the following machines:
  235. * The local machine.
  236. * The PDC of the primary domain of the local machine,
  237. * The PDC of the named trusted domain,
  238. * Each of the DC's in the LSA's current DC list for the named trusted
  239. domain.
  240. If this "NULL" case fails, the UI should prompt for the name of a DC
  241. in the trusted domain. This handles the case where the trusted domain
  242. cannot be reached via the above listed servers.
  243. Arguments:
  244. ServerName - name of remote server (null for special case).
  245. TrustedDomainName - name of domain.
  246. DCCount - Returns the number of entries in the DCNames array.
  247. DCNames - Returns a pointer to an array of names of NT Domain Controllers
  248. in the specified domain. The first entry is the name of the NT PDC.
  249. The first entry will be NULL if the PDC cannot be found.
  250. The buffer should be deallocated using NetApiBufferFree.
  251. Return Value:
  252. NERR_Success - Success.
  253. ERROR_INVALID_NAME Badly formed domain name
  254. NERR_DCNotFound - No DC's were found in the domain. Perhaps,
  255. a ServerName should be specified.
  256. --*/
  257. {
  258. NET_API_STATUS NetStatus;
  259. NET_API_STATUS SavedNetStatus;
  260. LPWSTR DCName = NULL;
  261. //
  262. // Initialization
  263. //
  264. *DCCount = 0;
  265. //
  266. // Try straight forward way to get the DC list.
  267. //
  268. NetStatus = InternalNetGetDCList( ServerName,
  269. TrustedDomainName,
  270. DCCount,
  271. DCNames );
  272. if ( NetStatus == NERR_Success || ServerName != NULL ) {
  273. SavedNetStatus = NetStatus;
  274. goto Cleanup;
  275. }
  276. SavedNetStatus = NetStatus;
  277. //
  278. // Simply use the PDC name as the DC list.
  279. //
  280. // NetServerEnum might be several minutes out of date. NetGetDCName
  281. // broadcasts to find the server, so that information will be more
  282. // current.
  283. //
  284. NetStatus = NetGetDCName( NULL, TrustedDomainName, (LPBYTE*)&DCName);
  285. if ( NetStatus == NERR_Success ) {
  286. PUNICODE_STRING ReturnBuffer = NULL;
  287. DWORD Size;
  288. LPWSTR Where;
  289. Size = sizeof(UNICODE_STRING) +
  290. (wcslen(DCName) + 1) * sizeof(WCHAR);
  291. NetStatus = NetApiBufferAllocate( Size, (LPVOID *) &ReturnBuffer );
  292. if ( NetStatus != NERR_Success ) {
  293. goto Cleanup;
  294. }
  295. Where = (LPWSTR)((LPBYTE)ReturnBuffer + sizeof(UNICODE_STRING));
  296. wcscpy( Where, DCName );
  297. RtlInitUnicodeString( ReturnBuffer, Where );
  298. *DCNames = ReturnBuffer;
  299. *DCCount = 1;
  300. SavedNetStatus = NERR_Success;
  301. }
  302. //
  303. // Cleanup locally used resources.
  304. //
  305. Cleanup:
  306. if( DCName != NULL ) {
  307. (VOID) NetApiBufferFree( DCName );
  308. }
  309. //
  310. // Return the status code from the original request.
  311. //
  312. return SavedNetStatus;
  313. }