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.

1182 lines
31 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. sainfo.c
  5. Abstract:
  6. This module contains code for managing shared access settings.
  7. Shared Access Settings are stored in a file and consist of a list
  8. of sections which correspond either to 'applications' or 'servers',
  9. and content indices which list all applications and servers in the file.
  10. E.g.
  11. [Contents.Application]
  12. <key>=1 ; Enabled
  13. [Contents.Server]
  14. <key>=1 ; Enabled
  15. An 'application' entry specifies parameters for a dynamic ticket
  16. which will allow the application to work through the NAT,
  17. by dynamically allowing an inbound secondary session.
  18. E.g.
  19. [Application.<key>]
  20. Title=DirectPlay
  21. Protocol=TCP
  22. Port=47624
  23. TcpResponseList=2300-2400
  24. UdpResponseList=2300-2400
  25. BuiltIn=1 ; optional flag, defaults to 0
  26. A 'server' entry specifies parameters for a static port mapping
  27. which will direct all sessions for a particular protocol and port
  28. to a particular internal machine.
  29. E.g.
  30. [Server.<key>]
  31. Title=WWW
  32. Protocol=TCP
  33. Port=80
  34. InternalName=MACHINENAME
  35. InternalPort=8080
  36. ReservedAddress=192.168.0.200
  37. BuiltIn=0 ; optional flag, defaults to 0
  38. Author:
  39. Abolade Gbadegesin (aboladeg) 17-Oct-1998
  40. Revision History:
  41. --*/
  42. #include "precomp.h"
  43. #pragma hdrstop
  44. #include <pbk.h>
  45. #include <tchar.h>
  46. #include <limits.h>
  47. #define LSTRLEN(s) ((sizeof(s) / sizeof(TCHAR)) - 1)
  48. #define HTONS(s) ((UCHAR)((s) >> 8) | ((UCHAR)(s) << 8))
  49. #define HTONL(l) ((HTONS(l) << 16) | HTONS((l) >> 16))
  50. #define NTOHS(s) HTONS(s)
  51. #define NTOHL(l) HTONL(l)
  52. #if 0
  53. const TCHAR c_szApplication[] = TEXT("Application");
  54. const TCHAR c_szBuiltIn[] = TEXT("BuiltIn");
  55. const TCHAR c_szContents[] = TEXT("Contents");
  56. const TCHAR c_szInternalName[] = TEXT("InternalName");
  57. const TCHAR c_szInternalPort[] = TEXT("InternalPort");
  58. const TCHAR c_szKeyFormat[] = TEXT("%08X");
  59. #endif
  60. const TCHAR c_szMaxResponseEntry[] = TEXT("65535-65535,");
  61. #if 0
  62. const TCHAR c_szPort[] = TEXT("Port");
  63. const TCHAR c_szProtocol[] = TEXT("Protocol");
  64. const TCHAR c_szReservedAddress[] = TEXT("ReservedAddress");
  65. #endif
  66. const TCHAR c_szResponseFormat1[] = TEXT("%d");
  67. const TCHAR c_szResponseFormat2[] = TEXT("%d-%d");
  68. #if 0
  69. const TCHAR c_szSectionFormat[] = TEXT("%s.%s");
  70. const TCHAR c_szServer[] = TEXT("Server");
  71. const TCHAR c_szSharedAccessIni[] = TEXT("SharedAccess.ini");
  72. const TCHAR c_szTagBuiltIn[] = TEXT("BuiltIn=");
  73. const TCHAR c_szTagInternalName[] = TEXT("InternalName=");
  74. const TCHAR c_szTagInternalPort[] = TEXT("InternalPort=");
  75. const TCHAR c_szTagPort[] = TEXT("Port=");
  76. const TCHAR c_szTagProtocol[] = TEXT("Protocol=");
  77. const TCHAR c_szTagReservedAddress[] = TEXT("ReservedAddress=");
  78. const TCHAR c_szTagTcpResponseList[] = TEXT("TcpResponseList=");
  79. const TCHAR c_szTagTitle[] = TEXT("Title=");
  80. const TCHAR c_szTagUdpResponseList[] = TEXT("UdpResponseList=");
  81. const TCHAR c_szTCP[] = TEXT("TCP");
  82. const TCHAR c_szTcpResponseList[] = TEXT("TcpResponseList");
  83. const TCHAR c_szTitle[] = TEXT("Title");
  84. const TCHAR c_szUDP[] = TEXT("UDP");
  85. const TCHAR c_szUdpResponseList[] = TEXT("UdpResponseList");
  86. //
  87. // FORWARD DECLARATIONS
  88. //
  89. SAAPPLICATION*
  90. LoadApplication(
  91. ULONG KeyValue,
  92. BOOL Enabled,
  93. const TCHAR* Path
  94. );
  95. TCHAR*
  96. LoadEntryList(
  97. const TCHAR* Path,
  98. const TCHAR* Section
  99. );
  100. TCHAR*
  101. LoadPath(
  102. VOID
  103. );
  104. SASERVER*
  105. LoadServer(
  106. ULONG KeyValue,
  107. BOOL Enabled,
  108. const TCHAR* Path
  109. );
  110. LONG
  111. Lstrcmpni(
  112. const TCHAR* String1,
  113. const TCHAR* String2,
  114. LONG Length
  115. );
  116. TCHAR*
  117. QueryEntryList(
  118. const TCHAR* EntryList,
  119. const TCHAR* Tag
  120. );
  121. BOOL
  122. SaveApplication(
  123. SAAPPLICATION* Application,
  124. const TCHAR* Path
  125. );
  126. BOOL
  127. SaveServer(
  128. SAINFO* Info,
  129. SASERVER* Server,
  130. const TCHAR* Path
  131. );
  132. BOOL
  133. WritePrivateProfileStringUTF8(
  134. const TCHAR* Section,
  135. const TCHAR* Key,
  136. const TCHAR* Value,
  137. const TCHAR* Path
  138. );
  139. VOID APIENTRY
  140. RasFreeSharedAccessSettings(
  141. IN SAINFO* Info
  142. )
  143. /*++
  144. Routine Description:
  145. Frees memory allocated for the contents of 'Info'.
  146. Arguments:
  147. Info - the settings to be freed
  148. Return Value:
  149. none.
  150. --*/
  151. {
  152. SAAPPLICATION* Application;
  153. PLIST_ENTRY Link;
  154. SASERVER* Server;
  155. TRACE("RasFreeSharedAccessSettings");
  156. while (!IsListEmpty(&Info->ApplicationList)) {
  157. Link = RemoveHeadList(&Info->ApplicationList);
  158. Application = CONTAINING_RECORD(Link, SAAPPLICATION, Link);
  159. FreeSharedAccessApplication(Application);
  160. }
  161. while (!IsListEmpty(&Info->ServerList)) {
  162. Link = RemoveHeadList(&Info->ServerList);
  163. Server = CONTAINING_RECORD(Link, SASERVER, Link);
  164. FreeSharedAccessServer(Server);
  165. }
  166. Free(Info);
  167. } // RasFreeSharedAccessSettings
  168. SAINFO* APIENTRY
  169. RasLoadSharedAccessSettings(
  170. BOOL EnabledOnly
  171. )
  172. /*++
  173. Routine Description:
  174. Reads in the local shared access settings, returning an allocated
  175. 'SAINFO' containing the settings retrieved.
  176. Arguments:
  177. EnabledOnly - if TRUE, only the application-entries which are enabled
  178. are retrieved.
  179. Return Value:
  180. SAINFO* - the settings retrieved
  181. --*/
  182. {
  183. SAAPPLICATION* Application;
  184. BOOL Enabled;
  185. SAINFO* Info;
  186. TCHAR* Key;
  187. TCHAR* KeyEnd;
  188. TCHAR* KeyList;
  189. ULONG KeyValue;
  190. TCHAR* Path;
  191. TCHAR SectionName[32];
  192. SASERVER* Server;
  193. TRACE("RasLoadSharedAccessSettings");
  194. //
  195. // Allocate and initialize the settings-structure
  196. //
  197. Info = (SAINFO*)Malloc(sizeof(SAINFO));
  198. if (!Info) { return NULL; }
  199. InitializeListHead(&Info->ApplicationList);
  200. InitializeListHead(&Info->ServerList);
  201. //
  202. // Read scope information from the registry
  203. //
  204. CsQueryScopeInformation(NULL, &Info->ScopeAddress, &Info->ScopeMask);
  205. //
  206. // Construct the path to the shared access information file,
  207. // and read the index of 'application' sections.
  208. // Each section should contain a valid application-description,
  209. // for which we construct a corresponding 'SAAPPLICATION' entry
  210. // in the application-list.
  211. //
  212. if (!(Path = LoadPath())) {
  213. RasFreeSharedAccessSettings(Info);
  214. return NULL;
  215. }
  216. wsprintf(SectionName, c_szSectionFormat, c_szContents, c_szApplication);
  217. if (KeyList = LoadEntryList(SectionName, Path)) {
  218. for (Key = KeyList; *Key; Key += lstrlen(Key) + 1) {
  219. //
  220. // Ensure the key is a valid hexadecimal integer,
  221. // and read the 'Enabled' setting which is its value.
  222. // N.B. if the entry is disabled and the caller only wants
  223. // enabled entries, exclude this one.
  224. //
  225. KeyValue = _tcstoul(Key, &KeyEnd, 16);
  226. if (*KeyEnd++ != TEXT('=')) {
  227. continue;
  228. } else if (!(Enabled = !!_ttol(KeyEnd)) && EnabledOnly) {
  229. continue;
  230. }
  231. //
  232. // Read in the corresponding 'Application.<key>' section.
  233. //
  234. Application = LoadApplication(KeyValue, Enabled, Path);
  235. if (Application) {
  236. InsertTailList(&Info->ApplicationList, &Application->Link);
  237. }
  238. }
  239. Free(KeyList);
  240. }
  241. //
  242. // Finally, read the index of 'server' sections, and read each section.
  243. // Each section contains a server-description for which we construct
  244. // a corresponding 'SASERVER' entry in the server-list.
  245. //
  246. wsprintf(SectionName, c_szSectionFormat, c_szContents, c_szServer);
  247. if (KeyList = LoadEntryList(SectionName, Path)) {
  248. for (Key = KeyList; *Key; Key += lstrlen(Key) + 1) {
  249. //
  250. // Ensure the key is a valid hexadecimal integer,
  251. // and read the 'Enabled' setting which is its value.
  252. // N.B. if the entry is disabled and the caller only wants
  253. // enabled entries, exclude this one.
  254. //
  255. KeyValue = _tcstoul(Key, &KeyEnd, 16);
  256. if (*KeyEnd++ != TEXT('=')) {
  257. continue;
  258. } else if (!(Enabled = !!_ttol(KeyEnd)) && EnabledOnly) {
  259. continue;
  260. }
  261. //
  262. // Read in the corresponding 'Server.<key>' section.
  263. //
  264. Server = LoadServer(KeyValue, Enabled, Path);
  265. if (Server) {
  266. InsertTailList(&Info->ServerList, &Server->Link);
  267. }
  268. }
  269. Free(KeyList);
  270. }
  271. return Info;
  272. } // RasLoadSharedAccessSettings
  273. BOOL APIENTRY
  274. RasSaveSharedAccessSettings(
  275. IN SAINFO* Info
  276. )
  277. /*++
  278. Routine Description:
  279. Stores the shared access settings in 'Info' back into the local registry
  280. from where the settings were read.
  281. N.B. If 'Info' was loaded with the 'EnableOnly' flag, saving it back
  282. will erase all disabled entries.
  283. Arguments:
  284. Info - supplies the settings to be saved
  285. Return Value:
  286. BOOL - TRUE if successful, FALSE otherwise.
  287. --*/
  288. {
  289. SAAPPLICATION* Application;
  290. TCHAR Buffer[10];
  291. PLIST_ENTRY Link;
  292. TCHAR Key[10];
  293. TCHAR* Path;
  294. TCHAR SectionName[32];
  295. SASERVER* Server;
  296. TRACE("RasSaveSharedAccessSettings");
  297. //
  298. // First erase the existing file.
  299. //
  300. if (!(Path = LoadPath()) || CreateDirectoriesOnPath(Path, NULL)) {
  301. Free0(Path);
  302. return FALSE;
  303. }
  304. DeleteFile(Path);
  305. //
  306. // Now we reconstruct the file.
  307. // We begin by saving each application entry, in the process building
  308. // a content index of all the saved entries.
  309. //
  310. wsprintf(SectionName, c_szSectionFormat, c_szContents, c_szApplication);
  311. for (Link = Info->ApplicationList.Flink; Link != &Info->ApplicationList;
  312. Link = Link->Flink) {
  313. Application = CONTAINING_RECORD(Link, SAAPPLICATION, Link);
  314. if (SaveApplication(Application, Path)) {
  315. wsprintf(Key, c_szKeyFormat, Application->Key);
  316. _ltot(!!Application->Enabled, Buffer, 10);
  317. WritePrivateProfileStringUTF8(
  318. SectionName,
  319. Key,
  320. Buffer,
  321. Path
  322. );
  323. }
  324. }
  325. //
  326. // Similarly, save each server entry, in the process building
  327. // a content index of all the saved entries.
  328. //
  329. wsprintf(SectionName, c_szSectionFormat, c_szContents, c_szServer);
  330. for (Link = Info->ServerList.Flink; Link != &Info->ServerList;
  331. Link = Link->Flink) {
  332. Server = CONTAINING_RECORD(Link, SASERVER, Link);
  333. if (SaveServer(Info, Server, Path)) {
  334. wsprintf(Key, c_szKeyFormat, Server->Key);
  335. _ltot(!!Server->Enabled, Buffer, 10);
  336. WritePrivateProfileStringUTF8(
  337. SectionName,
  338. Key,
  339. Buffer,
  340. Path
  341. );
  342. }
  343. }
  344. Free(Path);
  345. CsControlService(IPNATHLP_CONTROL_UPDATE_SETTINGS);
  346. return TRUE;
  347. } // RasSaveSharedAccessSettings
  348. VOID APIENTRY
  349. FreeSharedAccessApplication(
  350. SAAPPLICATION* Application
  351. )
  352. {
  353. PLIST_ENTRY Link;
  354. SARESPONSE* Response;
  355. while (!IsListEmpty(&Application->ResponseList)) {
  356. Link = RemoveHeadList(&Application->ResponseList);
  357. Response = CONTAINING_RECORD(Link, SARESPONSE, Link);
  358. Free(Response);
  359. }
  360. Free0(Application->Title);
  361. Free(Application);
  362. }
  363. VOID APIENTRY
  364. FreeSharedAccessServer(
  365. SASERVER* Server
  366. )
  367. {
  368. Free0(Server->Title);
  369. Free0(Server->InternalName);
  370. Free(Server);
  371. }
  372. SAAPPLICATION*
  373. LoadApplication(
  374. ULONG KeyValue,
  375. BOOL Enabled,
  376. const TCHAR* Path
  377. )
  378. {
  379. SAAPPLICATION* Application;
  380. TCHAR* EntryList;
  381. TCHAR Key[10];
  382. TCHAR SectionName[32];
  383. TCHAR* Value;
  384. wsprintf(Key, c_szKeyFormat, KeyValue);
  385. wsprintf(SectionName, c_szSectionFormat, c_szApplication, Key);
  386. if (!(EntryList = LoadEntryList(SectionName, Path))) { return NULL; }
  387. do {
  388. //
  389. // Allocate and initialize an 'application' entry.
  390. //
  391. Application = (SAAPPLICATION*)Malloc(sizeof(SAAPPLICATION));
  392. if (!Application) { break; }
  393. ZeroMemory(Application, sizeof(*Application));
  394. InitializeListHead(&Application->ResponseList);
  395. Application->Key = KeyValue;
  396. Application->Enabled = Enabled;
  397. //
  398. // Read each required '<tag>=<value>' entry in the section.
  399. // The tags required for an application are
  400. // 'Title='
  401. // 'Protocol='
  402. // 'Port='
  403. // The optional tags, at least one of which must be present, are
  404. // 'TcpResponseList='
  405. // 'UdpResponseList='
  406. // The optional tags which may be absent are
  407. // 'BuiltIn='
  408. //
  409. Value = QueryEntryList(EntryList, c_szTagTitle);
  410. if (!Value) { break; }
  411. Application->Title = StrDup(Value);
  412. Value = QueryEntryList(EntryList, c_szTagProtocol);
  413. if (!Value) { break; }
  414. if (!Lstrcmpni(Value, c_szTCP, LSTRLEN(c_szTCP))) {
  415. Application->Protocol = NAT_PROTOCOL_TCP;
  416. } else if (!Lstrcmpni(Value, c_szUDP, LSTRLEN(c_szTCP))) {
  417. Application->Protocol = NAT_PROTOCOL_UDP;
  418. } else {
  419. break;
  420. }
  421. Value = QueryEntryList(EntryList, c_szTagPort);
  422. if (!Value || !(Application->Port = (USHORT)_ttol(Value))) { break; }
  423. Application->Port = HTONS(Application->Port);
  424. Value = QueryEntryList(EntryList, c_szTagTcpResponseList);
  425. if (Value) {
  426. SharedAccessResponseStringToList(
  427. NAT_PROTOCOL_TCP,
  428. Value,
  429. &Application->ResponseList
  430. );
  431. }
  432. Value = QueryEntryList(EntryList, c_szTagUdpResponseList);
  433. if (Value) {
  434. SharedAccessResponseStringToList(
  435. NAT_PROTOCOL_UDP,
  436. Value,
  437. &Application->ResponseList
  438. );
  439. }
  440. if (IsListEmpty(&Application->ResponseList)) { break; }
  441. Value = QueryEntryList(EntryList, c_szTagBuiltIn);
  442. if (Value) {
  443. Application->BuiltIn = _ttol(Value) ? TRUE : FALSE;
  444. } else {
  445. Application->BuiltIn = FALSE;
  446. }
  447. //
  448. // The entry was loaded successfully.
  449. //
  450. Free(EntryList);
  451. return Application;
  452. } while (FALSE);
  453. //
  454. // Something went wrong.
  455. //
  456. if (Application) { FreeSharedAccessApplication(Application); }
  457. Free(EntryList);
  458. return NULL;
  459. }
  460. TCHAR*
  461. LoadEntryList(
  462. const TCHAR* Section,
  463. const TCHAR* Path
  464. )
  465. {
  466. CHAR* BufferA = NULL;
  467. ULONG Length;
  468. CHAR* PathA = NULL;
  469. CHAR* SectionA = NULL;
  470. ULONG Size;
  471. CHAR* Source;
  472. TCHAR* Target;
  473. TCHAR* BufferW = NULL;
  474. if (!(SectionA = StrDupAFromT(Section))) {
  475. return NULL;
  476. }
  477. if (!(PathA = StrDupAFromTAnsi(Path))) {
  478. Free(SectionA);
  479. return NULL;
  480. }
  481. for (BufferA = NULL, Size = MAX_PATH; ; Size += MAX_PATH, Free(BufferA)) {
  482. BufferA = (CHAR*)Malloc(Size);
  483. if (!BufferA) {
  484. break;
  485. }
  486. if (GetPrivateProfileSectionA(SectionA, BufferA, Size, PathA)
  487. == Size-2) {
  488. continue;
  489. }
  490. //
  491. // Convert each string in the buffer from UTF8 format to Unicode.
  492. // The conversion will result in at most 'Size' Unicode characters,
  493. // and fewer if 2- or 3-byte UTF8 sequences are present in the
  494. // source buffer.
  495. //
  496. BufferW = (TCHAR*)Malloc(Size * sizeof(TCHAR));
  497. if (!BufferW) {
  498. break;
  499. }
  500. Target = BufferW;
  501. for (Source = BufferA; *Source; Source += lstrlenA(Source) + 1) {
  502. if (StrCpyWFromA(Target, Source, Size) != NO_ERROR) {
  503. break;
  504. }
  505. Length = lstrlen(Target) + 1;
  506. Target += Length;
  507. Size -= Length;
  508. }
  509. if (*Source) { break; }
  510. Free(BufferA);
  511. Free(PathA);
  512. Free(SectionA);
  513. return BufferW;
  514. }
  515. Free0(BufferW);
  516. Free0(BufferA);
  517. Free0(PathA);
  518. Free0(SectionA);
  519. return NULL;
  520. }
  521. TCHAR*
  522. LoadPath(
  523. VOID
  524. )
  525. {
  526. TCHAR* Path;
  527. Path =
  528. (TCHAR*)Malloc(
  529. (MAX_PATH + lstrlen(c_szSharedAccessIni) + 1) * sizeof(TCHAR)
  530. );
  531. if (!Path || !GetPhonebookDirectory(PBM_System, Path)) {
  532. Free0(Path);
  533. return NULL;
  534. }
  535. lstrcat(Path, c_szSharedAccessIni);
  536. return Path;
  537. }
  538. SASERVER*
  539. LoadServer(
  540. ULONG KeyValue,
  541. BOOL Enabled,
  542. const TCHAR* Path
  543. )
  544. {
  545. SASERVER* Server;
  546. TCHAR* EntryList;
  547. TCHAR Key[10];
  548. TCHAR SectionName[32];
  549. TCHAR* Value;
  550. wsprintf(Key, c_szKeyFormat, KeyValue);
  551. wsprintf(SectionName, c_szSectionFormat, c_szServer, Key);
  552. if (!(EntryList = LoadEntryList(SectionName, Path))) { return NULL; }
  553. do {
  554. //
  555. // Allocate and initialize a 'server' entry.
  556. //
  557. Server = (SASERVER*)Malloc(sizeof(SASERVER));
  558. if (!Server) { break; }
  559. ZeroMemory(Server, sizeof(*Server));
  560. Server->Key = KeyValue;
  561. Server->Enabled = Enabled;
  562. //
  563. // Read each required '<tag>=<value>' entry in the section.
  564. // The tags required for a server are
  565. // 'Title='
  566. // 'Protocol='
  567. // 'Port='
  568. // 'InternalPort='
  569. // The optional tags which may be absent are
  570. // 'BuiltIn='
  571. // 'InternalName='
  572. // 'ReservedAddress='
  573. // The 'InternalName=' and 'ReservedAddress=' tags may only be absent
  574. // if 'BuiltIn' is set, in which case the entry is disabled.
  575. //
  576. Value = QueryEntryList(EntryList, c_szTagTitle);
  577. if (!Value) { break; }
  578. Server->Title = StrDup(Value);
  579. Value = QueryEntryList(EntryList, c_szTagProtocol);
  580. if (!Value) { break; }
  581. if (!Lstrcmpni(Value, c_szTCP, LSTRLEN(c_szTCP))) {
  582. Server->Protocol = NAT_PROTOCOL_TCP;
  583. } else if (!Lstrcmpni(Value, c_szUDP, LSTRLEN(c_szTCP))) {
  584. Server->Protocol = NAT_PROTOCOL_UDP;
  585. } else {
  586. break;
  587. }
  588. Value = QueryEntryList(EntryList, c_szTagPort);
  589. if (!Value || !(Server->Port = (USHORT)_ttol(Value))) { break; }
  590. Server->Port = HTONS(Server->Port);
  591. Value = QueryEntryList(EntryList, c_szTagInternalPort);
  592. if (!Value || !(Server->InternalPort = (USHORT)_ttol(Value))) { break; }
  593. Server->InternalPort = HTONS(Server->InternalPort);
  594. Value = QueryEntryList(EntryList, c_szTagBuiltIn);
  595. if (Value) {
  596. Server->BuiltIn = _ttol(Value) ? TRUE : FALSE;
  597. } else {
  598. Server->BuiltIn = FALSE;
  599. }
  600. Value = QueryEntryList(EntryList, c_szTagInternalName);
  601. if (!Value || !lstrlen(Value)) {
  602. if (!Server->BuiltIn) {
  603. break;
  604. } else {
  605. Server->InternalName = NULL;
  606. Server->Enabled = FALSE;
  607. }
  608. } else {
  609. Server->InternalName = StrDup(Value);
  610. }
  611. Value = QueryEntryList(EntryList, c_szTagReservedAddress);
  612. if (!Value || !lstrlen(Value)) {
  613. if (!Server->BuiltIn) {
  614. break;
  615. } else {
  616. Server->ReservedAddress = INADDR_NONE;
  617. Server->Enabled = FALSE;
  618. }
  619. } else {
  620. Server->ReservedAddress = IpPszToHostAddr(Value);
  621. if (Server->ReservedAddress == INADDR_NONE && !Server->BuiltIn) {
  622. break;
  623. }
  624. Server->ReservedAddress = HTONL(Server->ReservedAddress);
  625. }
  626. //
  627. // The entry was loaded successfully.
  628. //
  629. Free(EntryList);
  630. return Server;
  631. } while (FALSE);
  632. //
  633. // Something went wrong.
  634. //
  635. if (Server) { FreeSharedAccessServer(Server); }
  636. Free(EntryList);
  637. return NULL;
  638. }
  639. LONG
  640. Lstrcmpni(
  641. const TCHAR* String1,
  642. const TCHAR* String2,
  643. LONG Length
  644. )
  645. {
  646. return
  647. CSTR_EQUAL -
  648. CompareString(
  649. LOCALE_SYSTEM_DEFAULT,
  650. NORM_IGNORECASE,
  651. String1,
  652. Length,
  653. String2,
  654. Length
  655. );
  656. }
  657. TCHAR*
  658. QueryEntryList(
  659. const TCHAR* EntryList,
  660. const TCHAR* Tag
  661. )
  662. {
  663. TCHAR* Entry;
  664. ULONG TagLength = lstrlen(Tag);
  665. for (Entry = (TCHAR*)EntryList; *Entry; Entry += lstrlen(Entry) + 1) {
  666. if (Entry[0] == Tag[0] && !Lstrcmpni(Tag, Entry, TagLength)) {
  667. return Entry + TagLength;
  668. }
  669. }
  670. return NULL;
  671. }
  672. BOOL
  673. SaveApplication(
  674. SAAPPLICATION* Application,
  675. const TCHAR* Path
  676. )
  677. {
  678. TCHAR Buffer[32];
  679. ULONG Length;
  680. PLIST_ENTRY Link;
  681. SARESPONSE* Response;
  682. TCHAR SectionName[32];
  683. TCHAR* Value;
  684. wsprintf(Buffer, c_szKeyFormat, Application->Key);
  685. wsprintf(SectionName, c_szSectionFormat, c_szApplication, Buffer);
  686. WritePrivateProfileStringUTF8(
  687. SectionName,
  688. c_szTitle,
  689. Application->Title,
  690. Path
  691. );
  692. if (Application->Protocol == NAT_PROTOCOL_TCP) {
  693. Value = (TCHAR*)c_szTCP;
  694. } else if (Application->Protocol == NAT_PROTOCOL_UDP) {
  695. Value = (TCHAR*)c_szUDP;
  696. } else {
  697. return FALSE;
  698. }
  699. WritePrivateProfileStringUTF8(
  700. SectionName,
  701. c_szProtocol,
  702. Value,
  703. Path
  704. );
  705. _ltot(NTOHS(Application->Port), Buffer, 10);
  706. WritePrivateProfileStringUTF8(
  707. SectionName,
  708. c_szPort,
  709. Buffer,
  710. Path
  711. );
  712. Value = SharedAccessResponseListToString(&Application->ResponseList, NAT_PROTOCOL_TCP);
  713. if (Value) {
  714. WritePrivateProfileStringUTF8(
  715. SectionName,
  716. c_szTcpResponseList,
  717. Value,
  718. Path
  719. );
  720. Free(Value);
  721. }
  722. Value = SharedAccessResponseListToString(&Application->ResponseList, NAT_PROTOCOL_UDP);
  723. if (Value) {
  724. WritePrivateProfileStringUTF8(
  725. SectionName,
  726. c_szUdpResponseList,
  727. Value,
  728. Path
  729. );
  730. Free(Value);
  731. }
  732. _ltot(Application->BuiltIn, Buffer, 10);
  733. WritePrivateProfileStringUTF8(
  734. SectionName,
  735. c_szBuiltIn,
  736. Buffer,
  737. Path
  738. );
  739. return TRUE;
  740. }
  741. BOOL
  742. SaveServer(
  743. SAINFO* Info,
  744. SASERVER* Server,
  745. const TCHAR* Path
  746. )
  747. {
  748. TCHAR Buffer[32];
  749. ULONG ReservedAddress;
  750. TCHAR SectionName[32];
  751. TCHAR* Value;
  752. wsprintf(Buffer, c_szKeyFormat, Server->Key);
  753. wsprintf(SectionName, c_szSectionFormat, c_szServer, Buffer);
  754. WritePrivateProfileStringUTF8(
  755. SectionName,
  756. c_szTitle,
  757. Server->Title,
  758. Path
  759. );
  760. if (Server->Protocol == NAT_PROTOCOL_TCP) {
  761. Value = (TCHAR*)c_szTCP;
  762. } else if (Server->Protocol == NAT_PROTOCOL_UDP) {
  763. Value = (TCHAR*)c_szUDP;
  764. } else {
  765. return FALSE;
  766. }
  767. WritePrivateProfileStringUTF8(
  768. SectionName,
  769. c_szProtocol,
  770. Value,
  771. Path
  772. );
  773. _ltot(NTOHS(Server->Port), Buffer, 10);
  774. WritePrivateProfileStringUTF8(
  775. SectionName,
  776. c_szPort,
  777. Buffer,
  778. Path
  779. );
  780. WritePrivateProfileStringUTF8(
  781. SectionName,
  782. c_szInternalName,
  783. Server->InternalName,
  784. Path
  785. );
  786. _ltot(NTOHS(Server->InternalPort), Buffer, 10);
  787. WritePrivateProfileStringUTF8(
  788. SectionName,
  789. c_szInternalPort,
  790. Buffer,
  791. Path
  792. );
  793. if (Server->InternalName && lstrlen(Server->InternalName)) {
  794. ReservedAddress = IpPszToHostAddr(Server->InternalName);
  795. if (ReservedAddress != INADDR_NONE) {
  796. Server->ReservedAddress = HTONL(ReservedAddress);
  797. }
  798. if (Server->ReservedAddress == INADDR_NONE) {
  799. SASERVER* Entry;
  800. ULONG Index;
  801. PLIST_ENTRY Link;
  802. ULONG ScopeLength;
  803. for (Link = Info->ServerList.Flink; Link != &Info->ServerList;
  804. Link = Link->Flink) {
  805. Entry = CONTAINING_RECORD(Link, SASERVER, Link);
  806. if (Entry != Server &&
  807. Entry->ReservedAddress &&
  808. Entry->ReservedAddress != INADDR_NONE &&
  809. lstrcmpi(Entry->InternalName, Server->InternalName) == 0) {
  810. Server->ReservedAddress = Entry->ReservedAddress;
  811. break;
  812. }
  813. }
  814. if (Server->ReservedAddress == INADDR_NONE) {
  815. ScopeLength = NTOHL(~Info->ScopeMask);
  816. for (Index = 1; Index < ScopeLength - 1; Index++) {
  817. ReservedAddress =
  818. (Info->ScopeAddress & Info->ScopeMask) | HTONL(Index);
  819. if (ReservedAddress == Info->ScopeAddress) { continue; }
  820. for (Link = Info->ServerList.Flink;
  821. Link != &Info->ServerList; Link = Link->Flink) {
  822. Entry = CONTAINING_RECORD(Link, SASERVER, Link);
  823. if (Entry->ReservedAddress == ReservedAddress) {
  824. break;
  825. }
  826. }
  827. if (Link == &Info->ServerList) { break; }
  828. }
  829. if (Index > ScopeLength) { return FALSE; }
  830. Server->ReservedAddress = ReservedAddress;
  831. }
  832. }
  833. IpHostAddrToPsz(NTOHL(Server->ReservedAddress), Buffer);
  834. WritePrivateProfileStringUTF8(
  835. SectionName,
  836. c_szReservedAddress,
  837. Buffer,
  838. Path
  839. );
  840. }
  841. _ltot(Server->BuiltIn, Buffer, 10);
  842. WritePrivateProfileStringUTF8(
  843. SectionName,
  844. c_szBuiltIn,
  845. Buffer,
  846. Path
  847. );
  848. return TRUE;
  849. }
  850. #endif
  851. TCHAR* APIENTRY
  852. SharedAccessResponseListToString(
  853. PLIST_ENTRY ResponseList,
  854. UCHAR Protocol
  855. )
  856. {
  857. TCHAR Buffer[LSTRLEN(c_szMaxResponseEntry)];
  858. ULONG Length;
  859. PLIST_ENTRY Link;
  860. SARESPONSE* Response;
  861. TCHAR* Value;
  862. Length = 2;
  863. for (Link = ResponseList->Flink;
  864. Link != ResponseList; Link = Link->Flink) {
  865. Response = CONTAINING_RECORD(Link, SARESPONSE, Link);
  866. if (Response->Protocol != Protocol) { continue; }
  867. Length += LSTRLEN(c_szMaxResponseEntry);
  868. }
  869. if (Length == 2) { return NULL; }
  870. Value = (TCHAR*)Malloc(Length * sizeof(TCHAR));
  871. if (!Value) { return NULL; }
  872. Value[0] = TEXT('\0');
  873. for (Link = ResponseList->Flink;
  874. Link != ResponseList; Link = Link->Flink) {
  875. Response = CONTAINING_RECORD(Link, SARESPONSE, Link);
  876. if (Response->Protocol != Protocol) { continue; }
  877. if (Value[0] != TEXT('\0')) {
  878. lstrcat(Value, TEXT(","));
  879. }
  880. if (Response->StartPort == Response->EndPort) {
  881. wsprintf(
  882. Buffer,
  883. c_szResponseFormat1,
  884. NTOHS(Response->StartPort)
  885. );
  886. } else {
  887. wsprintf(
  888. Buffer,
  889. c_szResponseFormat2,
  890. NTOHS(Response->StartPort),
  891. NTOHS(Response->EndPort)
  892. );
  893. }
  894. lstrcat(Value, Buffer);
  895. }
  896. return Value;
  897. }
  898. BOOL APIENTRY
  899. SharedAccessResponseStringToList(
  900. UCHAR Protocol,
  901. TCHAR* Value,
  902. PLIST_ENTRY ListHead
  903. )
  904. {
  905. TCHAR* Endp;
  906. ULONG EndPort;
  907. LONG Length;
  908. SARESPONSE* Response;
  909. ULONG StartPort;
  910. while (*Value) {
  911. //
  912. // Read either a single port or a range of ports.
  913. //
  914. if (!(StartPort = _tcstoul(Value, &Endp, 10))) {
  915. return FALSE;
  916. } else if (StartPort > USHRT_MAX) {
  917. return FALSE;
  918. }
  919. while(*Endp == ' ') Endp++; // consume whitespace
  920. if (!*Endp || *Endp == ',') {
  921. EndPort = StartPort;
  922. Value = (!*Endp ? Endp : Endp + 1);
  923. } else if (*Endp != '-') {
  924. return FALSE;
  925. } else if (!(EndPort = _tcstoul(++Endp, &Value, 10))) {
  926. return FALSE;
  927. } else if (EndPort > USHRT_MAX) {
  928. return FALSE;
  929. } else if (EndPort < StartPort) {
  930. return FALSE;
  931. } else if (*Value && *Value++ != ',') {
  932. return FALSE;
  933. }
  934. //
  935. // Allocate and append another response entry
  936. //
  937. Response = (SARESPONSE*)Malloc(sizeof(SARESPONSE));
  938. if (!Response) { return FALSE; }
  939. Response->Protocol = Protocol;
  940. Response->StartPort = HTONS((USHORT)StartPort);
  941. Response->EndPort = HTONS((USHORT)EndPort);
  942. InsertTailList(ListHead, &Response->Link);
  943. }
  944. return TRUE;
  945. }
  946. #if 0
  947. BOOL
  948. WritePrivateProfileStringUTF8(
  949. const TCHAR* Section,
  950. const TCHAR* Key,
  951. const TCHAR* Value,
  952. const TCHAR* Path
  953. )
  954. {
  955. CHAR* KeyA;
  956. CHAR* PathA;
  957. CHAR* SectionA;
  958. BOOL Succeeded;
  959. CHAR* ValueA = NULL;
  960. if (!(SectionA = StrDupAFromT(Section))) {
  961. Succeeded = FALSE;
  962. } else {
  963. if (!(KeyA = StrDupAFromT(Key))) {
  964. Succeeded = FALSE;
  965. } else {
  966. if (Value && !(ValueA = StrDupAFromT(Value))) {
  967. Succeeded = FALSE;
  968. } else {
  969. if (!(PathA = StrDupAFromTAnsi(Path))) {
  970. Succeeded = FALSE;
  971. } else {
  972. Succeeded =
  973. WritePrivateProfileStringA(
  974. SectionA,
  975. KeyA,
  976. ValueA,
  977. PathA
  978. );
  979. Free(PathA);
  980. }
  981. Free0(ValueA);
  982. }
  983. Free(KeyA);
  984. }
  985. Free(SectionA);
  986. }
  987. return Succeeded;
  988. }
  989. #endif