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.

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