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.

834 lines
20 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1992 - 1999
  3. Module Name:
  4. cbind.cxx
  5. Abstract:
  6. This is the client side NSI service support layer. These functions
  7. provide for binding to the locator or other name server.
  8. Author:
  9. Steven Zeck (stevez) 03/04/92
  10. --*/
  11. #include <nsi.h>
  12. #ifndef NTENV
  13. #include <netcons.h>
  14. #include <neterr.h>
  15. #include <server.h>
  16. #include <access.h>
  17. #include <regapi.h>
  18. #include <mailslot.h>
  19. #include <wksta.h>
  20. #ifndef USHORT
  21. #define USHORT unsigned short
  22. #endif
  23. #else
  24. #include <lmcons.h>
  25. #include <lmapibuf.h>
  26. #include <lmaccess.h>
  27. #include <lmserver.h>
  28. #include <stdlib.h>
  29. #include "startsvc.h"
  30. #endif
  31. #include <string.h>
  32. #ifndef NTENV
  33. #include "locquery.h"
  34. #endif
  35. extern "C"
  36. {
  37. unsigned long RPC_ENTRY
  38. I_GetDefaultEntrySyntax(
  39. );
  40. }
  41. void RpcNsLmDiscard(void);
  42. #ifndef NTENV
  43. unsigned short BroadcastAQuery(unsigned long Query,
  44. char __RPC_FAR * Buffer,
  45. unsigned short Count);
  46. #define MAXLOCATORSTOTRY 8
  47. #endif
  48. #ifdef NTENV
  49. #define LOCALLOCATOR "\\\\."
  50. #endif
  51. #if defined(DOS) && !defined(WIN)
  52. extern int _NsAllocatorInitialized;
  53. extern __RPC_API NsAllocatorSetup();
  54. #define INIT_DOS_ALLOCATOR_IF_NECESSARY \
  55. { if (!_NsAllocatorInitialized) NsAllocatorSetup(); }
  56. #else // DOS only
  57. #define INIT_DOS_ALLOCATOR_IF_NECESSARY
  58. #endif // DOS only
  59. unsigned char * NsiStringBinding;
  60. enum {
  61. BindingReadRegistry = 0,
  62. BindingNotYetTried,
  63. BindingContinueRegistry,
  64. BindingFound,
  65. #ifndef NTENV
  66. BindingBackupFirst,
  67. BindingBackup,
  68. BindToBackupViaBC,
  69. BindToAnyViaBC
  70. #endif
  71. };
  72. #define NilOffset (-1)
  73. typedef struct
  74. {
  75. unsigned char *ProtoSeq;
  76. unsigned char *NetworkAddress;
  77. unsigned char *Endpoint;
  78. HKEY RegHandle;
  79. unsigned int NumberServers;
  80. int AddressOffset;
  81. void *Buffer;
  82. char *ServerList;
  83. int State;
  84. int NextState;
  85. } RPC_LOCATOR_BIND_CONTEXT, *PRPC_LOCATOR_BIND_CONTEXT;
  86. DWORD GblBindId = 0;
  87. #define MAX_SERVER_NAME 20
  88. static RPC_LOCATOR_BIND_CONTEXT near BindSearch;
  89. WIDE_STRING *DefaultName;
  90. long DefaultSyntax = RPC_C_NS_SYNTAX_DCE;
  91. int fSyntaxDefaultsLoaded;
  92. #ifndef NTENV
  93. char __RPC_FAR * MailslotName = "\\\\*\\mailslot\\Resp_s";
  94. char __RPC_FAR * LocalMS = "\\mailslot\\Resp_c";
  95. #define RESPONSETIME 4096L
  96. #endif
  97. unsigned char *
  98. RegGetString(
  99. IN void * RegHandle,
  100. IN char * KeyName
  101. )
  102. /*++
  103. Routine Description:
  104. Get a string from the registery.
  105. Arguments:
  106. KeyName - name of key to lookup.
  107. Returns:
  108. pointer to the allocated string, or Nil if not found
  109. --*/
  110. {
  111. char Buffer[300];
  112. DWORD BufferLength = sizeof(Buffer);
  113. DWORD Type;
  114. #ifdef NTENV
  115. if (RegQueryValueExA((HKEY)RegHandle, KeyName, 0, &Type,
  116. (unsigned char far*)Buffer, &BufferLength))
  117. #else
  118. if (RegQueryValueA((HKEY)RegHandle, KeyName,
  119. (char far*)Buffer, &BufferLength))
  120. #endif
  121. return(0);
  122. return(CopyString(Buffer));
  123. }
  124. static RPC_STATUS
  125. Bind(RPC_BINDING_HANDLE *NsiClntBinding
  126. )
  127. /*++
  128. Routine Description:
  129. Bind to the locator server
  130. Returns:
  131. RpcBindingFromStringBinding()
  132. --*/
  133. {
  134. RPC_STATUS status;
  135. unsigned char AddressBuffer[100];
  136. status = RpcStringFreeA(&NsiStringBinding);
  137. ASSERT(!status);
  138. // Get the next path componet from the NetworkAddress field.
  139. // Conponets are ; delimited fields.
  140. ASSERT(BindSearch.AddressOffset >= 0);
  141. for (int i = 0; i < sizeof(AddressBuffer); BindSearch.AddressOffset++, i++)
  142. {
  143. AddressBuffer[i] =
  144. BindSearch.NetworkAddress[BindSearch.AddressOffset];
  145. if (BindSearch.NetworkAddress[BindSearch.AddressOffset] == ';')
  146. {
  147. BindSearch.AddressOffset++;
  148. // If there are two ;; in a row, then pass through the ;
  149. // as a literal instead of a path seperator.
  150. if (BindSearch.NetworkAddress[BindSearch.AddressOffset] == ';')
  151. continue;
  152. AddressBuffer[i] = 0;
  153. break;
  154. }
  155. if (BindSearch.NetworkAddress[BindSearch.AddressOffset] == 0)
  156. {
  157. BindSearch.AddressOffset = NilOffset;
  158. break;
  159. }
  160. }
  161. status = RpcStringBindingComposeA(0, BindSearch.ProtoSeq,
  162. AddressBuffer, BindSearch.Endpoint,
  163. 0, &NsiStringBinding);
  164. if (status)
  165. return(status);
  166. return (RpcBindingFromStringBindingA(NsiStringBinding, NsiClntBinding));
  167. }
  168. RPC_STATUS RPC_ENTRY
  169. I_NsClientBindSearch(RPC_BINDING_HANDLE *NsiClntBinding, DWORD *BindId
  170. )
  171. /*++
  172. Routine Description:
  173. The function binds to the locator, first it tries to bind to a
  174. local machine, then it attempts to bind to the domain controller.
  175. Arguments:
  176. BindingSearchContext - context of search for the locator.
  177. Returns:
  178. RPC_S_OK, RPC_S_NO_BINDINGS, RPC_S_CANNOT_BIND, RPC_S_OUT_OF_RESOURCES
  179. rewritten to make it multi-thread capable. ushaji, Mar 98
  180. --*/
  181. {
  182. long status;
  183. #ifndef NTENV
  184. unsigned short cbSI;
  185. #define SERVER_INFO struct server_info_0
  186. #define ServerName(p) ((struct server_info_0 *)p)->sv0_name
  187. unsigned short Count = 1;
  188. QUERYLOCATORREPLY Reply, __RPC_FAR * QueryReply;
  189. #else
  190. #define SERVER_INFO SERVER_INFO_100
  191. #define ServerName(p) ((SERVER_INFO_100 *)p)->sv100_name
  192. #endif
  193. INIT_DOS_ALLOCATOR_IF_NECESSARY;
  194. RequestGlobalMutex();
  195. switch (BindSearch.State)
  196. {
  197. case BindingReadRegistry:
  198. if (BindSearch.RegHandle)
  199. {
  200. status = RegCloseKey(BindSearch.RegHandle);
  201. ASSERT(!status);
  202. BindSearch.RegHandle = 0;
  203. delete BindSearch.NetworkAddress;
  204. delete BindSearch.ProtoSeq;
  205. delete BindSearch.Endpoint;
  206. }
  207. memset(&BindSearch, 0, sizeof(RPC_LOCATOR_BIND_CONTEXT));
  208. // We store the binding information on the name service in
  209. // the registry. Get the information into BindingHandle.
  210. #ifdef NTENV
  211. status = RegOpenKeyExA(RPC_REG_ROOT, REG_NSI, 0L, KEY_READ,
  212. &BindSearch.RegHandle);
  213. #else
  214. status = RegOpenKeyA(RPC_REG_ROOT, REG_NSI, &BindSearch.RegHandle);
  215. #endif
  216. if (status) {
  217. status = RPC_S_NAME_SERVICE_UNAVAILABLE;
  218. break;
  219. }
  220. BindSearch.ProtoSeq = RegGetString((void *) BindSearch.RegHandle, "Protocol");
  221. BindSearch.NetworkAddress = RegGetString((void *) BindSearch.RegHandle,
  222. "NetworkAddress");
  223. BindSearch.Endpoint = RegGetString((void *) BindSearch.RegHandle, "Endpoint");
  224. GetDefaultEntrys((void *) BindSearch.RegHandle);
  225. if (!BindSearch.ProtoSeq || !BindSearch.Endpoint) {
  226. status = RPC_S_NAME_SERVICE_UNAVAILABLE;
  227. break;
  228. }
  229. #ifdef NTENV
  230. if (
  231. (BindSearch.NetworkAddress == NULL)
  232. || (BindSearch.NetworkAddress[0] == '\0')
  233. || (!strncmp((char *) BindSearch.NetworkAddress, LOCALLOCATOR,
  234. strlen(LOCALLOCATOR)))
  235. )
  236. {
  237. StartServiceIfNecessary();
  238. }
  239. #endif
  240. status = Bind(NsiClntBinding);
  241. if (status == RPC_S_OK) {
  242. BindSearch.State = BindingNotYetTried;
  243. GblBindId++;
  244. BindSearch.NextState = BindingContinueRegistry;
  245. }
  246. break;
  247. case BindingNotYetTried:
  248. case BindingFound:
  249. status = RpcBindingFromStringBindingA(NsiStringBinding, NsiClntBinding);
  250. break;
  251. case BindingContinueRegistry:
  252. if (BindSearch.AddressOffset != NilOffset) {
  253. status = Bind(NsiClntBinding);
  254. if (status == RPC_S_OK) {
  255. BindSearch.State = BindingNotYetTried;
  256. GblBindId++;
  257. }
  258. break;
  259. }
  260. #ifdef NTENV
  261. status = RPC_S_NAME_SERVICE_UNAVAILABLE;
  262. break;
  263. #else
  264. if (BindSearch.NetworkAddress)
  265. delete BindSearch.NetworkAddress;
  266. // Don't search the Net if we aren't looking for the locator.
  267. if (strcmp((char *)BindSearch.Endpoint, "\\pipe\\locator"))
  268. {
  269. status = RPC_S_NAME_SERVICE_UNAVAILABLE;
  270. break;
  271. }
  272. BindSearch.NetworkAddress = new unsigned char [MAX_SERVER_NAME];
  273. // second, try the domain controller
  274. if (NetGetDCName(0, 0, (char far *) BindSearch.NetworkAddress,
  275. MAX_SERVER_NAME))
  276. {
  277. status = RPC_S_NAME_SERVICE_UNAVAILABLE;
  278. break;
  279. }
  280. BindSearch.AddressOffset = 0;
  281. status = Bind(NsiClntBinding);
  282. if (status == RPC_S_OK)
  283. {
  284. GblBindId++;
  285. BindSearch.State = BindingNotYetTried;
  286. BindSearch.NextState = BindingBackupFirst;
  287. break;
  288. }
  289. break;
  290. case BindingBackupFirst:
  291. BindSearch.NumberServers = 0;
  292. // third, try all the member servers. First get the # of bytes
  293. // needed to hold all the names, then retrive them.
  294. NetServerEnum2(0, 0, 0, 0,
  295. (USHORT *) &BindSearch.NumberServers,
  296. (USHORT *) &BindSearch.NumberServers,
  297. SV_TYPE_DOMAIN_BAKCTRL, 0);
  298. cbSI = (BindSearch.NumberServers+2) * sizeof(SERVER_INFO);
  299. BindSearch.Buffer = new char [cbSI];
  300. BindSearch.ServerList = (char *) BindSearch.Buffer;
  301. if (!BindSearch.ServerList)
  302. {
  303. status = RPC_S_OUT_OF_RESOURCES;
  304. break;
  305. }
  306. if (NetServerEnum2(0, 0, (char far *)BindSearch.ServerList, cbSI,
  307. (USHORT *) &BindSearch.NumberServers,
  308. (USHORT *) &BindSearch.NumberServers,
  309. SV_TYPE_DOMAIN_BAKCTRL, 0))
  310. {
  311. delete BindSearch.Buffer;
  312. status = RPC_S_NAME_SERVICE_UNAVAILABLE;
  313. break;
  314. }
  315. case BindingBackup:
  316. if (BindSearch.NumberServers == 0)
  317. {
  318. delete BindSearch.Buffer;
  319. BindSearch.Buffer = new char [sizeof(QUERYLOCATORREPLY) *
  320. MAXLOCATORSTOTRY];
  321. if (BindSearch.Buffer == NULL)
  322. {
  323. status = RPC_S_NAME_SERVICE_UNAVAILABLE;
  324. break;
  325. }
  326. BindSearch.ServerList = (char *)BindSearch.Buffer;
  327. BindSearch.NumberServers = BroadcastAQuery(
  328. QUERY_DC_LOCATOR,
  329. (char __RPC_FAR *)BindSearch.Buffer,
  330. MAXLOCATORSTOTRY
  331. );
  332. }
  333. else
  334. {
  335. BindSearch.NumberServers--;
  336. BindSearch.NetworkAddress[0] = '\\';
  337. BindSearch.NetworkAddress[1] = '\\';
  338. strcpy((char far *)BindSearch.NetworkAddress+2,
  339. ServerName(BindSearch.ServerList));
  340. BindSearch.ServerList += sizeof(SERVER_INFO);
  341. BindSearch.AddressOffset = 0;
  342. status = Bind(NsiClntBinding);
  343. if (status == RPC_S_OK) {
  344. GblBindId++;
  345. BindSearch.NextState = BindSearch.State;
  346. BindSearch.State = BindingNotYetTried;
  347. }
  348. break;
  349. }
  350. case BindToBackupViaBC:
  351. if (BindSearch.NumberServers == 0)
  352. {
  353. //The buffer is already setup, use it for next phase
  354. BindSearch.NumberServers = BroadcastAQuery(
  355. QUERY_ANY_LOCATOR,
  356. (char __RPC_FAR *)BindSearch.Buffer,
  357. MAXLOCATORSTOTRY
  358. );
  359. BindSearch.State = BindToAnyViaBC;
  360. BindSearch.ServerList = (char *) BindSearch.Buffer;
  361. }
  362. else
  363. {
  364. BindSearch.NumberServers--;
  365. QueryReply = (QUERYLOCATORREPLY __RPC_FAR *)
  366. BindSearch.ServerList;
  367. UnicodeToAscii(QueryReply->SenderName);
  368. strcpy((char __RPC_FAR *) BindSearch.NetworkAddress,
  369. (char __RPC_FAR *)QueryReply->SenderName);
  370. BindSearch.ServerList = (char __RPC_FAR *)(QueryReply+1);
  371. BindSearch.AddressOffset = 0;
  372. status = Bind(NsiClntBinding);
  373. if (status == RPC_S_OK) {
  374. GblBindId++;
  375. BindSearch.NextState = BindSearch.State;
  376. BindSearch.State = BindingNotYetTried;
  377. }
  378. break;
  379. }
  380. //In the If case - we intentionally fall through to the
  381. //BindAny state.
  382. case BindToAnyViaBC:
  383. if (BindSearch.NumberServers == 0)
  384. {
  385. delete BindSearch.Buffer;
  386. status = RPC_S_NAME_SERVICE_UNAVAILABLE;
  387. }
  388. else
  389. {
  390. BindSearch.NumberServers--;
  391. QueryReply = (QUERYLOCATORREPLY __RPC_FAR *)
  392. BindSearch.ServerList;
  393. UnicodeToAscii(QueryReply->SenderName);
  394. strcpy((char __RPC_FAR *) BindSearch.NetworkAddress,
  395. (char __RPC_FAR *)QueryReply->SenderName);
  396. BindSearch.ServerList = (char __RPC_FAR *)(QueryReply+1);
  397. BindSearch.AddressOffset = 0;
  398. status = Bind(NsiClntBinding);
  399. if (status == RPC_S_OK) {
  400. GblBindId++;
  401. BindSearch.NextState = BindSearch.State;
  402. BindSearch.State = BindingNotYetTried;
  403. }
  404. }
  405. break;
  406. #endif
  407. default:
  408. ASSERT(!"Bad Search State");
  409. BindSearch.State = BindingReadRegistry;
  410. status = RPC_S_NAME_SERVICE_UNAVAILABLE;
  411. break;
  412. }
  413. *BindId = GblBindId;
  414. ClearGlobalMutex();
  415. return(status);
  416. }
  417. RPC_STATUS RPC_ENTRY
  418. I_NsBindingFoundBogus(RPC_BINDING_HANDLE *NsiClntBinding, DWORD BindId
  419. )
  420. {
  421. long status;
  422. if (*NsiClntBinding)
  423. {
  424. status = RpcBindingFree(NsiClntBinding);
  425. ASSERT(!status);
  426. }
  427. *NsiClntBinding = NULL;
  428. RequestGlobalMutex();
  429. switch (BindSearch.State)
  430. {
  431. case BindingNotYetTried:
  432. if (BindId == GblBindId)
  433. BindSearch.State = BindSearch.NextState;
  434. break;
  435. case BindingFound:
  436. if (BindId == GblBindId)
  437. BindSearch.State = BindingReadRegistry;
  438. break;
  439. default:
  440. break;
  441. }
  442. ClearGlobalMutex();
  443. return(RPC_S_OK);
  444. }
  445. void RPC_ENTRY
  446. I_NsClientBindDone(RPC_BINDING_HANDLE *NsiClntBinding, DWORD BindId
  447. )
  448. /*++
  449. Routine Description:
  450. The function cleans up after binding to the locator.
  451. Returns:
  452. --*/
  453. {
  454. long status;
  455. RPC_STATUS RpcStatus;
  456. RequestGlobalMutex();
  457. switch (BindSearch.State)
  458. {
  459. case BindingFound:
  460. break;
  461. case BindingReadRegistry:
  462. break;
  463. case BindingNotYetTried:
  464. if (BindId == GblBindId) {
  465. BindSearch.State = BindingFound;
  466. if (BindSearch.RegHandle)
  467. {
  468. status = RegCloseKey(BindSearch.RegHandle);
  469. ASSERT(!status);
  470. BindSearch.RegHandle = 0;
  471. delete BindSearch.NetworkAddress;
  472. delete BindSearch.ProtoSeq;
  473. delete BindSearch.Endpoint;
  474. }
  475. }
  476. break;
  477. case BindingContinueRegistry:
  478. if (BindId == GblBindId) {
  479. BindSearch.State = BindingReadRegistry;
  480. if (BindSearch.RegHandle)
  481. {
  482. status = RegCloseKey(BindSearch.RegHandle);
  483. ASSERT(!status);
  484. BindSearch.RegHandle = 0;
  485. delete BindSearch.NetworkAddress;
  486. delete BindSearch.ProtoSeq;
  487. delete BindSearch.Endpoint;
  488. }
  489. }
  490. break;
  491. #ifndef NTENV
  492. case BindToAnyViaBC:
  493. case BindToBackupViaBC:
  494. case BindingBackup:
  495. delete BindSearch.Buffer;
  496. case BindingBackupFirst:
  497. status = RegSetValue(BindSearch.RegHandle, "NetworkAddress",
  498. REG_SZ, (LPSTR) BindSearch.NetworkAddress,
  499. strlen((CONST_CHAR *)BindSearch.NetworkAddress) + 1);
  500. BindSearch.State = BindingFound;
  501. ASSERT(!status);
  502. break;
  503. #endif
  504. default:
  505. ASSERT(!"Bad State - \n");
  506. }
  507. #if defined(DOS) && !defined(WIN)
  508. // Unloaded the big fat lanman stuff now that we are done searching.
  509. RpcNsLmDiscard();
  510. #endif
  511. RpcStatus = RpcBindingFree(NsiClntBinding);
  512. ClearGlobalMutex();
  513. // ASSERT(!RpcStatus);
  514. }
  515. unsigned long RPC_ENTRY
  516. I_GetDefaultEntrySyntax(
  517. )
  518. /*++
  519. Routine Description:
  520. Called by the runtime DLL when it needs to know the default syntax.
  521. Currently this is used only by RpcBindingInqEntry().
  522. Arguments:
  523. none
  524. Return Value:
  525. the entry syntax
  526. Exceptions:
  527. none
  528. --*/
  529. {
  530. return (unsigned long) DefaultSyntax;
  531. }
  532. #ifndef NTENV
  533. unsigned short BroadcastAQuery(
  534. unsigned long Type,
  535. char __RPC_FAR * Buffer,
  536. unsigned short Count
  537. )
  538. {
  539. unsigned short Err;
  540. unsigned MSHandle;
  541. unsigned short Returned, NextSize, NextPri, Avail;
  542. unsigned short RetCount = 0;
  543. QUERYLOCATOR Query;
  544. unsigned long TimeRemaining = RESPONSETIME;
  545. wksta_info_10 __RPC_FAR * Wkio10;
  546. char __RPC_FAR * pBuf;
  547. unsigned short __RPC_FAR * pUZ;
  548. //First try and get the computer name
  549. Err = NetWkstaGetInfo(
  550. 0L,
  551. 10,
  552. (char __RPC_FAR *) 0L,
  553. 0,
  554. &Avail);
  555. ASSERT(Err == NERR_BufTooSmall);
  556. Wkio10 = (wksta_info_10 __RPC_FAR *) new char [Avail];
  557. if (Wkio10 == 0L)
  558. {
  559. return 0;
  560. }
  561. Err = NetWkstaGetInfo(
  562. 0L,
  563. 10,
  564. (char __RPC_FAR *) Wkio10,
  565. Avail,
  566. &Avail
  567. );
  568. //Format the Query!
  569. Query.MessageType = Type;
  570. Query.SenderOsType= OS_WIN31DOS;
  571. for (pBuf = &Wkio10->wki10_computername[0],pUZ = &Query.RequesterName[0];
  572. *pBuf !=0;
  573. pBuf++, pUZ++)
  574. *pUZ = *pBuf;
  575. *pUZ = 0;
  576. Err = DosMakeMailslot(
  577. LocalMS,
  578. sizeof(QUERYLOCATORREPLY),
  579. 0,
  580. &MSHandle
  581. );
  582. if (Err != NERR_Success)
  583. {
  584. return 0;
  585. }
  586. Err = DosWriteMailslot(
  587. MailslotName,
  588. (char __RPC_FAR *) &Query,
  589. sizeof(Query),
  590. 0, //Priority
  591. 2, //Class
  592. 0 //Timeout
  593. );
  594. if (Err != NERR_Success)
  595. goto CleanupAndExit;
  596. //Now sit in a loop and wait
  597. //for WAITRESPONSE secs
  598. while ((TimeRemaining) && (RetCount < Count))
  599. {
  600. Err = DosReadMailslot(
  601. MSHandle,
  602. Buffer,
  603. &Returned,
  604. &NextSize,
  605. &NextPri,
  606. TimeRemaining
  607. );
  608. if (Err == NERR_Success)
  609. {
  610. ASSERT (Returned == sizeof(QUERYLOCATORREPLY));
  611. Buffer += sizeof(QUERYLOCATORREPLY);
  612. RetCount ++;
  613. TimeRemaining >> 1;
  614. continue;
  615. }
  616. break;
  617. } //end of while ReadMS
  618. CleanupAndExit:
  619. DosDeleteMailslot(MSHandle);
  620. return (RetCount);
  621. }
  622. #endif