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.

2375 lines
50 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. record.c
  5. Abstract:
  6. Domain Name System (DNS) Library
  7. Routines to handle resource records (RR).
  8. Author:
  9. Jim Gilroy (jamesg) December 1996
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. #include "time.h"
  14. #include "ws2tcpip.h" // IPv6 inaddr definitions
  15. //
  16. // Type name mapping.
  17. //
  18. // Unlike above general value\string mapping the type lookup
  19. // has property of allowing direct lookup indexing with type, so
  20. // it is special cased.
  21. //
  22. //
  23. // DCR: make combined type table
  24. // DCR: add property flags to type table
  25. // - writeability flag?
  26. // - record/query type?
  27. // - indexable type?
  28. //
  29. // then function just get index for type and check flag(s)
  30. //
  31. TYPE_NAME_TABLE TypeTable[] =
  32. {
  33. "ZERO" , 0 ,
  34. "A" , DNS_TYPE_A ,
  35. "NS" , DNS_TYPE_NS ,
  36. "MD" , DNS_TYPE_MD ,
  37. "MF" , DNS_TYPE_MF ,
  38. "CNAME" , DNS_TYPE_CNAME ,
  39. "SOA" , DNS_TYPE_SOA ,
  40. "MB" , DNS_TYPE_MB ,
  41. "MG" , DNS_TYPE_MG ,
  42. "MR" , DNS_TYPE_MR ,
  43. "NULL" , DNS_TYPE_NULL ,
  44. "WKS" , DNS_TYPE_WKS ,
  45. "PTR" , DNS_TYPE_PTR ,
  46. "HINFO" , DNS_TYPE_HINFO ,
  47. "MINFO" , DNS_TYPE_MINFO ,
  48. "MX" , DNS_TYPE_MX ,
  49. "TXT" , DNS_TYPE_TEXT ,
  50. "RP" , DNS_TYPE_RP ,
  51. "AFSDB" , DNS_TYPE_AFSDB ,
  52. "X25" , DNS_TYPE_X25 ,
  53. "ISDN" , DNS_TYPE_ISDN ,
  54. "RT" , DNS_TYPE_RT ,
  55. "NSAP" , DNS_TYPE_NSAP ,
  56. "NSAPPTR" , DNS_TYPE_NSAPPTR ,
  57. "SIG" , DNS_TYPE_SIG ,
  58. "KEY" , DNS_TYPE_KEY ,
  59. "PX" , DNS_TYPE_PX ,
  60. "GPOS" , DNS_TYPE_GPOS ,
  61. "AAAA" , DNS_TYPE_AAAA ,
  62. "LOC" , DNS_TYPE_LOC ,
  63. "NXT" , DNS_TYPE_NXT ,
  64. "EID" , DNS_TYPE_EID ,
  65. "NIMLOC" , DNS_TYPE_NIMLOC ,
  66. "SRV" , DNS_TYPE_SRV ,
  67. "ATMA" , DNS_TYPE_ATMA ,
  68. "NAPTR" , DNS_TYPE_NAPTR ,
  69. "KX" , DNS_TYPE_KX ,
  70. "CERT" , DNS_TYPE_CERT ,
  71. "A6" , DNS_TYPE_A6 ,
  72. "DNAME" , DNS_TYPE_DNAME ,
  73. "SINK" , DNS_TYPE_SINK ,
  74. "OPT" , DNS_TYPE_OPT ,
  75. "42" , 0x002a ,
  76. "43" , 0x002b ,
  77. "44" , 0x002c ,
  78. "45" , 0x002d ,
  79. "46" , 0x002e ,
  80. "47" , 0x002f ,
  81. "48" , 0x0030 ,
  82. //
  83. // NOTE: last type indexed by type ID MUST be set
  84. // as MAX_SELF_INDEXED_TYPE #define in record.h
  85. // and MUST be added to function tables below,
  86. // even if with NULL entry
  87. //
  88. //
  89. // Pseudo record types
  90. //
  91. "TKEY" , DNS_TYPE_TKEY ,
  92. "TSIG" , DNS_TYPE_TSIG ,
  93. //
  94. // MS only types
  95. //
  96. "WINS" , DNS_TYPE_WINS ,
  97. "WINSR" , DNS_TYPE_WINSR ,
  98. // **********************************************
  99. //
  100. // NOTE: This is the END of the type lookup table
  101. // for dispatch purposes.
  102. //
  103. // Defined by MAX_RECORD_TYPE_INDEX in dnslibp.h
  104. // Type dispatch tables MUST be at least this size.
  105. // Geyond this value table continues for string to type
  106. // matching only
  107. //
  108. "UINFO" , DNS_TYPE_UINFO ,
  109. "UID" , DNS_TYPE_UID ,
  110. "GID" , DNS_TYPE_GID ,
  111. "UNSPEC" , DNS_TYPE_UNSPEC ,
  112. "WINS-R" , DNS_TYPE_WINSR ,
  113. "NBSTAT" , DNS_TYPE_WINSR ,
  114. //
  115. // Query types -- only for getting strings
  116. //
  117. "ADDRS" , DNS_TYPE_ADDRS ,
  118. "TKEY" , DNS_TYPE_TKEY ,
  119. "TSIG" , DNS_TYPE_TSIG ,
  120. "IXFR" , DNS_TYPE_IXFR ,
  121. "AXFR" , DNS_TYPE_AXFR ,
  122. "MAILB" , DNS_TYPE_MAILB ,
  123. "MAILA" , DNS_TYPE_MAILA ,
  124. "MAILB" , DNS_TYPE_MAILB ,
  125. "ALL" , DNS_TYPE_ALL ,
  126. NULL, 0,
  127. };
  128. // Handy for screening writeable types
  129. #define LOW_QUERY_TYPE (DNS_TYPE_ADDRS)
  130. WORD
  131. Dns_RecordTableIndexForType(
  132. IN WORD wType
  133. )
  134. /*++
  135. Routine Description:
  136. Get record table index for a given type.
  137. Arguments:
  138. wType -- RR type in net byte order
  139. Return Value:
  140. Ptr to RR mneumonic string.
  141. NULL if unknown RR type.
  142. --*/
  143. {
  144. //
  145. // if type directly indexes table, directly get string
  146. //
  147. if ( wType <= MAX_SELF_INDEXED_TYPE )
  148. {
  149. return( wType );
  150. }
  151. //
  152. // types not directly indexed
  153. //
  154. else
  155. {
  156. WORD i = MAX_SELF_INDEXED_TYPE + 1;
  157. while ( i <= MAX_RECORD_TYPE_INDEX )
  158. {
  159. if ( TypeTable[i].wType == wType )
  160. {
  161. return( i );
  162. }
  163. i++;
  164. continue;
  165. }
  166. }
  167. return( 0 ); // type not indexed
  168. }
  169. WORD
  170. Dns_RecordTypeForNameA(
  171. IN PCHAR pchName,
  172. IN INT cchNameLength
  173. )
  174. /*++
  175. Routine Description:
  176. Retrieve RR corresponding to RR database name.
  177. Arguments:
  178. pchName - name of record type
  179. cchNameLength - record name length
  180. Return Value:
  181. Record type corresponding to pchName, if found.
  182. Otherwise zero.
  183. --*/
  184. {
  185. INT i;
  186. PCHAR recordString;
  187. CHAR firstNameChar;
  188. CHAR upcaseName[ MAX_RECORD_NAME_LENGTH+1 ];
  189. //
  190. // if not given get string length
  191. //
  192. if ( !cchNameLength )
  193. {
  194. cchNameLength = strlen( pchName );
  195. }
  196. // upcase name to optimize compare
  197. // allows single character comparison and use of faster case sensitive
  198. // compare routine
  199. if ( cchNameLength > MAX_RECORD_NAME_LENGTH )
  200. {
  201. return( 0 );
  202. }
  203. memcpy(
  204. upcaseName,
  205. pchName,
  206. cchNameLength );
  207. upcaseName[ cchNameLength ] = 0;
  208. _strupr( upcaseName );
  209. firstNameChar = *upcaseName;
  210. //
  211. // check all supported RR types for name match
  212. //
  213. i = 0;
  214. while( TypeTable[++i].wType != 0 )
  215. {
  216. recordString = TypeTable[i].pszTypeName;
  217. if ( firstNameChar == *recordString
  218. && ! strncmp( upcaseName, recordString, cchNameLength ) )
  219. {
  220. return( TypeTable[i].wType );
  221. }
  222. }
  223. return( 0 );
  224. }
  225. WORD
  226. Dns_RecordTypeForNameW(
  227. IN PWCHAR pchName,
  228. IN INT cchNameLength
  229. )
  230. /*++
  231. Routine Description:
  232. Retrieve RR corresponding to RR database name.
  233. Arguments:
  234. pchName - name of record type
  235. cchNameLength - record name length
  236. Return Value:
  237. Record type corresponding to pchName, if found.
  238. Otherwise zero.
  239. --*/
  240. {
  241. DWORD length;
  242. CHAR ansiName[ MAX_RECORD_NAME_LENGTH+1 ];
  243. //
  244. // convert to ANSI
  245. //
  246. length = MAX_RECORD_NAME_LENGTH + 1;
  247. if ( ! Dns_StringCopy(
  248. ansiName,
  249. & length,
  250. (PSTR) pchName,
  251. cchNameLength,
  252. DnsCharSetUnicode,
  253. DnsCharSetAnsi ) )
  254. {
  255. return 0;
  256. }
  257. return Dns_RecordTypeForNameA(
  258. ansiName,
  259. 0 );
  260. }
  261. PCHAR
  262. private_StringForRecordType(
  263. IN WORD wType
  264. )
  265. /*++
  266. Routine Description:
  267. Get string corresponding to record type.
  268. Arguments:
  269. wType -- RR type in net byte order
  270. Return Value:
  271. Ptr to RR mneumonic string.
  272. NULL if unknown RR type.
  273. --*/
  274. {
  275. //
  276. // if type directly indexes table, directly get string
  277. //
  278. if ( wType <= MAX_SELF_INDEXED_TYPE )
  279. {
  280. return( TypeTable[wType].pszTypeName );
  281. }
  282. //
  283. // strings not indexed by type, walk the list
  284. //
  285. else
  286. {
  287. INT i = MAX_SELF_INDEXED_TYPE + 1;
  288. while( TypeTable[i].wType != 0 )
  289. {
  290. if ( wType == TypeTable[i].wType )
  291. {
  292. return( TypeTable[i].pszTypeName );
  293. }
  294. i++;
  295. }
  296. }
  297. return( NULL );
  298. }
  299. PCHAR
  300. Dns_RecordStringForType(
  301. IN WORD wType
  302. )
  303. /*++
  304. Routine Description:
  305. Get type string for type.
  306. This routine gets pointer rather than direct access to buffer.
  307. Arguments:
  308. wType -- RR type in net byte order
  309. Return Value:
  310. Ptr to RR mneumonic string.
  311. NULL if unknown RR type.
  312. --*/
  313. {
  314. PSTR pstr;
  315. pstr = private_StringForRecordType( wType );
  316. if ( !pstr )
  317. {
  318. pstr = "UNKNOWN";
  319. }
  320. return pstr;
  321. }
  322. PCHAR
  323. Dns_RecordStringForWritableType(
  324. IN WORD wType
  325. )
  326. /*++
  327. Routine Description:
  328. Retrieve RR string corresponding to the RR type -- ONLY if writable type.
  329. Arguments:
  330. wType -- RR type in net byte order
  331. Return Value:
  332. Ptr to RR mneumonic string.
  333. NULL if unknown RR type.
  334. --*/
  335. {
  336. //
  337. // eliminate all supported types that are NOT writable
  338. //
  339. // DCR: should have writeability screen
  340. // this misses OPT ... then QUERY types
  341. //
  342. if ( wType == DNS_TYPE_ZERO ||
  343. wType == DNS_TYPE_NULL ||
  344. wType == DNS_TYPE_OPT ||
  345. (wType >= LOW_QUERY_TYPE && wType <= DNS_TYPE_ALL) )
  346. {
  347. return( NULL );
  348. }
  349. //
  350. // otherwise return type string
  351. // string is NULL if type is unknown
  352. //
  353. return( private_StringForRecordType(wType) );
  354. }
  355. BOOL
  356. Dns_WriteStringForType_A(
  357. OUT PCHAR pBuffer,
  358. IN WORD wType
  359. )
  360. /*++
  361. Routine Description:
  362. Write type name string for type.
  363. Arguments:
  364. wType -- RR type in net byte order
  365. Return Value:
  366. TRUE if found string.
  367. FALSE if converted type numerically.
  368. --*/
  369. {
  370. PSTR pstr;
  371. pstr = private_StringForRecordType( wType );
  372. if ( pstr )
  373. {
  374. strcpy( pBuffer, pstr );
  375. }
  376. else
  377. {
  378. sprintf( pBuffer, "%u", wType );
  379. }
  380. return pstr ? TRUE : FALSE;
  381. }
  382. BOOL
  383. Dns_WriteStringForType_W(
  384. OUT PWCHAR pBuffer,
  385. IN WORD wType
  386. )
  387. {
  388. PSTR pstr;
  389. pstr = private_StringForRecordType( wType );
  390. if ( pstr )
  391. {
  392. swprintf( pBuffer, L"%S", pstr );
  393. }
  394. else
  395. {
  396. swprintf( pBuffer, L"%u", wType );
  397. }
  398. return pstr ? TRUE : FALSE;
  399. }
  400. BOOL
  401. _fastcall
  402. Dns_IsAMailboxType(
  403. IN WORD wType
  404. )
  405. {
  406. return( wType == DNS_TYPE_MB ||
  407. wType == DNS_TYPE_MG ||
  408. wType == DNS_TYPE_MR );
  409. }
  410. BOOL
  411. _fastcall
  412. Dns_IsUpdateType(
  413. IN WORD wType
  414. )
  415. {
  416. return( wType != 0 &&
  417. ( wType < DNS_TYPE_OPT ||
  418. (wType < DNS_TYPE_ADDRS && wType != DNS_TYPE_OPT) ) );
  419. }
  420. //
  421. // RPC-able record types
  422. //
  423. BOOL IsRpcTypeTable[] =
  424. {
  425. 0, // ZERO
  426. 1, // A
  427. 1, // NS
  428. 1, // MD
  429. 1, // MF
  430. 1, // CNAME
  431. 1, // SOA
  432. 1, // MB
  433. 1, // MG
  434. 1, // MR
  435. 0, // NULL
  436. 0, // WKS
  437. 1, // PTR
  438. 0, // HINFO
  439. 1, // MINFO
  440. 1, // MX
  441. 0, // TXT
  442. 1, // RP
  443. 1, // AFSDB
  444. 0, // X25
  445. 0, // ISDN
  446. 0, // RT
  447. 0, // NSAP
  448. 0, // NSAPPTR
  449. 0, // SIG
  450. 0, // KEY
  451. 0, // PX
  452. 0, // GPOS
  453. 1, // AAAA
  454. 0, // LOC
  455. 0, // NXT
  456. 0, // EID
  457. 0, // NIMLOC
  458. 1, // SRV
  459. 1, // ATMA
  460. 0, // NAPTR
  461. 0, // KX
  462. 0, // CERT
  463. 0, // A6
  464. 0, // DNAME
  465. 0, // SINK
  466. 0, // OPT
  467. 0, // 42
  468. 0, // 43
  469. 0, // 44
  470. 0, // 45
  471. 0, // 46
  472. 0, // 47
  473. 0, // 48
  474. };
  475. BOOL
  476. Dns_IsRpcRecordType(
  477. IN WORD wType
  478. )
  479. /*++
  480. Routine Description:
  481. Check if valid to RPC records of this type.
  482. MIDL compiler has problem with a union of types of varying
  483. length (no clue why -- i can write the code). This function
  484. allows us to screen them out.
  485. Arguments:
  486. wType -- type to check
  487. Return Value:
  488. None
  489. --*/
  490. {
  491. if ( wType < MAX_SELF_INDEXED_TYPE )
  492. {
  493. return IsRpcTypeTable[ wType ];
  494. }
  495. else
  496. {
  497. return FALSE;
  498. }
  499. }
  500. //
  501. // RR type specific conversions
  502. //
  503. //
  504. // Text string type routine
  505. //
  506. BOOL
  507. Dns_IsStringCountValidForTextType(
  508. IN WORD wType,
  509. IN WORD StringCount
  510. )
  511. /*++
  512. Routine Description:
  513. Verify a valid count of strings for the particular text
  514. string type.
  515. HINFO -- 2
  516. ISDN -- 1 or 2
  517. TXT -- any number
  518. X25 -- 1
  519. Arguments:
  520. wType -- type
  521. StringCount -- count of strings
  522. Return Value:
  523. TRUE if string count is acceptable for type.
  524. FALSE otherwise.
  525. --*/
  526. {
  527. switch ( wType )
  528. {
  529. case DNS_TYPE_HINFO:
  530. return ( StringCount == 2 );
  531. case DNS_TYPE_ISDN:
  532. return ( StringCount == 1 || StringCount == 2 );
  533. case DNS_TYPE_X25:
  534. return ( StringCount == 1 );
  535. default:
  536. return( TRUE );
  537. }
  538. }
  539. //
  540. // WINS flag table
  541. //
  542. // Associates a WINS flag with the string used for it in database
  543. // files.
  544. //
  545. DNS_FLAG_TABLE_ENTRY WinsFlagTable[] =
  546. {
  547. // value mask string
  548. DNS_WINS_FLAG_SCOPE, DNS_WINS_FLAG_SCOPE, "SCOPE",
  549. DNS_WINS_FLAG_LOCAL, DNS_WINS_FLAG_LOCAL, "LOCAL",
  550. 0 , 0 , NULL
  551. };
  552. DWORD
  553. Dns_WinsRecordFlagForString(
  554. IN PCHAR pchName,
  555. IN INT cchNameLength
  556. )
  557. /*++
  558. Routine Description:
  559. Retrieve WINS mapping flag corresponding to string.
  560. Arguments:
  561. pchName - ptr to string
  562. cchNameLength - length of string
  563. Return Value:
  564. flag corresponding to string, if found.
  565. WINS_FLAG_ERROR otherwise.
  566. --*/
  567. {
  568. return Dns_FlagForString(
  569. WinsFlagTable,
  570. TRUE, // ignore case
  571. pchName,
  572. cchNameLength );
  573. }
  574. PCHAR
  575. Dns_WinsRecordFlagString(
  576. IN DWORD dwFlag,
  577. IN OUT PCHAR pchFlag
  578. )
  579. /*++
  580. Routine Description:
  581. Retrieve string corresponding to a given mapping type.
  582. Arguments:
  583. dwFlag -- WINS mapping type string
  584. pchFlag -- buffer to write flag to
  585. Return Value:
  586. Ptr to mapping mneumonic string.
  587. NULL if unknown mapping type.
  588. --*/
  589. {
  590. return Dns_WriteStringsForFlag(
  591. WinsFlagTable,
  592. dwFlag,
  593. pchFlag );
  594. }
  595. //
  596. // WKS record conversions
  597. //
  598. #if 0
  599. PCHAR
  600. Dns_GetWksServicesString(
  601. IN INT Protocol,
  602. IN PBYTE ServicesBitmask,
  603. IN WORD wBitmaskLength
  604. )
  605. /*++
  606. Routine Description:
  607. Get list of services in WKS record.
  608. Arguments:
  609. pRR - flat WKS record being written
  610. Return Value:
  611. Ptr to services string, caller MUST free.
  612. NULL on error.
  613. --*/
  614. {
  615. struct servent * pServent;
  616. struct protoent * pProtoent;
  617. INT i;
  618. DWORD length;
  619. USHORT port;
  620. UCHAR portBitmask;
  621. CHAR buffer[ WKS_SERVICES_BUFFER_SIZE ];
  622. PCHAR pch = buffer;
  623. PCHAR pchstart;
  624. PCHAR pchstop;
  625. // protocol
  626. pProtoent = getprotobynumber( iProtocol );
  627. if ( ! pProtoent )
  628. {
  629. DNS_PRINT((
  630. "ERROR: Unable to find protocol %d, writing WKS record.\n",
  631. (INT) pRR->Data.WKS.chProtocol
  632. ));
  633. return( NULL );
  634. }
  635. //
  636. // services
  637. //
  638. // find each bit set in bitmask, lookup and write service
  639. // corresponding to that port
  640. //
  641. // note, that since that port zero is the front of port bitmask,
  642. // lowest ports are the highest bits in each byte
  643. //
  644. pchstart = pch;
  645. pchstop = pch + WKS_SERVICES_BUFFER_SIZE;
  646. for ( i = 0;
  647. i < wBitmaskLength
  648. i++ )
  649. {
  650. portBitmask = (UCHAR) ServicesBitmask[i];
  651. port = i * 8;
  652. // write service name for each bit set in byte
  653. // - get out as soon byte is empty of ports
  654. // - terminate each name with blank (until last)
  655. while ( bBitmask )
  656. {
  657. if ( bBitmask & 0x80 )
  658. {
  659. pServent = getservbyport(
  660. (INT) htons(port),
  661. pProtoent->p_name );
  662. if ( pServent )
  663. {
  664. INT copyCount = strlen(pServent->s_name);
  665. pch++;
  666. if ( pchstop - pch <= copyCount+1 )
  667. {
  668. return( NULL );
  669. }
  670. RtlCopyMemory(
  671. pch,
  672. pServent->s_name,
  673. copyCount );
  674. pch += copyCount;
  675. *pch = ' ';
  676. }
  677. else
  678. {
  679. DNS_PRINT((
  680. "ERROR: Unable to find service for port %d, "
  681. "writing WKS record.\n",
  682. port
  683. ));
  684. pch += sprintf( pch, "%d", port );
  685. }
  686. }
  687. port++; // next service port
  688. bBitmask <<= 1; // shift mask up to read next port
  689. }
  690. }
  691. // NULL terminate services string
  692. // and determine length
  693. *pch++ = 0;
  694. length = pch - pchstart;
  695. // allocate copy of this string
  696. pch = ALLOCATE_HEAP( length );
  697. if ( !pch )
  698. {
  699. SetLastError( DNS_ERROR_NO_MEMORY );
  700. return( NULL );
  701. }
  702. RtlCopyMemory(
  703. pch,
  704. pchstart,
  705. length );
  706. return( pch );
  707. }
  708. #endif
  709. #if 0
  710. DNS_STATUS
  711. Dns_WksRecordToStrings(
  712. IN PDNS_WKS_DATA pWksData,
  713. IN WORD wLength,
  714. OUT LPSTR * ppszIpAddress,
  715. OUT LPSTR * ppszProtocol,
  716. OUT LPSTR * ppszServices
  717. )
  718. /*++
  719. Routine Description:
  720. Get string representation of WKS data.
  721. Arguments:
  722. Return Value:
  723. ERROR_SUCCESS if successful.
  724. Error code on failure.
  725. --*/
  726. {
  727. //
  728. // record must contain IP and protocol
  729. //
  730. if ( wLength < SIZEOF_WKS_FIXED_DATA )
  731. {
  732. return( ERROR_INVALID_DATA );
  733. }
  734. //
  735. // convert IP
  736. //
  737. if ( ppszIpAddress )
  738. {
  739. LPSTR pszip;
  740. pszip = ALLOCATE_HEAP( IP_ADDRESS_STRING_LENGTH+1 );
  741. if ( ! pszip )
  742. {
  743. return( GetLastError() );
  744. }
  745. strcpy( pszip, IP4_STRING( pWksData->ipAddress ) );
  746. }
  747. //
  748. // convert protocol
  749. //
  750. pProtoent = getprotobyname( pszNameBuffer );
  751. if ( ! pProtoent || pProtoent->p_proto >= MAXUCHAR )
  752. {
  753. dns_LogFileParsingError(
  754. DNS_EVENT_UNKNOWN_PROTOCOL,
  755. pParseInfo,
  756. Argv );
  757. return( DNS_ERROR_INVALID_TOKEN );
  758. }
  759. //
  760. // get port for each service
  761. // - if digit, then use port number
  762. // - if not digit, then service name
  763. // - save max port for determining RR length
  764. //
  765. for ( i=1; i<Argc; i++ )
  766. {
  767. if ( dns_ParseDwordToken(
  768. & portDword,
  769. & Argv[i],
  770. NULL ) )
  771. {
  772. if ( portDword > MAXWORD )
  773. {
  774. return( DNS_ERROR_INVALID_TOKEN );
  775. }
  776. port = (WORD) portDword;
  777. }
  778. else
  779. {
  780. if ( ! dns_MakeTokenString(
  781. pszNameBuffer,
  782. & Argv[i],
  783. pParseInfo ) )
  784. {
  785. return( DNS_ERROR_INVALID_TOKEN );
  786. }
  787. pServent = getservbyname(
  788. pszNameBuffer,
  789. pProtoent->p_name );
  790. if ( ! pServent )
  791. {
  792. dns_LogFileParsingError(
  793. DNS_EVENT_UNKNOWN_SERVICE,
  794. pParseInfo,
  795. & Argv[i] );
  796. return( DNS_ERROR_INVALID_TOKEN );
  797. }
  798. port = ntohs( pServent->s_port );
  799. }
  800. portArray[ i ] = port;
  801. if ( port > maxPort )
  802. {
  803. maxPort = port;
  804. }
  805. }
  806. //
  807. // allocate required length
  808. // - fixed length, plus bitmask covering max port
  809. //
  810. wbitmaskLength = maxPort/8 + 1;
  811. prr = RRecordAllocate(
  812. (WORD)(SIZEOF_WKS_FIXED_DATA + wbitmaskLength) );
  813. if ( !prr )
  814. {
  815. return( DNS_ERROR_NO_MEMORY );
  816. }
  817. //
  818. // copy fixed fields -- IP and protocol
  819. //
  820. prr->Data.WKS.ipAddress = ipAddress;
  821. prr->Data.WKS.chProtocol = (UCHAR) pProtoent->p_proto;
  822. //
  823. // build bitmask from port array
  824. // - clear port array first
  825. //
  826. // note that bitmask is just flat run of bits
  827. // hence lowest port in byte, corresponds to highest bit
  828. // highest port in byte, corresponds to lowest bit and
  829. // requires no shift
  830. //
  831. bitmaskBytes = prr->Data.WKS.bBitMask;
  832. RtlZeroMemory(
  833. bitmaskBytes,
  834. (size_t) wbitmaskLength );
  835. for ( i=1; i<Argc; i++ )
  836. {
  837. port = portArray[ i ];
  838. bit = port & 0x7; // mod 8
  839. port = port >> 3; // divide by 8
  840. bitmaskBytes[ port ] |= 1 << (7-bit);
  841. }
  842. // return ptr to new WKS record
  843. *ppRR = prr;
  844. return( ERROR_SUCCESS );
  845. }
  846. #endif
  847. //
  848. // Security KEY\SIG record routines
  849. //
  850. #define DNSSEC_ERROR_NOSTRING (-1)
  851. //
  852. // KEY flags table
  853. //
  854. // Note that number-to-string mapping is NOT UNIQUE.
  855. // Zero is in the table a few times are multiple bit fields may have a
  856. // zero value which is given a particular mnemonic.
  857. //
  858. DNS_FLAG_TABLE_ENTRY KeyFlagTable[] =
  859. {
  860. // value mask string
  861. 0x0001, 0x0001, "NOAUTH",
  862. 0x0002, 0x0002, "NOCONF",
  863. 0x0004, 0x0004, "FLAG2",
  864. 0x0008, 0x0008, "EXTEND",
  865. 0x0010, 0x0010, "FLAG4",
  866. 0x0020, 0x0020, "FLAG5",
  867. // bits 6,7// bits 6,7 are name type
  868. 0x0000, 0x00c0, "USER",
  869. 0x0040, 0x00c0, "ZONE",
  870. 0x0080, 0x00c0, "HOST",
  871. 0x00c0, 0x00c0, "NTPE3",
  872. // bits 8-1// bits 8-11 are reserved for future use
  873. 0x0100, 0x0100, "FLAG8",
  874. 0x0200, 0x0200, "FLAG9",
  875. 0x0400, 0x0400, "FLAG10",
  876. 0x0800, 0x0800, "FLAG11",
  877. // bits 12-// bits 12-15 are sig field
  878. 0x0000, 0xf000, "SIG0",
  879. 0x1000, 0xf000, "SIG1",
  880. 0x2000, 0xf000, "SIG2",
  881. 0x3000, 0xf000, "SIG3",
  882. 0x4000, 0xf000, "SIG4",
  883. 0x5000, 0xf000, "SIG5",
  884. 0x6000, 0xf000, "SIG6",
  885. 0x7000, 0xf000, "SIG7",
  886. 0x8000, 0xf000, "SIG8",
  887. 0x9000, 0xf000, "SIG9",
  888. 0xa000, 0xf000, "SIG10",
  889. 0xb000, 0xf000, "SIG11",
  890. 0xc000, 0xf000, "SIG12",
  891. 0xd000, 0xf000, "SIG13",
  892. 0xe000, 0xf000, "SIG14",
  893. 0xf000, 0xf000, "SIG15",
  894. 0 , 0 , NULL
  895. };
  896. //
  897. // KEY protocol table
  898. //
  899. DNS_VALUE_TABLE_ENTRY KeyProtocolTable[] =
  900. {
  901. 0, "NONE" ,
  902. 1, "TLS" ,
  903. 2, "EMAIL" ,
  904. 3, "DNSSEC" ,
  905. 4, "IPSEC" ,
  906. 0, NULL
  907. };
  908. //
  909. // Security alogrithm table
  910. //
  911. DNS_VALUE_TABLE_ENTRY DnssecAlgorithmTable[] =
  912. {
  913. 1, "RSA/MD5" ,
  914. 2, "DIFFIE-HELLMAN" ,
  915. 3, "DSA" ,
  916. 253, "NULL" ,
  917. 254, "PRIVATE" ,
  918. 0, NULL
  919. };
  920. WORD
  921. Dns_KeyRecordFlagForString(
  922. IN PCHAR pchName,
  923. IN INT cchNameLength
  924. )
  925. /*++
  926. Routine Description:
  927. Retrieve KEY record flag corresponding to a particular
  928. string mnemonics.
  929. Arguments:
  930. pchName - ptr to string
  931. cchNameLength - length of string
  932. Return Value:
  933. flag corresponding to string, if found.
  934. DNSSEC_ERROR_NOSTRING otherwise.
  935. --*/
  936. {
  937. return (WORD) Dns_FlagForString(
  938. KeyFlagTable,
  939. FALSE, // case sensitive (all upcase)
  940. pchName,
  941. cchNameLength );
  942. }
  943. PCHAR
  944. Dns_KeyRecordFlagString(
  945. IN DWORD dwFlag,
  946. IN OUT PCHAR pchFlag
  947. )
  948. /*++
  949. Routine Description:
  950. Write mnemonics corresponding to string.
  951. Arguments:
  952. dwFlag -- KEY mapping type string
  953. pchFlag -- buffer to write flag to
  954. Return Value:
  955. Ptr to mapping mneumonic string.
  956. NULL if unknown mapping type.
  957. --*/
  958. {
  959. return Dns_WriteStringsForFlag(
  960. KeyFlagTable,
  961. dwFlag,
  962. pchFlag );
  963. }
  964. UCHAR
  965. Dns_KeyRecordProtocolForString(
  966. IN PCHAR pchName,
  967. IN INT cchNameLength
  968. )
  969. /*++
  970. Routine Description:
  971. Retrieve KEY record protocol for string.
  972. Arguments:
  973. pchName - ptr to string
  974. cchNameLength - length of string
  975. Return Value:
  976. Protocol value corresponding to string, if found.
  977. DNSSEC_ERROR_NOSTRING otherwise.
  978. --*/
  979. {
  980. return (UCHAR) Dns_ValueForString(
  981. KeyProtocolTable,
  982. FALSE, // case sensitive (all upcase)
  983. pchName,
  984. cchNameLength );
  985. }
  986. PCHAR
  987. Dns_GetKeyProtocolString(
  988. IN UCHAR uchProtocol
  989. )
  990. /*++
  991. Routine Description:
  992. Retrieve KEY protocol string for protocol.
  993. Arguments:
  994. dwProtocol - KEY protocol to map to string
  995. Return Value:
  996. Ptr to protocol mneumonic for string.
  997. NULL if unknown protocol.
  998. --*/
  999. {
  1000. return Dns_GetStringForValue(
  1001. KeyProtocolTable,
  1002. (DWORD) uchProtocol );
  1003. }
  1004. UCHAR
  1005. Dns_SecurityAlgorithmForString(
  1006. IN PCHAR pchName,
  1007. IN INT cchNameLength
  1008. )
  1009. /*++
  1010. Routine Description:
  1011. Retrieve DNSSEC algorithm for string.
  1012. Arguments:
  1013. pchName - ptr to string
  1014. cchNameLength - length of string
  1015. Return Value:
  1016. Algorithm value corresponding to string, if found.
  1017. DNSSEC_ERROR_NOSTRING otherwise.
  1018. --*/
  1019. {
  1020. return (UCHAR) Dns_ValueForString(
  1021. DnssecAlgorithmTable,
  1022. FALSE, // case sensitive (all upcase)
  1023. pchName,
  1024. cchNameLength );
  1025. }
  1026. PCHAR
  1027. Dns_GetDnssecAlgorithmString(
  1028. IN UCHAR uchAlgorithm
  1029. )
  1030. /*++
  1031. Routine Description:
  1032. Retrieve DNSSEC algorithm string.
  1033. Arguments:
  1034. dwAlgorithm - security alogorithm to map to string
  1035. Return Value:
  1036. Ptr to algorithm string if found.
  1037. NULL if unknown algorithm.
  1038. --*/
  1039. {
  1040. return Dns_GetStringForValue(
  1041. DnssecAlgorithmTable,
  1042. (DWORD) uchAlgorithm );
  1043. }
  1044. //
  1045. // Security base64 conversions.
  1046. //
  1047. // Keys and signatures are represented in base 64 mapping for human use.
  1048. // (Why? Why not just use give the hex representation?
  1049. // All this for 33% compression -- amazing.)
  1050. //
  1051. #if 0
  1052. // forward lookup table doesn't buy much, simple function actually smaller
  1053. // and not much slower
  1054. UCHAR DnsSecurityBase64Mapping[] =
  1055. {
  1056. // 0-31 unprintable
  1057. 0xff, 0xff, 0xff, 0xff,
  1058. 0xff, 0xff, 0xff, 0xff,
  1059. 0xff, 0xff, 0xff, 0xff,
  1060. 0xff, 0xff, 0xff, 0xff,
  1061. 0xff, 0xff, 0xff, 0xff,
  1062. 0xff, 0xff, 0xff, 0xff,
  1063. 0xff, 0xff, 0xff, 0xff,
  1064. 0xff, 0xff, 0xff, 0xff,
  1065. // '0' - '9' map
  1066. 0xff, 0xff, 0xff, 0xff,
  1067. 0xff, 0xff, 0xff, 0xff,
  1068. 0xff, 0xff, 0xff, 62, // '+' => 62
  1069. 0xff, 0xff, 0xff, 63, // '/' => 63
  1070. 52, 53, 54, 55, // 0-9 map to 52-61
  1071. 0xff, 0xff, 0xff, 0xff,
  1072. 0xff, 0xff, 0xff, 0xff,
  1073. 0xff, 0xff, 0xff, 0xff,
  1074. }
  1075. #endif
  1076. //
  1077. // Security KEY, SIG 6-bit values to base64 character mapping
  1078. //
  1079. CHAR DnsSecurityBase64Mapping[] =
  1080. {
  1081. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
  1082. 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
  1083. 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
  1084. 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
  1085. 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
  1086. 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
  1087. 'w', 'x', 'y', 'z', '0', '1', '2', '3',
  1088. '4', '5', '6', '7', '8', '9', '+', '/'
  1089. };
  1090. #define SECURITY_PAD_CHAR ('=')
  1091. UCHAR
  1092. Dns_SecurityBase64CharToBits(
  1093. IN CHAR ch64
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. Get value of security base64 character.
  1098. Arguments:
  1099. ch64 -- character in security base64
  1100. Return Value:
  1101. Value of character, only low 6-bits are significant, high bits zero.
  1102. (-1) if not a base64 character.
  1103. --*/
  1104. {
  1105. // A - Z map to 0 -25
  1106. // a - z map to 26-51
  1107. // 0 - 9 map to 52-61
  1108. // + is 62
  1109. // / is 63
  1110. // could do a lookup table
  1111. // since we can in general complete mapping with an average of three
  1112. // comparisons, just encode
  1113. if ( ch64 >= 'a' )
  1114. {
  1115. if ( ch64 <= 'z' )
  1116. {
  1117. return( ch64 - 'a' + 26 );
  1118. }
  1119. }
  1120. else if ( ch64 >= 'A' )
  1121. {
  1122. if ( ch64 <= 'Z' )
  1123. {
  1124. return( ch64 - 'A' );
  1125. }
  1126. }
  1127. else if ( ch64 >= '0')
  1128. {
  1129. if ( ch64 <= '9' )
  1130. {
  1131. return( ch64 - '0' + 52 );
  1132. }
  1133. else if ( ch64 == '=' )
  1134. {
  1135. //*pPadCount++;
  1136. return( 0 );
  1137. }
  1138. }
  1139. else if ( ch64 == '+' )
  1140. {
  1141. return( 62 );
  1142. }
  1143. else if ( ch64 == '/' )
  1144. {
  1145. return( 63 );
  1146. }
  1147. // all misses fall here
  1148. return (UCHAR)(-1);
  1149. }
  1150. DNS_STATUS
  1151. Dns_SecurityBase64StringToKey(
  1152. OUT PBYTE pKey,
  1153. OUT PDWORD pKeyLength,
  1154. IN PCHAR pchString,
  1155. IN DWORD cchLength
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. Write base64 representation of key to buffer.
  1160. Arguments:
  1161. pchString - base64 string to write
  1162. cchLength - length of string
  1163. pKey - ptr to key to write
  1164. Return Value:
  1165. None
  1166. --*/
  1167. {
  1168. DWORD blend = 0;
  1169. DWORD index = 0;
  1170. UCHAR bits;
  1171. PBYTE pkeyStart = pKey;
  1172. //
  1173. // Mapping is essentially in 24 bit quantums.
  1174. // Take 4 characters of string key and convert to 3 bytes of binary key.
  1175. //
  1176. while ( cchLength-- )
  1177. {
  1178. bits = Dns_SecurityBase64CharToBits( *pchString++ );
  1179. if ( bits >= 64 )
  1180. {
  1181. return ERROR_INVALID_PARAMETER;
  1182. }
  1183. blend <<= 6;
  1184. blend |= bits;
  1185. index++;
  1186. if ( index == 4 )
  1187. {
  1188. index = 0;
  1189. //
  1190. // The first byte of key is top 8 bits of the 24 bit quantum.
  1191. //
  1192. *pKey++ = ( UCHAR ) ( ( blend & 0x00ff0000 ) >> 16 );
  1193. if ( cchLength || *( pchString - 1 ) != SECURITY_PAD_CHAR )
  1194. {
  1195. //
  1196. // There is no padding so the next two bytes of key
  1197. // are bottom 16 bits of the 24 bit quantum.
  1198. //
  1199. *pKey++ = ( UCHAR ) ( ( blend & 0x0000ff00 ) >> 8 );
  1200. *pKey++ = ( UCHAR ) ( blend & 0x000000ff );
  1201. }
  1202. else if ( *( pchString - 2 ) != SECURITY_PAD_CHAR )
  1203. {
  1204. //
  1205. // There is one pad character, so we need to get one
  1206. // more byte of key out of the 24 bit quantum. Make sure
  1207. // that there are no one bits in the bottom 8 bits of the
  1208. // quantum.
  1209. //
  1210. if ( blend & 0x000000ff )
  1211. {
  1212. return ERROR_INVALID_PARAMETER;
  1213. }
  1214. *pKey++ = ( UCHAR ) ( ( blend & 0x0000ff00 ) >> 8 );
  1215. }
  1216. else
  1217. {
  1218. //
  1219. // There are two pad characters. Make sure that there
  1220. // are no one bits in the bottom 16 bits of the quantum.
  1221. //
  1222. if ( blend & 0x0000ffff )
  1223. {
  1224. return ERROR_INVALID_PARAMETER;
  1225. }
  1226. }
  1227. blend = 0;
  1228. }
  1229. }
  1230. //
  1231. // Base64 representation should always be padded out to an even
  1232. // multiple of 4 characters.
  1233. //
  1234. if ( index == 0 )
  1235. {
  1236. //
  1237. // Key length does not include padding.
  1238. //
  1239. *pKeyLength = ( DWORD ) ( pKey - pkeyStart );
  1240. return ERROR_SUCCESS;
  1241. }
  1242. return ERROR_INVALID_PARAMETER;
  1243. }
  1244. PCHAR
  1245. Dns_SecurityKeyToBase64String(
  1246. IN PBYTE pKey,
  1247. IN DWORD KeyLength,
  1248. OUT PCHAR pchBuffer
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. Write base64 representation of key to buffer.
  1253. Arguments:
  1254. pKey - ptr to key to write
  1255. KeyLength - length of key in bytes
  1256. pchBuffer - buffer to write to (must be adequate for key length)
  1257. Return Value:
  1258. Ptr to next byte in buffer after string.
  1259. --*/
  1260. {
  1261. DWORD blend = 0;
  1262. DWORD index = 0;
  1263. //
  1264. // mapping is essentially in 24bit blocks
  1265. // read three bytes of key and transform into four 64bit characters
  1266. //
  1267. while ( KeyLength-- )
  1268. {
  1269. blend <<= 8;
  1270. blend += *pKey++;
  1271. index++;
  1272. if ( index == 3 )
  1273. {
  1274. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00fc0000) >> 18 ];
  1275. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x0003f000) >> 12 ];
  1276. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00000fc0) >> 6 ];
  1277. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x0000003f) ];
  1278. blend = 0;
  1279. index = 0;
  1280. }
  1281. }
  1282. //
  1283. // key terminates on byte boundary, but not necessarily 24bit block boundary
  1284. // shift to fill 24bit block filling with zeros
  1285. // if two bytes written
  1286. // => write three 6-bits chars and one pad
  1287. // if one byte written
  1288. // => write two 6-bits chars and two pads
  1289. //
  1290. if ( index )
  1291. {
  1292. blend <<= (8 * (3-index));
  1293. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00fc0000) >> 18 ];
  1294. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x0003f000) >> 12 ];
  1295. if ( index == 2 )
  1296. {
  1297. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00000fc0) >> 6 ];
  1298. }
  1299. else
  1300. {
  1301. *pchBuffer++ = SECURITY_PAD_CHAR;
  1302. }
  1303. *pchBuffer++ = SECURITY_PAD_CHAR;
  1304. }
  1305. return( pchBuffer );
  1306. }
  1307. //
  1308. // Hex digit \ Hex char mapping.
  1309. //
  1310. // This stuff ought to be in system (CRTs) somewhere but apparently isn't.
  1311. //
  1312. UCHAR HexCharToHexDigitTable[] =
  1313. {
  1314. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0-47 invalid
  1315. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1316. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1317. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1318. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1319. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1320. 0x0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0-9 chars map to 0-9
  1321. 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1322. 0xff, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xff, // A-F chars map to 10-15
  1323. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1324. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1325. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1326. 0xff, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xff, // a-f chars map to 10-15
  1327. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1328. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1329. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1330. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // above 127 invalid
  1331. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1332. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1333. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1334. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1335. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1336. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1337. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1338. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1339. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1340. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1341. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1342. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1343. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1344. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1345. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1346. };
  1347. UCHAR HexDigitToHexCharTable[] =
  1348. {
  1349. '0', '1', '2', '3',
  1350. '4', '5', '6', '7',
  1351. '8', '9', 'a', 'b',
  1352. 'c', 'd', 'e', 'f'
  1353. };
  1354. #define HexCharToHexDigit(_ch) ( HexCharToHexDigitTable[(_ch)] )
  1355. #define HexDigitToHexChar(_d) ( HexDigitToHexCharTable[(_d)] )
  1356. time_t
  1357. makeGMT(
  1358. IN struct tm * tm
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. This function is like mktime for GMT times. The CRT is missing such
  1363. a function, unfortunately. Which is weird, because it does provide
  1364. gmtime() for the reverse conversion.
  1365. //
  1366. // DCR: add makeGMT() to CRT dll?
  1367. //
  1368. Arguments:
  1369. tm - ptr to tm struct (tm_dst, tm_yday, tm_wday are all ignored)
  1370. Return Value:
  1371. Returns the time_t corresponding to the time in the tm struct,
  1372. assuming GMT.
  1373. --*/
  1374. {
  1375. static const int daysInMonth[ 12 ] =
  1376. { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  1377. time_t gmt = 0;
  1378. int i;
  1379. int j;
  1380. #define IS_LEAP_YEAR(x) \
  1381. (( ((x)%4)==0 && ((x)%100)!=0 ) || ((x)%400)==0 )
  1382. #define SECONDS_PER_DAY (60*60*24)
  1383. //
  1384. // Years
  1385. //
  1386. j = 0;
  1387. for ( i = 70; i < tm->tm_year; i++ )
  1388. {
  1389. // j += IS_LEAP_YEAR( 1900 + i ) ? 366 : 365; // Days in year.
  1390. if ( IS_LEAP_YEAR( 1900 + i ) )
  1391. j += 366; // Days in year.
  1392. else
  1393. j += 365; // Days in year.
  1394. }
  1395. gmt += j * SECONDS_PER_DAY;
  1396. //
  1397. // Months
  1398. //
  1399. j = 0;
  1400. for ( i = 0; i < tm->tm_mon; i++ )
  1401. {
  1402. j += daysInMonth[ i ]; // Days in month.
  1403. if ( i == 1 && IS_LEAP_YEAR( 1900 + tm->tm_year ) )
  1404. {
  1405. ++j; // Add February 29.
  1406. }
  1407. }
  1408. gmt += j * SECONDS_PER_DAY;
  1409. //
  1410. // Days, hours, minutes, seconds
  1411. //
  1412. gmt += ( tm->tm_mday - 1 ) * SECONDS_PER_DAY;
  1413. gmt += tm->tm_hour * 60 * 60;
  1414. gmt += tm->tm_min * 60;
  1415. gmt += tm->tm_sec;
  1416. return gmt;
  1417. }
  1418. LONG
  1419. Dns_ParseSigTime(
  1420. IN PCHAR pTimeString,
  1421. IN INT cchLength
  1422. )
  1423. /*++
  1424. Routine Description:
  1425. Parse time string into a time_t value. The time string will be in
  1426. the format: YYYYMMDDHHMMSS. See RFC2535 section 7.2.
  1427. It is assumed that the time is GMT, not local time, but I have not
  1428. found this in an RFC or other document (it just makes sense).
  1429. Arguments:
  1430. pTimeString - pointer to time string
  1431. cchLength - length of time string
  1432. Return Value:
  1433. Returns -1 on failure.
  1434. --*/
  1435. {
  1436. time_t timeValue = -1;
  1437. struct tm t = { 0 };
  1438. CHAR szVal[ 10 ];
  1439. PCHAR pch = pTimeString;
  1440. if ( cchLength == 0 )
  1441. {
  1442. cchLength = strlen( pch );
  1443. }
  1444. if ( cchLength != 14 )
  1445. {
  1446. goto Cleanup;
  1447. }
  1448. RtlCopyMemory( szVal, pch, 4 );
  1449. szVal[ 4 ] = '\0';
  1450. t.tm_year = atoi( szVal ) - 1900;
  1451. RtlCopyMemory( szVal, pch + 4, 2 );
  1452. szVal[ 2 ] = '\0';
  1453. t.tm_mon = atoi( szVal ) - 1;
  1454. RtlCopyMemory( szVal, pch + 6, 2 );
  1455. t.tm_mday = atoi( szVal );
  1456. RtlCopyMemory( szVal, pch + 8, 2 );
  1457. t.tm_hour = atoi( szVal );
  1458. RtlCopyMemory( szVal, pch + 10, 2 );
  1459. t.tm_min = atoi( szVal );
  1460. RtlCopyMemory( szVal, pch + 12, 2 );
  1461. t.tm_sec = atoi( szVal );
  1462. timeValue = makeGMT( &t );
  1463. Cleanup:
  1464. return ( LONG ) timeValue;
  1465. } // Dns_ParseSigTime
  1466. PCHAR
  1467. Dns_SigTimeString(
  1468. IN LONG SigTime,
  1469. OUT PCHAR pchBuffer
  1470. )
  1471. /*++
  1472. Routine Description:
  1473. Formats the input time in the buffer in YYYYMMDDHHMMSS format.
  1474. See RFC 2535 section 7.2 for spec.
  1475. Arguments:
  1476. SigTime - time to convert to string format in HOST byte order
  1477. pchBuffer - output buffer - must be 15 chars minimum
  1478. Return Value:
  1479. pchBuffer
  1480. --*/
  1481. {
  1482. time_t st = SigTime;
  1483. struct tm * t;
  1484. t = gmtime( &st );
  1485. if ( !t )
  1486. {
  1487. *pchBuffer = '\0';
  1488. goto Cleanup;
  1489. }
  1490. sprintf(
  1491. pchBuffer,
  1492. "%04d%02d%02d%02d%02d%02d",
  1493. t->tm_year + 1900,
  1494. t->tm_mon + 1,
  1495. t->tm_mday,
  1496. t->tm_hour,
  1497. t->tm_min,
  1498. t->tm_sec );
  1499. Cleanup:
  1500. return pchBuffer;
  1501. } // SigTimeString
  1502. //
  1503. // ATMA record conversions
  1504. //
  1505. #define ATMA_AESA_HEX_DIGIT_COUNT (40)
  1506. #define ATMA_AESA_RECORD_LENGTH (21)
  1507. DWORD
  1508. Dns_AtmaAddressLengthForAddressString(
  1509. IN PCHAR pchString,
  1510. IN DWORD dwStringLength
  1511. )
  1512. /*++
  1513. Routine Description:
  1514. Find length of ATMA address corresponding to ATMA address string.
  1515. Arguments:
  1516. pchString - address string
  1517. dwStringLength - address string length
  1518. Return Value:
  1519. Length of ATMA address -- includes the format\type byte.
  1520. Non-zero value indicates successful conversion.
  1521. Zero indicates bad address string.
  1522. --*/
  1523. {
  1524. PCHAR pchstringEnd;
  1525. DWORD length = 0;
  1526. UCHAR ch;
  1527. DNSDBG( PARSE2, (
  1528. "Dns_AtmaLengthForAddressString()\n"
  1529. "\tpchString = %p\n",
  1530. dwStringLength,
  1531. pchString,
  1532. pchString ));
  1533. //
  1534. // get string length if not given
  1535. //
  1536. if ( ! dwStringLength )
  1537. {
  1538. dwStringLength = strlen( pchString );
  1539. }
  1540. pchstringEnd = pchString + dwStringLength;
  1541. //
  1542. // get address length
  1543. //
  1544. // E164 type
  1545. // ex. +358.400.1234567
  1546. // - '+' to indicate E164
  1547. // - chars map one-to-one into address
  1548. // - arbitrarily placed "." separators
  1549. //
  1550. if ( *pchString == '+' )
  1551. {
  1552. pchString++;
  1553. length++;
  1554. while( pchString < pchstringEnd )
  1555. {
  1556. if ( *pchString++ != '.' )
  1557. {
  1558. length++;
  1559. }
  1560. }
  1561. return( length );
  1562. }
  1563. //
  1564. // AESA type
  1565. // ex. 39.246f.123456789abcdef0123.00123456789a.00
  1566. // - 40 hex digits, mapping to 20 bytes
  1567. // - arbitrarily placed "." separators
  1568. //
  1569. else // AESA format
  1570. {
  1571. while( pchString < pchstringEnd )
  1572. {
  1573. ch = *pchString++;
  1574. if ( ch != '.' )
  1575. {
  1576. ch = HexCharToHexDigit(ch);
  1577. if ( ch > 0xf )
  1578. {
  1579. // bad hex digit
  1580. DNSDBG( PARSE2, (
  1581. "ERROR: Parsing ATMA AESA address;\n"
  1582. "\tch = %c not hex digit\n",
  1583. *(pchString-1) ));
  1584. return( 0 );
  1585. }
  1586. length++;
  1587. }
  1588. }
  1589. if ( length == ATMA_AESA_HEX_DIGIT_COUNT )
  1590. {
  1591. return ATMA_AESA_RECORD_LENGTH;
  1592. }
  1593. DNSDBG( PARSE2, (
  1594. "ERROR: Parsing ATMA AESA address;\n"
  1595. "\tinvalid length = %d\n",
  1596. length ));
  1597. return( 0 ); // bad digit count
  1598. }
  1599. }
  1600. DNS_STATUS
  1601. Dns_AtmaStringToAddress(
  1602. OUT PBYTE pAddress,
  1603. IN OUT PDWORD pdwAddrLength,
  1604. IN PCHAR pchString,
  1605. IN DWORD dwStringLength
  1606. )
  1607. /*++
  1608. Routine Description:
  1609. Convert string to ATMA address.
  1610. Arguments:
  1611. pAddress - buffer to receive address
  1612. pdwAddrLength - ptr to DWORD holding buffer length (if MAX_DWORD) no length check
  1613. pchString - address string
  1614. dwStringLength - address string length
  1615. Return Value:
  1616. ERROR_SUCCESS if converted
  1617. ERROR_MORE_DATA if buffer too small.
  1618. ERROR_INVALID_DATA on bum ATMA address string.
  1619. --*/
  1620. {
  1621. UCHAR ch;
  1622. PCHAR pch;
  1623. PCHAR pchstringEnd;
  1624. DWORD length;
  1625. DNSDBG( PARSE2, (
  1626. "Parsing ATMA address %.*s\n"
  1627. "\tpchString = %p\n",
  1628. dwStringLength,
  1629. pchString,
  1630. pchString ));
  1631. //
  1632. // get string length if not given
  1633. //
  1634. if ( ! dwStringLength )
  1635. {
  1636. dwStringLength = strlen( pchString );
  1637. }
  1638. pchstringEnd = pchString + dwStringLength;
  1639. //
  1640. // check for adequate length
  1641. //
  1642. // DCR_PERF: if have max length on ATMA, skip length check
  1643. // allow direct conversion, catching errors there
  1644. //
  1645. length = Dns_AtmaAddressLengthForAddressString(
  1646. pchString,
  1647. dwStringLength );
  1648. if ( length == 0 )
  1649. {
  1650. return( ERROR_INVALID_DATA );
  1651. }
  1652. if ( length > *pdwAddrLength )
  1653. {
  1654. *pdwAddrLength = length;
  1655. return( ERROR_MORE_DATA );
  1656. }
  1657. //
  1658. // read address into buffer
  1659. //
  1660. // E164 type
  1661. // ex. +358.400.1234567
  1662. // - '+' to indicate E164
  1663. // - chars map one-to-one into address
  1664. // - arbitrarily placed "." separators
  1665. //
  1666. pch = pAddress;
  1667. if ( *pchString == '+' )
  1668. {
  1669. *pch++ = DNS_ATMA_FORMAT_E164;
  1670. pchString++;
  1671. while( pchString < pchstringEnd )
  1672. {
  1673. ch = *pchString++;
  1674. if ( ch != '.' )
  1675. {
  1676. *pch++ = ch;
  1677. }
  1678. }
  1679. ASSERT( pch == (PCHAR)pAddress + length );
  1680. }
  1681. //
  1682. // AESA type
  1683. // ex. 39.246f.123456789abcdef0123.00123456789a.00
  1684. // - 40 hex digits, mapping to 20 bytes
  1685. // - arbitrarily placed "." separators
  1686. //
  1687. else // AESA format
  1688. {
  1689. BOOL fodd = FALSE;
  1690. *pch++ = DNS_ATMA_FORMAT_AESA;
  1691. while( pchString < pchstringEnd )
  1692. {
  1693. ch = *pchString++;
  1694. if ( ch != '.' )
  1695. {
  1696. ch = HexCharToHexDigit(ch);
  1697. if ( ch > 0xf )
  1698. {
  1699. ASSERT( FALSE ); // shouldn't hit with test above
  1700. return( ERROR_INVALID_DATA );
  1701. }
  1702. if ( !fodd )
  1703. {
  1704. *pch = (ch << 4);
  1705. fodd = TRUE;
  1706. }
  1707. else
  1708. {
  1709. *pch++ += ch;
  1710. fodd = FALSE;
  1711. }
  1712. }
  1713. }
  1714. ASSERT( !fodd );
  1715. ASSERT( pch == (PCHAR)pAddress + length );
  1716. }
  1717. *pdwAddrLength = length;
  1718. return( ERROR_SUCCESS );
  1719. }
  1720. PCHAR
  1721. Dns_AtmaAddressToString(
  1722. OUT PCHAR pchString,
  1723. IN UCHAR AddrType,
  1724. IN PBYTE pAddress,
  1725. IN DWORD dwAddrLength
  1726. )
  1727. /*++
  1728. Routine Description:
  1729. Convert ATMA address to string format.
  1730. Arguments:
  1731. pchString -- buffer to hold string; MUST be at least
  1732. IPV6_ADDRESS_STRING_LENGTH+1 in length
  1733. pAddress -- ATMA address to convert to string
  1734. dwAddrLength -- length of address
  1735. Return Value:
  1736. Ptr to next location in buffer (the terminating NULL).
  1737. NULL on bogus ATM address.
  1738. --*/
  1739. {
  1740. DWORD count = 0;
  1741. UCHAR ch;
  1742. UCHAR lowDigit;
  1743. //
  1744. // read address into buffer
  1745. //
  1746. // E164 type
  1747. // ex. +358.400.1234567
  1748. // - '+' to indicate E164
  1749. // - chars map one-to-one into address
  1750. // - arbitrarily placed "." separators
  1751. // -> write with separating dots after 3rd and 6th chars
  1752. //
  1753. if ( AddrType == DNS_ATMA_FORMAT_E164 )
  1754. {
  1755. *pchString++ = '+';
  1756. while( count < dwAddrLength )
  1757. {
  1758. if ( count == 3 || count == 6 )
  1759. {
  1760. *pchString++ = '.';
  1761. }
  1762. *pchString++ = pAddress[count++];
  1763. }
  1764. }
  1765. //
  1766. // AESA type
  1767. // ex. 39.246f.123456789abcdef0123.00123456789a.00
  1768. // - 40 hex digits, mapping to 20 bytes
  1769. // - arbitrarily placed "." separators
  1770. // -> write with separators after chars 1,3,13,19
  1771. // (hex digits 2,6,26,38)
  1772. //
  1773. else if ( AddrType == DNS_ATMA_FORMAT_AESA )
  1774. {
  1775. if ( dwAddrLength != DNS_ATMA_AESA_ADDR_LENGTH )
  1776. {
  1777. return( NULL );
  1778. }
  1779. while( count < dwAddrLength )
  1780. {
  1781. if ( count == 1 || count == 3 || count == 13 || count == 19 )
  1782. {
  1783. *pchString++ = '.';
  1784. }
  1785. ch = pAddress[count++];
  1786. // save low hex digit, then get and convert high digit
  1787. lowDigit = ch & 0xf;
  1788. ch >>= 4;
  1789. *pchString++ = HexDigitToHexChar( ch );
  1790. *pchString++ = HexDigitToHexChar( lowDigit );
  1791. }
  1792. // could ASSERT here that have written exactly 44 chars
  1793. }
  1794. // no other ATM address formats supported
  1795. else
  1796. {
  1797. return( NULL );
  1798. }
  1799. *pchString = 0; // NULL terminate
  1800. return( pchString );
  1801. }
  1802. //
  1803. // End record.c
  1804. //