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.

1375 lines
33 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. Epts.c
  5. Abstract:
  6. Common code to listen to endpoints in the DCOM service.
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 6/16/1995 Bits 'n pieces
  11. Edwardr 7/17/1996 Added ncadg_mq
  12. Edwardr 5/01/1997 Added ncacn_http
  13. MazharM 10-12.98 Add pnp stuff
  14. KamenM Oct 2000 Removed ncadg_mq
  15. --*/
  16. //#define NCADG_MQ_ON
  17. //#define NETBIOS_ON
  18. #if !defined(_M_IA64)
  19. #define SPX_ON
  20. #endif
  21. //#define IPX_ON
  22. #if !defined(SPX_ON) && !defined(IPX_ON)
  23. #define SPX_IPX_OFF
  24. #endif
  25. #include <dcomss.h>
  26. #include <winsvc.h>
  27. #include <winsock2.h>
  28. #if !defined(SPX_IPX_OFF)
  29. #include <wsipx.h>
  30. #include <svcguid.h>
  31. #include "sap.h"
  32. #endif
  33. // Globals
  34. #if !defined(SPX_IPX_OFF)
  35. const IPX_BOGUS_NETWORK_NUMBER = 0xefcd3412;
  36. BOOL gfDelayedAdvertiseSaps = FALSE;
  37. typedef enum
  38. {
  39. SapStateUnknown,
  40. SapStateNoServices,
  41. SapStateEnabled,
  42. SapStateDisabled
  43. } SAP_STATE;
  44. SAP_STATE SapState = SapStateUnknown;
  45. #endif
  46. enum RegistryState
  47. {
  48. RegStateUnknown,
  49. RegStateMissing,
  50. RegStateYes,
  51. RegStateNo
  52. } RegistryState = RegStateUnknown;
  53. // Prototypes
  54. #if !defined(SPX_IPX_OFF)
  55. void AdvertiseNameWithSap(void);
  56. void CallSetService( SOCKADDR_IPX * pipxaddr, BOOL fRegister );
  57. #endif
  58. //
  59. // The index is the protseq tower id.
  60. //
  61. PROTSEQ_INFO
  62. gaProtseqInfo[] =
  63. {
  64. /* 0x00 */ { STOPPED, 0, 0 },
  65. /* 0x01 */ { STOPPED, 0, 0 },
  66. /* 0x02 */ { STOPPED, 0, 0 },
  67. /* 0x03 */ { STOPPED, 0, 0 },
  68. /* 0x04 */ { STOPPED, L"ncacn_dnet_nsp", L"#69" },
  69. /* 0x05 */ { STOPPED, 0, 0 },
  70. /* 0x06 */ { STOPPED, 0, 0 },
  71. /* 0x07 */ { STOPPED, L"ncacn_ip_tcp", L"135" },
  72. /* 0x08 */ { STOPPED, L"ncadg_ip_udp", L"135" },
  73. #ifdef NETBIOS_ON
  74. /* 0x09 */ { STOPPED, L"ncacn_nb_tcp", L"135" },
  75. #else
  76. /* 0x09 */ { STOPPED, 0, 0 },
  77. #endif
  78. /* 0x0a */ { STOPPED, 0, 0 },
  79. /* 0x0b */ { STOPPED, 0, 0 },
  80. #if defined(SPX_ON)
  81. /* 0x0c */ { STOPPED, L"ncacn_spx", L"34280" },
  82. #else
  83. /* 0x0c */ { STOPPED, 0, 0 },
  84. #endif
  85. #ifdef NETBIOS_ON
  86. /* 0x0d */ { STOPPED, L"ncacn_nb_ipx", L"135" },
  87. #else
  88. /* 0x0d */ { STOPPED, 0, 0 },
  89. #endif
  90. /* 0x0e */ { STOPPED, L"ncadg_ipx", L"34280" },
  91. /* 0x0f */ { STOPPED, L"ncacn_np", L"\\pipe\\epmapper" },
  92. /* 0x10 */ { STOPPED, L"ncalrpc", L"epmapper" },
  93. /* 0x11 */ { STOPPED, 0, 0 },
  94. /* 0x12 */ { STOPPED, 0, 0 },
  95. #ifdef NETBIOS_ON
  96. /* 0x13 */ { STOPPED, L"ncacn_nb_nb", L"135" },
  97. #else
  98. /* 0x13 */ { STOPPED, 0, 0 },
  99. #endif
  100. /* 0x14 */ { STOPPED, 0, 0 },
  101. /* 0x15 */ { STOPPED, 0, 0 }, // was ncacn_nb_xns - unsupported.
  102. /* 0x16 */ { STOPPED, L"ncacn_at_dsp", L"Endpoint Mapper" },
  103. /* 0x17 */ { STOPPED, L"ncadg_at_ddp", L"Endpoint Mapper" },
  104. /* 0x18 */ { STOPPED, 0, 0 },
  105. /* 0x19 */ { STOPPED, 0, 0 },
  106. /* 0x1A */ { STOPPED, 0, 0 },
  107. /* 0x1B */ { STOPPED, 0, 0 },
  108. /* 0x1C */ { STOPPED, 0, 0 },
  109. #ifdef NCADG_MQ_ON
  110. /* 0x1D */ { STOPPED, L"ncadg_mq", L"EpMapper"},
  111. #else
  112. /* 0x1D */ { STOPPED, 0, 0 },
  113. #endif
  114. /* 0x1E */ { STOPPED, 0, 0 },
  115. /* 0x1F */ { STOPPED, L"ncacn_http", L"593" }, // dcomhttp port assigned by IANA
  116. /* 0x20 */ { STOPPED, 0, 0 },
  117. };
  118. #define PROTSEQ_IDS (sizeof(gaProtseqInfo)/sizeof(PROTSEQ_INFO))
  119. #define ID_LPC (0x10)
  120. #define ID_IPX (0x0E)
  121. #if defined(SPX_ON)
  122. #define ID_SPX (0x0C)
  123. #endif
  124. #define ID_HTTP (0x1F)
  125. #define ID_TCP (0x07)
  126. // Do not listen on all NICs by default.
  127. // A reg key can be used to override this and listen on all NICs, but
  128. // the override will break DG dynamic endpoint functionality when selective
  129. // binding is enabled.
  130. BOOL fListenOnInternet = FALSE; // see bug 69332 (in old nt raid db)
  131. BOOL
  132. CreateSids(
  133. PSID* ppsidBuiltInAdministrators,
  134. PSID* ppsidSystem,
  135. PSID* ppsidWorld
  136. )
  137. /*++
  138. Routine Description:
  139. Creates and return pointers to three SIDs one for each of World,
  140. Local Administrators, and System.
  141. Arguments:
  142. ppsidBuiltInAdministrators - Receives pointer to SID representing local
  143. administrators;
  144. ppsidSystem - Receives pointer to SID representing System;
  145. ppsidWorld - Receives pointer to SID representing World.
  146. Return Value:
  147. BOOL indicating success (TRUE) or failure (FALSE).
  148. Caller must free returned SIDs by calling FreeSid() for each returned
  149. SID when this function return TRUE; pointers should be assumed garbage
  150. when the function returns FALSE.
  151. --*/
  152. {
  153. //
  154. // An SID is built from an Identifier Authority and a set of Relative IDs
  155. // (RIDs). The Authority of interest to us SECURITY_NT_AUTHORITY.
  156. //
  157. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  158. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  159. //
  160. // Each RID represents a sub-unit of the authority. Local
  161. // Administrators is in the "built in" domain. The other SIDs, for
  162. // Authenticated users and system, is based directly off of the
  163. // authority.
  164. //
  165. // For examples of other useful SIDs consult the list in
  166. // \nt\public\sdk\inc\ntseapi.h.
  167. //
  168. if (!AllocateAndInitializeSid(&NtAuthority,
  169. 2, // 2 sub-authorities
  170. SECURITY_BUILTIN_DOMAIN_RID,
  171. DOMAIN_ALIAS_RID_ADMINS,
  172. 0,0,0,0,0,0,
  173. ppsidBuiltInAdministrators)) {
  174. // error
  175. } else if (!AllocateAndInitializeSid(&NtAuthority,
  176. 1, // 1 sub-authorities
  177. SECURITY_LOCAL_SYSTEM_RID,
  178. 0,0,0,0,0,0,0,
  179. ppsidSystem)) {
  180. // error
  181. FreeSid(*ppsidBuiltInAdministrators);
  182. *ppsidBuiltInAdministrators = NULL;
  183. } else if (!AllocateAndInitializeSid(&WorldAuthority,
  184. 1, // 1 sub-authority
  185. SECURITY_WORLD_RID,
  186. 0,0,0,0,0,0,0,
  187. ppsidWorld)) {
  188. // error
  189. FreeSid(*ppsidBuiltInAdministrators);
  190. *ppsidBuiltInAdministrators = NULL;
  191. FreeSid(*ppsidSystem);
  192. *ppsidSystem = NULL;
  193. } else {
  194. return TRUE;
  195. }
  196. return FALSE;
  197. }
  198. PSECURITY_DESCRIPTOR
  199. CreateSd(
  200. VOID
  201. )
  202. /*++
  203. Routine Description:
  204. Creates and return a SECURITY_DESCRIPTOR with a DACL granting
  205. (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | SYNCHRONIZE) to World,
  206. and GENERIC_ALL to Local Administrators and System.
  207. Arguments:
  208. None
  209. Return Value:
  210. Pointer to the created SECURITY_DESCRIPTOR, or NULL if an error occurred.
  211. Caller must free returned SECURITY_DESCRIPTOR back to process heap by
  212. a call to HeapFree.
  213. --*/
  214. {
  215. PSID psidWorld;
  216. PSID psidBuiltInAdministrators;
  217. PSID psidSystem;
  218. if (!CreateSids(&psidBuiltInAdministrators,
  219. &psidSystem,
  220. &psidWorld)) {
  221. // error
  222. } else {
  223. //
  224. // Calculate the size of and allocate a buffer for the DACL, we need
  225. // this value independently of the total alloc size for ACL init.
  226. //
  227. PSECURITY_DESCRIPTOR Sd = NULL;
  228. ULONG AclSize;
  229. //
  230. // "- sizeof (ULONG)" represents the SidStart field of the
  231. // ACCESS_ALLOWED_ACE. Since we're adding the entire length of the
  232. // SID, this field is counted twice.
  233. //
  234. AclSize = sizeof (ACL) +
  235. (3 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (ULONG))) +
  236. GetLengthSid(psidWorld) +
  237. GetLengthSid(psidBuiltInAdministrators) +
  238. GetLengthSid(psidSystem);
  239. Sd = HeapAlloc(GetProcessHeap(),
  240. 0,
  241. SECURITY_DESCRIPTOR_MIN_LENGTH + AclSize);
  242. if (!Sd) {
  243. // error
  244. } else {
  245. ACL *Acl;
  246. Acl = (ACL *)((BYTE *)Sd + SECURITY_DESCRIPTOR_MIN_LENGTH);
  247. if (!InitializeAcl(Acl,
  248. AclSize,
  249. ACL_REVISION)) {
  250. // error
  251. } else if (!AddAccessAllowedAce(Acl,
  252. ACL_REVISION,
  253. SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
  254. psidWorld)) {
  255. // Failed to build the ACE granting "WORLD"
  256. // (SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE) access.
  257. } else if (!AddAccessAllowedAce(Acl,
  258. ACL_REVISION,
  259. GENERIC_ALL,
  260. psidBuiltInAdministrators)) {
  261. // Failed to build the ACE granting "Built-in Administrators"
  262. // (GENERIC_ALL) access.
  263. } else if (!AddAccessAllowedAce(Acl,
  264. ACL_REVISION,
  265. GENERIC_ALL,
  266. psidSystem)) {
  267. // Failed to build the ACE granting "System"
  268. // GENERIC_ALL access.
  269. } else if (!InitializeSecurityDescriptor(Sd,
  270. SECURITY_DESCRIPTOR_REVISION)) {
  271. // error
  272. } else if (!SetSecurityDescriptorDacl(Sd,
  273. TRUE,
  274. Acl,
  275. FALSE)) {
  276. // error
  277. } else {
  278. FreeSid(psidWorld);
  279. FreeSid(psidBuiltInAdministrators);
  280. FreeSid(psidSystem);
  281. return Sd;
  282. }
  283. HeapFree(GetProcessHeap(),
  284. 0,
  285. Sd);
  286. }
  287. FreeSid(psidWorld);
  288. FreeSid(psidBuiltInAdministrators);
  289. FreeSid(psidSystem);
  290. }
  291. return NULL;
  292. }
  293. RPC_STATUS
  294. UseProtseqIfNecessary(
  295. IN USHORT id
  296. )
  297. /*++
  298. Routine Description:
  299. Listens to the well known RPC endpoint mapper endpoint
  300. for the protseq. Returns very quickly if the process
  301. is already listening to the protseq.
  302. Arguments:
  303. id - the tower id of protseq. See GetProtseqId() if you don't
  304. already have this value.
  305. Return Value:
  306. RPC_S_OK - no errors occured.
  307. RPC_S_OUT_OF_RESOURCES - when we're unable to setup security for the endpoint.
  308. RPC_S_INVALID_RPC_PROTSEQ - if id is unknown/invalid.
  309. Any error from RpcServerUseProtseqEp.
  310. --*/
  311. {
  312. RPC_STATUS status = RPC_S_OK;
  313. SECURITY_DESCRIPTOR *psd = NULL;
  314. RPC_POLICY Policy;
  315. Policy.Length = sizeof(RPC_POLICY);
  316. Policy.EndpointFlags = 0;
  317. if (fListenOnInternet)
  318. {
  319. Policy.NICFlags = RPC_C_BIND_TO_ALL_NICS;
  320. }
  321. else
  322. {
  323. Policy.NICFlags = 0;
  324. }
  325. ASSERT(id);
  326. if (id == 0 || id >= PROTSEQ_IDS)
  327. {
  328. ASSERT(0);
  329. return(RPC_S_INVALID_RPC_PROTSEQ);
  330. }
  331. if (gaProtseqInfo[id].state == STARTED)
  332. {
  333. return(RPC_S_OK);
  334. }
  335. if (id == ID_LPC)
  336. {
  337. // ncalrpc needs a security descriptor.
  338. psd = CreateSd();
  339. if ( NULL == psd )
  340. {
  341. status = RPC_S_OUT_OF_RESOURCES;
  342. }
  343. }
  344. else
  345. {
  346. psd = NULL;
  347. }
  348. if (status == RPC_S_OK )
  349. {
  350. status = RpcServerUseProtseqEpEx(gaProtseqInfo[id].pwstrProtseq,
  351. RPC_C_PROTSEQ_MAX_REQS_DEFAULT + 40,
  352. gaProtseqInfo[id].pwstrEndpoint,
  353. psd,
  354. &Policy);
  355. if ( NULL != psd )
  356. {
  357. HeapFree(GetProcessHeap(),
  358. 0,
  359. psd);
  360. psd = NULL;
  361. }
  362. // No locking is done here, the RPC runtime may return duplicate
  363. // endpoint if two threads call this at the same time.
  364. if (status == RPC_S_DUPLICATE_ENDPOINT)
  365. {
  366. status = RPC_S_OK;
  367. }
  368. #ifdef DEBUGRPC
  369. if (status != RPC_S_OK)
  370. {
  371. KdPrintEx((DPFLTR_DCOMSS_ID,
  372. DPFLTR_WARNING_LEVEL,
  373. "DCOMSS: Unable to listen to %S (0x%x)\n",
  374. gaProtseqInfo[id].pwstrProtseq,
  375. status));
  376. }
  377. #endif
  378. if (status == RPC_S_OK)
  379. {
  380. gaProtseqInfo[id].state = STARTED;
  381. #if !defined(SPX_IPX_OFF)
  382. if (
  383. #if defined(IPX_ON)
  384. (id == ID_IPX)
  385. ||
  386. #endif
  387. #if defined(SPX_ON)
  388. (id == ID_SPX)
  389. #endif
  390. )
  391. {
  392. UpdateSap(SAP_CTRL_MAYBE_REGISTER);
  393. }
  394. #endif
  395. }
  396. }
  397. return(status);
  398. }
  399. PWSTR
  400. GetProtseq(
  401. IN USHORT ProtseqId
  402. )
  403. /*++
  404. Routine Description:
  405. Returns the unicode protseq give the protseqs tower id.
  406. Arguments:
  407. ProtseqId - Tower id of the protseq in question.
  408. Return Value:
  409. NULL if the id is invalid.
  410. non-NULL if the id is valid - note the pointer doesn't need to be freed.
  411. --*/
  412. {
  413. ASSERT(ProtseqId);
  414. if (ProtseqId < PROTSEQ_IDS)
  415. {
  416. return(gaProtseqInfo[ProtseqId].pwstrProtseq);
  417. }
  418. return(0);
  419. }
  420. PWSTR
  421. GetEndpoint(
  422. IN USHORT ProtseqId
  423. )
  424. /*++
  425. Routine Description:
  426. Returns the well known endpoint associated with the protseq.
  427. Arguments:
  428. ProtseqId - the id (See GetProtseqId()) of the protseq in question.
  429. Return Value:
  430. 0 - Unknown/invalid id.
  431. !0 - The endpoint associated with the protseq.
  432. note: should not be freed.
  433. --*/
  434. {
  435. ASSERT(ProtseqId);
  436. if (ProtseqId < PROTSEQ_IDS)
  437. {
  438. return(gaProtseqInfo[ProtseqId].pwstrEndpoint);
  439. }
  440. return(0);
  441. }
  442. USHORT
  443. GetProtseqId(
  444. IN PWSTR Protseq
  445. )
  446. /*++
  447. Routine Description:
  448. Returns the tower id for a protseq.
  449. This could be changed to a faster search, but remember that
  450. eventually the table will NOT be static. (ie. we can't just
  451. create a perfect hash based on the static table).
  452. Arguments:
  453. Protseq - a unicode protseq to lookup. It is assumed
  454. to be non-null.
  455. Return Value:
  456. 0 - unknown/invalid protseq
  457. non-zero - the id.
  458. --*/
  459. {
  460. int i;
  461. ASSERT(Protseq);
  462. for(i = 1; i < PROTSEQ_IDS; i++)
  463. {
  464. if ( 0 != gaProtseqInfo[i].pwstrProtseq
  465. && 0 == lstrcmpW(gaProtseqInfo[i].pwstrProtseq, Protseq))
  466. {
  467. return((USHORT)i);
  468. }
  469. }
  470. return(0);
  471. }
  472. USHORT
  473. GetProtseqIdAnsi(
  474. IN PSTR pstrProtseq
  475. )
  476. /*++
  477. Routine Description:
  478. Returns the tower id for a protseq.
  479. This could be changed to a faster search, but remember that
  480. eventually the table will NOT be static. (ie. we can't just
  481. create a perfect hash based on the static table).
  482. Arguments:
  483. Protseq - an ansi (8 bit char) protseq to lookup. It is assumed
  484. to be non-null.
  485. Return Value:
  486. 0 - unknown/invalid protseq
  487. non-zero - the id.
  488. --*/
  489. {
  490. int i;
  491. ASSERT(pstrProtseq);
  492. for(i = 1; i < PROTSEQ_IDS; i++)
  493. {
  494. if (0 != gaProtseqInfo[i].pwstrProtseq)
  495. {
  496. PWSTR pwstrProtseq = gaProtseqInfo[i].pwstrProtseq;
  497. PSTR pstrT = pstrProtseq;
  498. while(*pstrT && *pwstrProtseq && *pstrT == *pwstrProtseq)
  499. {
  500. pstrT++;
  501. pwstrProtseq++;
  502. }
  503. if (*pstrT == *pwstrProtseq)
  504. {
  505. return((USHORT)i);
  506. }
  507. }
  508. }
  509. return(0);
  510. }
  511. const PWSTR NICConfigKey = L"System\\CurrentControlSet\\Services\\RpcSs";
  512. const PWSTR ListenOnInternet = L"ListenOnInternet";
  513. RPC_STATUS
  514. InitializeEndpointManager(
  515. VOID
  516. )
  517. /*++
  518. Routine Description:
  519. Called when the dcom service starts.
  520. Arguments:
  521. None
  522. Return Value:
  523. RPC_S_OUT_OF_MEMORY - if needed
  524. RPC_S_OUT_OF_RESOURCES - usually on registry failures.
  525. --*/
  526. {
  527. HKEY hkey;
  528. DWORD size, type, value;
  529. RPC_STATUS status;
  530. status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  531. (PWSTR)NICConfigKey,
  532. 0,
  533. KEY_READ,
  534. &hkey);
  535. if (status != RPC_S_OK)
  536. {
  537. ASSERT(status == ERROR_FILE_NOT_FOUND);
  538. return(RPC_S_OK);
  539. }
  540. size = sizeof(value);
  541. status = RegQueryValueExW(hkey,
  542. (PWSTR)ListenOnInternet,
  543. 0,
  544. &type,
  545. (PBYTE)&value,
  546. &size);
  547. if ( status == RPC_S_OK )
  548. {
  549. if ((type != REG_SZ)
  550. || (*(PWSTR)&value != 'Y'
  551. && *(PWSTR)&value != 'y'
  552. && *(PWSTR)&value != 'N'
  553. && *(PWSTR)&value != 'n'))
  554. {
  555. goto Cleanup;
  556. }
  557. if (*(PWSTR)&value == 'Y'
  558. || *(PWSTR)&value == 'y')
  559. {
  560. fListenOnInternet = TRUE;
  561. }
  562. else
  563. {
  564. fListenOnInternet = FALSE;
  565. }
  566. }
  567. Cleanup:
  568. RegCloseKey(hkey);
  569. return(RPC_S_OK);
  570. }
  571. BOOL
  572. IsLocal(
  573. IN USHORT ProtseqId
  574. )
  575. /*++
  576. Routine Description:
  577. Determines if the protseq id is local-only. (ncalrpc)
  578. Arguments:
  579. ProtseqId - The id of the protseq in question.
  580. Return Value:
  581. TRUE - if the protseq id is local-only
  582. FALSE - if the protseq id invalid or available remotely.
  583. --*/
  584. {
  585. return(ProtseqId == ID_LPC);
  586. }
  587. RPC_STATUS
  588. DelayedUseProtseq(
  589. IN USHORT id
  590. )
  591. /*++
  592. Routine Description:
  593. If the protseq is not being used its state is changed
  594. so that a callto CompleteDelayedUseProtseqs() will actually
  595. cause the server to listen to the protseq.
  596. This is called when an RPC server registers an dynamic
  597. endpoint on this protocol.
  598. Arguments:
  599. id - the id of the protseq you wish to listen to.
  600. Return Value:
  601. 0 - normally
  602. RPC_S_INVALID_RPC_PROTSEQ - if id is invalid.
  603. --*/
  604. {
  605. #if !defined(SPX_IPX_OFF)
  606. // For IPX and SPX
  607. if (
  608. #if defined(IPX_ON)
  609. (id == ID_IPX)
  610. ||
  611. #endif
  612. #if defined(SPX_ON)
  613. (id == ID_SPX)
  614. #endif
  615. )
  616. {
  617. gfDelayedAdvertiseSaps = TRUE;
  618. }
  619. #endif
  620. if (id < PROTSEQ_IDS)
  621. {
  622. if (gaProtseqInfo[id].pwstrProtseq != 0)
  623. {
  624. if (gaProtseqInfo[id].state == STOPPED)
  625. gaProtseqInfo[id].state = START;
  626. return(RPC_S_OK);
  627. }
  628. }
  629. return(RPC_S_INVALID_RPC_PROTSEQ);
  630. }
  631. VOID
  632. CompleteDelayedUseProtseqs(
  633. VOID
  634. )
  635. /*++
  636. Routine Description:
  637. Start listening to any protseqs previously passed
  638. to DelayedUseProtseq(). No errors are returned,
  639. but informationals are printed on debug builds.
  640. Arguments:
  641. None
  642. Return Value:
  643. None
  644. --*/
  645. {
  646. USHORT i;
  647. for(i = 1; i < PROTSEQ_IDS; i++)
  648. {
  649. if (START == gaProtseqInfo[i].state)
  650. {
  651. RPC_STATUS status = UseProtseqIfNecessary(i);
  652. #ifdef DEBUGRPC
  653. if (RPC_S_OK == status)
  654. ASSERT(gaProtseqInfo[i].state == STARTED);
  655. #endif
  656. }
  657. }
  658. #if !defined(SPX_IPX_OFF)
  659. if (gfDelayedAdvertiseSaps)
  660. {
  661. gfDelayedAdvertiseSaps = FALSE;
  662. UpdateSap(SAP_CTRL_MAYBE_REGISTER);
  663. }
  664. #endif
  665. }
  666. #if !defined(SPX_IPX_OFF)
  667. RPC_STATUS
  668. ServiceInstalled(
  669. PWSTR ServiceName
  670. )
  671. /*++
  672. Routine Description:
  673. Tests if a service is installed.
  674. Arguments:
  675. ServiceName - The unicode name (short or long) of the service
  676. to check.
  677. Return Value:
  678. 0 - service installed
  679. ERROR_SERVICE_DOES_NOT_EXIST - service not installed
  680. other - parameter or resource problem
  681. --*/
  682. {
  683. SC_HANDLE ScHandle;
  684. SC_HANDLE ServiceHandle;
  685. ScHandle = OpenSCManagerW(0, 0, GENERIC_READ);
  686. if (ScHandle == 0)
  687. {
  688. return(ERROR_SERVICE_DOES_NOT_EXIST);
  689. }
  690. ServiceHandle = OpenService(ScHandle, ServiceName, GENERIC_READ);
  691. if (ServiceHandle == 0)
  692. {
  693. #if DBG
  694. if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
  695. {
  696. KdPrintEx((DPFLTR_DCOMSS_ID,
  697. DPFLTR_WARNING_LEVEL,
  698. "OR: Failed %d opening the %S service\n",
  699. GetLastError(),
  700. ServiceName));
  701. }
  702. #endif
  703. CloseServiceHandle(ScHandle);
  704. return(ERROR_SERVICE_DOES_NOT_EXIST);
  705. }
  706. // Service installed
  707. CloseServiceHandle(ScHandle);
  708. CloseServiceHandle(ServiceHandle);
  709. return(RPC_S_OK);
  710. }
  711. const GUID RPC_SAP_SERVICE_TYPE = SVCID_NETWARE(0x640);
  712. void
  713. UpdateSap(
  714. enum SAP_CONTROL_TYPE action
  715. )
  716. /*++
  717. Routine Description:
  718. Starts, stops, or updates the periodic SPX SAP broadcasts that allow an RPC
  719. client to map the server name to an IPX address. To understand IPX and SAP,
  720. read "IPX Router Specification", Novell part # 107-000029-001.
  721. A SAP broadcast will be processed by several categories of machines
  722. - all machines in the local subnet(s) will have to read and discard the packet
  723. - routers connected to the local subnet(s) will add the data to the info they
  724. periodically exchange with other routers
  725. - Netware-compatible servers will add the info to their Bindery tables.
  726. That is why not all NT machines should SAP.
  727. Arguments:
  728. action:
  729. SAP_CTRL_FORCE_REGISTER: begin sapping
  730. SAP_CTRL_MAYBE_REGISTER: begin sapping only if the Netware-compatible
  731. workstation and/or the SAP Agent service is
  732. installed. File/Print Svcs for Netware forces the
  733. SAP Agent, so it too will enable sapping.
  734. SAP_CTRL_UPDATE_ADDRESS: a net card was added or subtracted, or the network
  735. address changed. Re-register if sapping is already
  736. active.
  737. SAP_CTRL_UNREGISTER: stop sapping
  738. --*/
  739. {
  740. DWORD status;
  741. HKEY hKey;
  742. // Service paramaters
  743. NT_PRODUCT_TYPE type;
  744. if (RegistryState == RegStateUnknown)
  745. {
  746. // The registry key has absolute control of SAPing
  747. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  748. TEXT("Software\\Microsoft\\Rpc"),
  749. 0,
  750. KEY_READ,
  751. &hKey);
  752. if (status == ERROR_SUCCESS)
  753. {
  754. WCHAR pwstrValue[8];
  755. DWORD dwType, dwLenBuffer;
  756. dwLenBuffer = sizeof(pwstrValue);
  757. status = RegQueryValueEx(hKey,
  758. TEXT("AdvertiseRpcService"),
  759. 0,
  760. &dwType,
  761. (PBYTE)pwstrValue,
  762. &dwLenBuffer
  763. );
  764. if ( status == ERROR_SUCCESS
  765. && dwType == REG_SZ)
  766. {
  767. if ( pwstrValue[0] == 'y'
  768. || pwstrValue[0] == 'Y' )
  769. {
  770. RegistryState = RegStateYes;
  771. }
  772. else if ( pwstrValue[0] == 'n'
  773. || pwstrValue[0] == 'N' )
  774. {
  775. RegistryState = RegStateNo;
  776. }
  777. else
  778. {
  779. // Value in the registry is wrong, pretend it doesn't exist.
  780. RegistryState = RegStateMissing;
  781. }
  782. }
  783. else
  784. {
  785. // Bad or missing value in the registry, pretend is doesn't exist.
  786. RegistryState = RegStateMissing;
  787. }
  788. RegCloseKey(hKey);
  789. }
  790. }
  791. switch (action)
  792. {
  793. case SAP_CTRL_FORCE_REGISTER:
  794. if (RegistryState == RegStateNo)
  795. {
  796. // "no" in registry trumps any registration
  797. return;
  798. }
  799. if (SapState == SapStateEnabled)
  800. {
  801. // already active
  802. return;
  803. }
  804. break;
  805. case SAP_CTRL_MAYBE_REGISTER:
  806. if (RegistryState == RegStateNo)
  807. {
  808. // "no" in registry trumps any registration
  809. return;
  810. }
  811. if (SapState == SapStateEnabled)
  812. {
  813. // already registered
  814. return;
  815. }
  816. if (RegistryState == RegStateYes)
  817. {
  818. // don't check services, just register.
  819. break;
  820. }
  821. if (SapState == SapStateNoServices)
  822. {
  823. ASSERT( RegistryState != RegStateYes ); // in case checks are rearranged
  824. // the appropriate services are not installed
  825. return;
  826. }
  827. //
  828. // Getting here means we don't know yet whether the proper services are installed.
  829. //
  830. // Depending on configuration, this controls if automatic
  831. // listens (due to DCOM configuration) enable SAPing or not.
  832. type = NtProductWinNt;
  833. RtlGetNtProductType(&type);
  834. status = ERROR_SERVICE_DOES_NOT_EXIST;
  835. if (type != NtProductWinNt)
  836. {
  837. // Server platform, try NWCWorkstation
  838. status = ServiceInstalled(L"NWCWorkstation");
  839. }
  840. if (status == ERROR_SERVICE_DOES_NOT_EXIST)
  841. {
  842. status = ServiceInstalled(L"NwSapAgent");
  843. }
  844. if (status == ERROR_SERVICE_DOES_NOT_EXIST)
  845. {
  846. SapState = SapStateNoServices;
  847. return;
  848. }
  849. //
  850. // Proper services are installed.
  851. //
  852. break;
  853. case SAP_CTRL_UPDATE_ADDRESS:
  854. if (SapState != SapStateEnabled)
  855. {
  856. return;
  857. }
  858. break;
  859. case SAP_CTRL_UNREGISTER:
  860. if (SapState == SapStateDisabled ||
  861. SapState == SapStateNoServices)
  862. {
  863. // already not registered
  864. }
  865. break;
  866. default:
  867. ASSERT( 0 );
  868. }
  869. AdvertiseNameWithSap();
  870. }
  871. void
  872. AdvertiseNameWithSap()
  873. /*++
  874. Parameters:
  875. Description:
  876. Returns:
  877. --*/
  878. {
  879. // winsock (socket, bind, getsockname) parameters
  880. SOCKADDR_IPX new_ipxaddr;
  881. static SOCKADDR_IPX old_ipxaddr = { AF_IPX, { 0 }, { 0 }, 0 } ;
  882. static CRITICAL_SECTION * pCritsec;
  883. SOCKET s;
  884. int err;
  885. int size;
  886. //
  887. // A critical section protects old_ipxaddr since several different events lead to
  888. // calling this function. The following code makes sure that the critical
  889. // section is created, and that all threads are using the same one.
  890. //
  891. if (!pCritsec)
  892. {
  893. CRITICAL_SECTION * myCritsec = HeapAlloc( GetProcessHeap(), 0, sizeof(CRITICAL_SECTION));
  894. if (!myCritsec)
  895. {
  896. return;
  897. }
  898. err = RtlInitializeCriticalSection( myCritsec );
  899. if (!NT_SUCCESS(err))
  900. {
  901. HeapFree(GetProcessHeap(), 0, myCritsec);
  902. return;
  903. }
  904. myCritsec = (CRITICAL_SECTION *) InterlockedExchangePointer( (PVOID *) &pCritsec, myCritsec );
  905. if (myCritsec)
  906. {
  907. HeapFree(GetProcessHeap(), 0, myCritsec);
  908. }
  909. }
  910. //
  911. // Get this server's IPX address.
  912. //
  913. s = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
  914. if (s != -1)
  915. {
  916. size = sizeof(new_ipxaddr);
  917. memset(&new_ipxaddr, 0, sizeof(new_ipxaddr));
  918. new_ipxaddr.sa_family = AF_IPX;
  919. err = bind(s, (struct sockaddr *)&new_ipxaddr, sizeof(new_ipxaddr));
  920. if (err == 0)
  921. {
  922. err = getsockname(s, (struct sockaddr *)&new_ipxaddr, &size);
  923. }
  924. }
  925. else
  926. {
  927. err = -1;
  928. }
  929. if (err != 0)
  930. {
  931. KdPrintEx((DPFLTR_DCOMSS_ID,
  932. DPFLTR_WARNING_LEVEL,
  933. "OR: socket() or getsockname() failed %d, aborting SAP setup\n",
  934. GetLastError()));
  935. return;
  936. }
  937. if (s != -1)
  938. {
  939. closesocket(s);
  940. }
  941. EnterCriticalSection( pCritsec );
  942. if (0 != memcmp( old_ipxaddr.sa_netnum, new_ipxaddr.sa_netnum, sizeof(old_ipxaddr.sa_netnum)) ||
  943. 0 != memcmp( old_ipxaddr.sa_nodenum, new_ipxaddr.sa_nodenum, sizeof(old_ipxaddr.sa_nodenum)))
  944. {
  945. memcpy( &old_ipxaddr, &new_ipxaddr, sizeof(old_ipxaddr) );
  946. LeaveCriticalSection( pCritsec );
  947. if (*((long *) &new_ipxaddr.sa_netnum) != IPX_BOGUS_NETWORK_NUMBER)
  948. {
  949. CallSetService( &new_ipxaddr, TRUE);
  950. }
  951. else
  952. {
  953. KdPrintEx((DPFLTR_DCOMSS_ID,
  954. DPFLTR_WARNING_LEVEL,
  955. "OR: SPX net number is bogus. Not registering until a real address arrives. \n"));
  956. CallSetService( &new_ipxaddr, FALSE);
  957. }
  958. }
  959. else
  960. {
  961. LeaveCriticalSection( pCritsec );
  962. }
  963. }
  964. void
  965. CallSetService(
  966. SOCKADDR_IPX * pipxaddr,
  967. BOOL fRegister
  968. )
  969. /*++
  970. Function Name:CallSetService
  971. Parameters:
  972. Description:
  973. Returns:
  974. --*/
  975. {
  976. DWORD ignore;
  977. DWORD status;
  978. // SetService params
  979. WSAQUERYSETW info;
  980. CSADDR_INFO addresses;
  981. // GetComputerName parameters
  982. static WCHAR buffer[MAX_COMPUTERNAME_LENGTH + 1];
  983. static BOOL bufferValid = FALSE;
  984. if (!bufferValid)
  985. {
  986. // Get this server's name
  987. ignore = MAX_COMPUTERNAME_LENGTH + 1;
  988. if (!GetComputerNameW(buffer, &ignore))
  989. {
  990. return;
  991. }
  992. bufferValid = TRUE;
  993. }
  994. // We'll register only for the endpoint mapper port. The port
  995. // value is not required but should be the same to avoid
  996. // confusing routers keeping track of SAPs...
  997. pipxaddr->sa_socket = htons(34280);
  998. // Fill in the service info structure.
  999. memset(&info, 0, sizeof(info));
  1000. info.dwSize = sizeof(info);
  1001. info.lpszServiceInstanceName = buffer;
  1002. info.lpServiceClassId = (GUID *)&RPC_SAP_SERVICE_TYPE;
  1003. info.lpszComment = L"RPC Services";
  1004. info.dwNameSpace = NS_SAP;
  1005. info.dwNumberOfCsAddrs = 1;
  1006. info.lpcsaBuffer = &addresses;
  1007. addresses.LocalAddr.iSockaddrLength = sizeof(SOCKADDR_IPX);
  1008. addresses.LocalAddr.lpSockaddr = (LPSOCKADDR) pipxaddr;
  1009. addresses.RemoteAddr.iSockaddrLength = sizeof(SOCKADDR_IPX);
  1010. addresses.RemoteAddr.lpSockaddr = (LPSOCKADDR) pipxaddr;
  1011. addresses.iSocketType = AF_IPX;
  1012. addresses.iProtocol = NSPROTO_IPX;
  1013. status = WSASetService(&info,
  1014. fRegister ? RNRSERVICE_REGISTER : RNRSERVICE_DEREGISTER,
  1015. 0);
  1016. ASSERT(status == SOCKET_ERROR || status == 0);
  1017. if (status == SOCKET_ERROR)
  1018. {
  1019. status = GetLastError();
  1020. }
  1021. if (status == 0)
  1022. {
  1023. if (fRegister)
  1024. {
  1025. SapState = SapStateEnabled;
  1026. }
  1027. else
  1028. {
  1029. SapState = SapStateDisabled;
  1030. }
  1031. }
  1032. else
  1033. {
  1034. KdPrintEx((DPFLTR_DCOMSS_ID,
  1035. DPFLTR_WARNING_LEVEL,
  1036. "OR: WSASetService(%s) failed %d\n",
  1037. fRegister ? "ENABLE" : "DISABLE",
  1038. status));
  1039. }
  1040. return;
  1041. }
  1042. #endif
  1043. extern void
  1044. DealWithDeviceEvent();
  1045. void RPC_ENTRY
  1046. UpdateAddresses( PVOID arg )
  1047. {
  1048. // Calls to this function are serialized
  1049. DealWithDeviceEvent();
  1050. }