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.

1168 lines
40 KiB

  1. /*
  2. * HrSWInstalledEntry.c v0.10
  3. * Generated in conjunction with Management Factory scripts:
  4. * script version: SNMPv1, 0.16, Apr 25, 1996
  5. * project: D:\TEMP\EXAMPLE\HOSTMIB
  6. ****************************************************************************
  7. * *
  8. * (C) Copyright 1995 DIGITAL EQUIPMENT CORPORATION *
  9. * *
  10. * This software is an unpublished work protected under the *
  11. * the copyright laws of the United States of America, all *
  12. * rights reserved. *
  13. * *
  14. * In the event this software is licensed for use by the United *
  15. * States Government, all use, duplication or disclosure by the *
  16. * United States Government is subject to restrictions as set *
  17. * forth in either subparagraph (c)(1)(ii) of the Rights in *
  18. * Technical Data And Computer Software Clause at DFARS *
  19. * 252.227-7013, or the Commercial Computer Software Restricted *
  20. * Rights Clause at FAR 52.221-19, whichever is applicable. *
  21. * *
  22. ****************************************************************************
  23. *
  24. * Facility:
  25. *
  26. * Windows NT SNMP Extension Agent
  27. *
  28. * Abstract:
  29. *
  30. * This module contains the code for dealing with the get, set, and
  31. * instance name routines for the HrSWInstalledEntry. Actual instrumentation code is
  32. * supplied by the developer.
  33. *
  34. * Functions:
  35. *
  36. * A get and set routine for each attribute in the class.
  37. *
  38. * The routines for instances within the class.
  39. *
  40. * Author:
  41. *
  42. * D. D. Burns @ Webenable Inc
  43. *
  44. * Revision History:
  45. *
  46. * V1.00 - 04/27/97 D. D. Burns Genned: Thu Nov 07 16:49:12 1996
  47. *
  48. */
  49. #include <windows.h>
  50. #include <malloc.h>
  51. #include <snmp.h>
  52. #include <winsock.h> /* For htons() */
  53. #include "mib.h"
  54. #include "smint.h"
  55. #include "hostmsmi.h"
  56. #include "user.h" /* Developer supplied include file */
  57. #include "HMCACHE.H" /* Cache-related definitions */
  58. #include <regstr.h> /* For Registry-lookup on software */
  59. #include <winreg.h> /* For Registry-lookup on software */
  60. #include <objbase.h> /* For CoFileTimeToDosDateTime() */
  61. /*
  62. |==============================================================================
  63. | Function prototypes for this module.
  64. |
  65. */
  66. /* Gen_SingleDevices - Generate Single Device row entries in HrDevice */
  67. BOOL Gen_SingleDevices( void );
  68. /* AddSWInstalled - Add a row to HrSWInstalled Table */
  69. BOOL AddSWInstalled( HKEY sw_key, FILETIME *ft);
  70. #if defined(CACHE_DUMP)
  71. /* debug_print_hrswinstalled - Prints a Row from HrSWInstalled table */
  72. static void
  73. debug_print_hrswinstalled(
  74. CACHEROW *row /* Row in hrSWInstalled table */
  75. );
  76. #endif
  77. /*
  78. |==============================================================================
  79. | Create the list-head for the HrSWInstalled table cache.
  80. |
  81. | (This macro is defined in "HMCACHE.H").
  82. */
  83. static CACHEHEAD_INSTANCE(hrSWInstalled_cache, debug_print_hrswinstalled);
  84. /*
  85. |==============================================================================
  86. | hrSWInstalledTable Attribute Defines
  87. |
  88. | Each attribute defined for this table is associated with one of the
  89. | #defines below. These symbols are used as C indices into the array of
  90. | attributes within a cached-row.
  91. |
  92. */
  93. #define HRIN_INDEX 0 // hrSWInstalledIndex
  94. #define HRIN_NAME 1 // hrSWInstalledName
  95. #define HRIN_DATE 2 // hrSWInstalledDate
  96. //-->Add more here, change count below!
  97. #define HRIN_ATTRIB_COUNT 3
  98. /*
  99. * GetHrSWInstalledIndex
  100. * A unique value for each piece of software installed on the host. This
  101. * value shall be in the range from 1 to the number of piece
  102. *
  103. * Gets the value for HrSWInstalledIndex.
  104. *
  105. * Arguments:
  106. *
  107. * outvalue address to return variable value
  108. * accesss Reserved for future security use
  109. * instance address of instance name as ordered native
  110. * data type(s)
  111. *
  112. * Return Codes:
  113. *
  114. * Standard PDU error codes.
  115. *
  116. * SNMP_ERRORSTATUS_NOERROR Successful get
  117. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  118. * mibtget.c v0.10
  119. *
  120. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  121. | hrSWInstalledIndex
  122. |
  123. | ACCESS SYNTAX
  124. | read-only INTEGER (1..2147483647)
  125. |
  126. | "A unique value for each piece of software installed on the host. This value
  127. | shall be in the range from 1 to the number of pieces of software installed on
  128. | the host."
  129. |
  130. |============================================================================
  131. | 1.3.6.1.2.1.25.6.3.1.1.<instance>
  132. | | | | |
  133. | | | | *-hrSwInstalledIndex
  134. | | | *-hrSWInstalledEntry
  135. | | *-hrSWInstalledTable
  136. | *-hrSWInstalled
  137. */
  138. UINT
  139. GetHrSWInstalledIndex(
  140. OUT Integer *outvalue ,
  141. IN Access_Credential *access ,
  142. IN InstanceName *instance )
  143. {
  144. ULONG index; /* As fetched from instance structure */
  145. CACHEROW *row; /* Row entry fetched from cache */
  146. /*
  147. | Grab the instance information
  148. */
  149. index = GET_INSTANCE(0);
  150. /*
  151. | Use it to find the right entry in the cache
  152. */
  153. if ((row = FindTableRow(index, &hrSWInstalled_cache)) == NULL) {
  154. return SNMP_ERRORSTATUS_GENERR;
  155. }
  156. /*
  157. | Return the "hrSWInstalledIndex" value from this entry
  158. */
  159. *outvalue = row->attrib_list[HRIN_INDEX].u.unumber_value;
  160. return SNMP_ERRORSTATUS_NOERROR ;
  161. } /* end of GetHrSWInstalledIndex() */
  162. /*
  163. * GetHrSWInstalledName
  164. * A textual description of this installed piece of software, including the
  165. * manufacturer, revision, the name by which it is commonl
  166. *
  167. * Gets the value for HrSWInstalledName.
  168. *
  169. * Arguments:
  170. *
  171. * outvalue address to return variable value
  172. * accesss Reserved for future security use
  173. * instance address of instance name as ordered native
  174. * data type(s)
  175. *
  176. * Return Codes:
  177. *
  178. * Standard PDU error codes.
  179. *
  180. * SNMP_ERRORSTATUS_NOERROR Successful get
  181. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  182. * mibtget.c v0.10
  183. *
  184. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  185. | hrSWInstalledName
  186. |
  187. | ACCESS SYNTAX
  188. | read-only InternationalDisplayString (SIZE (0..64))
  189. |
  190. | "A textual description of this installed piece of software, including the
  191. | manufacturer, revision, the name by which it is commonly known, and
  192. | optionally, its serial number."
  193. |
  194. |============================================================================
  195. | DISCUSSION:
  196. | For logo 95 programs, we use the Registry sub-key name.
  197. |
  198. | 1.3.6.1.2.1.25.6.3.1.2.<instance>
  199. | | | | |
  200. | | | | *-hrSwInstalledName
  201. | | | *-hrSWInstalledEntry
  202. | | *-hrSWInstalledTable
  203. | *-hrSWInstalled
  204. */
  205. UINT
  206. GetHrSWInstalledName(
  207. OUT InternationalDisplayString *outvalue ,
  208. IN Access_Credential *access ,
  209. IN InstanceName *instance )
  210. {
  211. ULONG index; /* As fetched from instance structure */
  212. CACHEROW *row; /* Row entry fetched from cache */
  213. /*
  214. | Grab the instance information
  215. */
  216. index = GET_INSTANCE(0);
  217. /*
  218. | Use it to find the right entry in the cache
  219. */
  220. if ((row = FindTableRow(index, &hrSWInstalled_cache)) == NULL) {
  221. return SNMP_ERRORSTATUS_GENERR;
  222. }
  223. /*
  224. | Return the "hrSWInstalledName" value from this entry
  225. */
  226. outvalue->string = row->attrib_list[HRIN_NAME].u.string_value;
  227. /* "Truncate" here to meet RFC as needed*/
  228. if ((outvalue->length = strlen(outvalue->string)) > 64) {
  229. outvalue->length = 64;
  230. }
  231. return SNMP_ERRORSTATUS_NOERROR ;
  232. } /* end of GetHrSWInstalledName() */
  233. /*
  234. * GetHrSWInstalledID
  235. * The product ID of this installed piece of software.
  236. *
  237. * Gets the value for HrSWInstalledID.
  238. *
  239. * Arguments:
  240. *
  241. * outvalue address to return variable value
  242. * accesss Reserved for future security use
  243. * instance address of instance name as ordered native
  244. * data type(s)
  245. *
  246. * Return Codes:
  247. *
  248. * Standard PDU error codes.
  249. *
  250. * SNMP_ERRORSTATUS_NOERROR Successful get
  251. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  252. * mibtget.c v0.10
  253. *
  254. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  255. | hrSWInstalledID
  256. |
  257. | ACCESS SYNTAX
  258. | read-only ProductID
  259. |
  260. | "The product ID of this installed piece of software."
  261. |
  262. |============================================================================
  263. | DISCUSSION:
  264. | For logo 95 programs we don't know the ProductID as an OID, so we
  265. | return the ProductID for "unknown": { 0.0 }
  266. |
  267. | 1.3.6.1.2.1.25.6.3.1.3.<instance>
  268. | | | | |
  269. | | | | *-hrSwInstalledID
  270. | | | *-hrSWInstalledEntry
  271. | | *-hrSWInstalledTable
  272. | *-hrSWInstalled
  273. */
  274. UINT
  275. GetHrSWInstalledID(
  276. OUT ProductID *outvalue ,
  277. IN Access_Credential *access ,
  278. IN InstanceName *instance )
  279. {
  280. /*
  281. | The deal on this attribute is that we'll never have a valid OID value
  282. | for this attribute. Consequently, we always return the standard
  283. | "unknown" OID value ("0.0") regardless of the instance value (which
  284. | by now in the calling sequence of things has been validated anyway).
  285. */
  286. if ( (outvalue->ids = SNMP_malloc(2 * sizeof( UINT ))) == NULL) {
  287. return SNMP_ERRORSTATUS_GENERR;
  288. }
  289. outvalue->idLength = 2;
  290. /*
  291. | Load in the OID value for "unknown" for ProductID: "0.0"
  292. */
  293. outvalue->ids[0] = 0;
  294. outvalue->ids[1] = 0;
  295. return SNMP_ERRORSTATUS_NOERROR ;
  296. } /* end of GetHrSWInstalledID() */
  297. /*
  298. * GetHrSWInstalledType
  299. * The type of this software.
  300. *
  301. * Gets the value for HrSWInstalledType.
  302. *
  303. * Arguments:
  304. *
  305. * outvalue address to return variable value
  306. * accesss Reserved for future security use
  307. * instance address of instance name as ordered native
  308. * data type(s)
  309. *
  310. * Return Codes:
  311. *
  312. * Standard PDU error codes.
  313. *
  314. * SNMP_ERRORSTATUS_NOERROR Successful get
  315. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  316. * mibtget.c v0.10
  317. *
  318. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  319. | hrSWInstalledType
  320. |
  321. | ACCESS SYNTAX
  322. | read-only INTEGER {unknown(1),operatingSystem(2),deviceDriver(3),
  323. | application(4)}
  324. |
  325. | "The type of this software."
  326. |============================================================================
  327. | DISCUSSION:
  328. | For logo 95 programs we presume that all uninstallable software is
  329. | an application. That is the only type we return.
  330. |
  331. | 1.3.6.1.2.1.25.6.3.1.4.<instance>
  332. | | | | |
  333. | | | | *-hrSwInstalledType
  334. | | | *-hrSWInstalledEntry
  335. | | *-hrSWInstalledTable
  336. | *-hrSWInstalled
  337. */
  338. UINT
  339. GetHrSWInstalledType(
  340. OUT INTSWType *outvalue ,
  341. IN Access_Credential *access ,
  342. IN InstanceName *instance )
  343. {
  344. *outvalue = 4; // 4 = "application"
  345. return SNMP_ERRORSTATUS_NOERROR ;
  346. } /* end of GetHrSWInstalledType() */
  347. /*
  348. * GetHrSWInstalledDate
  349. * The last-modification date of this application as it would appear in a
  350. * directory listing.
  351. *
  352. * Gets the value for HrSWInstalledDate.
  353. *
  354. * Arguments:
  355. *
  356. * outvalue address to return variable value
  357. * accesss Reserved for future security use
  358. * instance address of instance name as ordered native
  359. * data type(s)
  360. *
  361. * Return Codes:
  362. *
  363. * Standard PDU error codes.
  364. *
  365. * SNMP_ERRORSTATUS_NOERROR Successful get
  366. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  367. * mibtget.c v0.10
  368. *
  369. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  370. | hrSWInstalledDate
  371. |
  372. | ACCESS SYNTAX
  373. | read-only DateAndTime
  374. |
  375. | "The last-modification date of this application as it would appear in a
  376. | directory listing."
  377. |============================================================================
  378. | DISCUSSION:
  379. | For logo 95 programs we use the date of the last write into the
  380. | Registry key associated with the application.
  381. |
  382. | 1.3.6.1.2.1.25.6.3.1.5.<instance>
  383. | | | | |
  384. | | | | *-hrSwInstalledDate
  385. | | | *-hrSWInstalledEntry
  386. | | *-hrSWInstalledTable
  387. | *-hrSWInstalled
  388. */
  389. UINT
  390. GetHrSWInstalledDate(
  391. OUT DateAndTime *outvalue ,
  392. IN Access_Credential *access ,
  393. IN InstanceName *instance )
  394. {
  395. ULONG index; /* As fetched from instance structure */
  396. CACHEROW *row; /* Row entry fetched from cache */
  397. /*
  398. | Grab the instance information
  399. */
  400. index = GET_INSTANCE(0);
  401. /*
  402. | Use it to find the right entry in the cache
  403. */
  404. if ((row = FindTableRow(index, &hrSWInstalled_cache)) == NULL) {
  405. return SNMP_ERRORSTATUS_GENERR;
  406. }
  407. /*
  408. | Return the "hrSWInstalledDate" value from this entry
  409. */
  410. outvalue->string = row->attrib_list[HRIN_DATE].u.string_value;
  411. outvalue->length = 8;
  412. return SNMP_ERRORSTATUS_NOERROR ;
  413. } /* end of GetHrSWInstalledDate() */
  414. /*
  415. * HrSWInstalledEntryFindInstance
  416. *
  417. * This routine is used to verify that the specified instance is
  418. * valid.
  419. *
  420. * Arguments:
  421. *
  422. * FullOid Address for the full oid - group, variable,
  423. * and instance information
  424. * instance Address for instance specification as an oid
  425. *
  426. * Return Codes:
  427. *
  428. * SNMP_ERRORSTATUS_NOERROR Instance found and valid
  429. * SNMP_ERRORSTATUS_NOSUCHNAME Invalid instance
  430. *
  431. */
  432. UINT
  433. HrSWInstalledEntryFindInstance( IN ObjectIdentifier *FullOid ,
  434. IN OUT ObjectIdentifier *instance )
  435. {
  436. UINT tmp_instance ;
  437. //
  438. // Developer instrumentation code to find appropriate instance goes here.
  439. // For non-tables, it is not necessary to modify this routine. However, if
  440. // there is any context that needs to be set, it can be done here.
  441. //
  442. if ( FullOid->idLength <= HRSWINSTALLEDENTRY_VAR_INDEX )
  443. // No instance was specified
  444. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  445. else if ( FullOid->idLength != HRSWINSTALLEDENTRY_VAR_INDEX + 1 )
  446. // Instance length is more than 1
  447. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  448. else
  449. // The only valid instance for a non-table are instance 0. If this
  450. // is a non-table, the following code validates the instances. If this
  451. // is a table, developer modification is necessary below.
  452. tmp_instance = FullOid->ids[ HRSWINSTALLEDENTRY_VAR_INDEX ] ;
  453. /*
  454. | For hrSWInstalledTable, the instance arc(s) is a single arc, and
  455. | it must correctly select an entry in the hrSWInstalled Table cache.
  456. | Check that here.
  457. */
  458. if ( FindTableRow(tmp_instance, &hrSWInstalled_cache) == NULL ) {
  459. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  460. }
  461. else
  462. {
  463. // the instance is valid. Create the instance portion of the OID
  464. // to be returned from this call.
  465. instance->ids[ 0 ] = tmp_instance ;
  466. instance->idLength = 1 ;
  467. }
  468. return SNMP_ERRORSTATUS_NOERROR ;
  469. } /* end of HrSWInstalledEntryFindInstance() */
  470. /*
  471. * HrSWInstalledEntryFindNextInstance
  472. *
  473. * This routine is called to get the next instance. If no instance
  474. * was passed than return the first instance (1).
  475. *
  476. * Arguments:
  477. *
  478. * FullOid Address for the full oid - group, variable,
  479. * and instance information
  480. * instance Address for instance specification as an oid
  481. *
  482. * Return Codes:
  483. *
  484. * SNMP_ERRORSTATUS_NOERROR Instance found and valid
  485. * SNMP_ERRORSTATUS_NOSUCHNAME Invalid instance
  486. *
  487. */
  488. UINT
  489. HrSWInstalledEntryFindNextInstance( IN ObjectIdentifier *FullOid ,
  490. IN OUT ObjectIdentifier *instance )
  491. {
  492. //
  493. // Developer supplied code to find the next instance of class goes here.
  494. // If this is a class with cardinality 1, no modification of this routine
  495. // is necessary unless additional context needs to be set.
  496. // If the FullOid does not specify an instance, then the only instance
  497. // of the class is returned. If this is a table, the first row of the
  498. // table is returned.
  499. //
  500. // If an instance is specified and this is a non-table class, then NOSUCHNAME
  501. // is returned so that correct MIB rollover processing occurs. If this is
  502. // a table, then the next instance is the one following the current instance.
  503. // If there are no more instances in the table, return NOSUCHNAME.
  504. //
  505. CACHEROW *row;
  506. ULONG tmp_instance;
  507. if ( FullOid->idLength <= HRSWINSTALLEDENTRY_VAR_INDEX )
  508. {
  509. /*
  510. | Too short: must return the instance arc that selects the first
  511. | entry in the table if there is one.
  512. */
  513. tmp_instance = 0;
  514. }
  515. else {
  516. /*
  517. | There is at least one instance arc. Even if it is the only arc
  518. | we use it as the "index" in a request for the "NEXT" one.
  519. */
  520. tmp_instance = FullOid->ids[ HRSWINSTALLEDENTRY_VAR_INDEX ] ;
  521. }
  522. /* Now go off and try to find the next instance in the table */
  523. if ((row = FindNextTableRow(tmp_instance, &hrSWInstalled_cache)) == NULL) {
  524. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  525. }
  526. instance->ids[ 0 ] = row->index ;
  527. instance->idLength = 1 ;
  528. return SNMP_ERRORSTATUS_NOERROR ;
  529. } /* end of HrSWInstalledEntryFindNextInstance() */
  530. /*
  531. * HrSWInstalledEntryConvertInstance
  532. *
  533. * This routine is used to convert the object id specification of an
  534. * instance into an ordered native representation. The object id format
  535. * is that object identifier that is returned from the Find Instance
  536. * or Find Next Instance routines. It is NOT the full object identifier
  537. * that contains the group and variable object ids as well. The native
  538. * representation is an argc/argv-like structure that contains the
  539. * ordered variables that define the instance. This is specified by
  540. * the MIB's INDEX clause. See RFC 1212 for information about the INDEX
  541. * clause.
  542. *
  543. *
  544. * Arguments:
  545. *
  546. * oid_spec Address of the object id instance specification
  547. * native_spec Address to return the ordered native instance
  548. * specification
  549. *
  550. * Return Codes:
  551. *
  552. * SUCCESS Conversion complete successfully
  553. * FAILURE Unable to convert object id into native format
  554. *
  555. */
  556. UINT
  557. HrSWInstalledEntryConvertInstance( IN ObjectIdentifier *oid_spec ,
  558. IN OUT InstanceName *native_spec )
  559. {
  560. static char *array; /* The address of this (char *) is passed back */
  561. /* as though it were an array of length 1 of these */
  562. /* types. */
  563. static ULONG inst; /* The address of this ULONG is passed back */
  564. /* (Obviously, no "free()" action is needed) */
  565. /* We only expect the one arc in "oid_spec" */
  566. inst = oid_spec->ids[0];
  567. array = (char *) &inst;
  568. native_spec->count = 1;
  569. native_spec->array = &array;
  570. return SUCCESS ;
  571. } /* end of HrSWInstalledEntryConvertInstance() */
  572. /*
  573. * HrSWInstalledEntryFreeInstance
  574. *
  575. * This routine is used to free an ordered native representation of an
  576. * instance name.
  577. *
  578. * Arguments:
  579. *
  580. * instance Address to return the ordered native instance
  581. * specification
  582. *
  583. * Return Codes:
  584. *
  585. *
  586. */
  587. void
  588. HrSWInstalledEntryFreeInstance( IN OUT InstanceName *instance )
  589. {
  590. /* No action needed for hrSWInstalledTable */
  591. } /* end of HrSWInstalledEntryFreeInstance() */
  592. /*
  593. | End of Generated Code
  594. */
  595. /* Gen_HrSWInstalled_Cache - Generate a cache for HrSWInstalled Table */
  596. /* Gen_HrSWInstalled_Cache - Generate a cache for HrSWInstalled Table */
  597. /* Gen_HrSWInstalled_Cache - Generate a cache for HrSWInstalled Table */
  598. BOOL
  599. Gen_HrSWInstalled_Cache(
  600. void
  601. )
  602. /*
  603. | EXPLICIT INPUTS:
  604. |
  605. | None.
  606. |
  607. | IMPLICIT INPUTS:
  608. |
  609. | The module-local head of the cache for the HrSWInstalled table,
  610. | "hrSWInstalled_cache".
  611. |
  612. | OUTPUTS:
  613. |
  614. | On Success:
  615. | Function returns TRUE indicating that the cache has been fully
  616. | populated with all "static" cache-able values.
  617. |
  618. | On any Failure:
  619. | Function returns FALSE (indicating "not enough storage" or other
  620. | internal logic error).
  621. |
  622. | THE BIG PICTURE:
  623. |
  624. | At subagent startup time, the cache for each table in the MIB is
  625. | populated with rows for each row in the table. This function is
  626. | invoked by the start-up code in "UserMibInit()" ("MIB.C") to
  627. | populate the cache for the HrSWInstalled table.
  628. |
  629. | OTHER THINGS TO KNOW:
  630. |
  631. | There is one of these function for every table that has a cache.
  632. | Each is found in the respective source file.
  633. |
  634. |=============== From WebEnable Design Spec Rev 3 04/11/97==================
  635. | DISCUSSION:
  636. |
  637. | This implementation of this entire group is rather problematical without the
  638. | creation of a standard. It certainly appears that many software manufacturers
  639. | dutifully register SOMETHING in the Registry when software is installed,
  640. | however there appears to be no rhyme nor reason to the information put into
  641. | the Registry in leaves below the manufacturers name. Consequently, for
  642. | installed application software, there is no easy, reliable way of mapping
  643. | the Registry information into entries in this table.
  644. |
  645. | It is clear that some consistent scheme seems to be currently implemented for
  646. | Microsoft software, however the details of extracting it from the Registry
  647. | (and whether or not all information needed for full population of entries in
  648. | this table is available) is not documented.
  649. |
  650. | Proper implementation of "hrSWInstalled" requires the creation and
  651. | promulgation of a standard for registering ISD software (presumably in the
  652. | Registry). Information in "hrSWInstalled" includes attributes with
  653. | values of Object Identifiers. Webenable Inc. is prepared to work with
  654. | Microsoft in establishing a standard for registering software in a fashion
  655. | that allows proper implementation of the "hrSWInstalled" table.
  656. |
  657. | Resolution:
  658. | Report only logo 95 compliant software initially.
  659. |
  660. |============================================================================
  661. |
  662. | 1.3.6.1.2.1.25.6.1.0....
  663. | | |
  664. | | *hrSWInstalledLastChange
  665. | *-hrSWInstalled
  666. |
  667. | 1.3.6.1.2.1.25.6.2.0....
  668. | | |
  669. | | *hrSWInstalledLastUpdateTime
  670. | *-hrSWInstalled
  671. |
  672. | 1.3.6.1.2.1.25.6.3.1....
  673. | | | |
  674. | | | *-hrSWInstalledEntry
  675. | | *-hrSWInstalledTable
  676. | *-hrSWInstalled
  677. |
  678. */
  679. #define SUBKEY_LEN 64 // Long enough for short key-name of software
  680. {
  681. HKEY subkey; /* Handle of subkey for uninstall software */
  682. DWORD index; /* Index counter for enumerating subkeys */
  683. LONG enum_status=ERROR_SUCCESS; /* Status from subkey enumeration */
  684. CHAR subkey_name[SUBKEY_LEN+1]; /* Subkey name returned here */
  685. DWORD subkey_len=SUBKEY_LEN; /* Subkey name buffer size */
  686. FILETIME keytime; /* Time subkey was last written to */
  687. BOOL add_status; /* Status from add-row operation */
  688. HKEY sw_key; /* Handle of software key for value enum */
  689. // ensure null terminated string
  690. subkey_name[SUBKEY_LEN] = 0;
  691. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, // hkey - currently open
  692. REGSTR_PATH_UNINSTALL, // subkey to open
  693. 0, // options
  694. KEY_READ, // Security access mask
  695. &subkey
  696. ) == ERROR_SUCCESS) {
  697. /* Enumerate the keys using the Uninstall subkey */
  698. for (index = 0; enum_status != ERROR_NO_MORE_ITEMS; index += 1) {
  699. subkey_len=SUBKEY_LEN;
  700. enum_status = RegEnumKeyEx(subkey, // Enumerating this key
  701. index, // next subkey index
  702. subkey_name, // Buffer to rcv subkey name
  703. &subkey_len, // Buffer size
  704. NULL, // Reserved
  705. NULL, // Class name buffer
  706. NULL, // Class buffer size
  707. &keytime // Time of last write to subkey
  708. );
  709. /* Skip if we didn't open OK */
  710. if (enum_status != ERROR_SUCCESS) {
  711. continue;
  712. }
  713. /* Now try for the software itself */
  714. if (RegOpenKeyEx(subkey, // hkey - currently open
  715. subkey_name, // subkey to open
  716. 0, // options
  717. KEY_READ, // Security access mask
  718. &sw_key
  719. ) == ERROR_SUCCESS) {
  720. /* Now Enumerate the Values of this key */
  721. add_status =
  722. AddSWInstalled(sw_key, // Key to obtain DisplayName
  723. &keytime // Date and Time installed
  724. );
  725. RegCloseKey(sw_key);
  726. /* If something blew down below, bail out */
  727. if (add_status == FALSE) {
  728. RegCloseKey(subkey);
  729. return ( FALSE );
  730. }
  731. }
  732. }
  733. RegCloseKey(subkey);
  734. }
  735. #if defined(CACHE_DUMP)
  736. PrintCache(&hrSWInstalled_cache);
  737. #endif
  738. /* hrSWInstalled cache initialized */
  739. return ( TRUE );
  740. }
  741. /* UTCDosDateTimeToLocalSysTime - converts UTC msdos date and time to local SYSTEMTIME structure */
  742. /* UTCDosDateTimeToLocalSysTime - converts UTC msdos date and time to local SYSTEMTIME structure */
  743. /* UTCDosDateTimeToLocalSysTime - converts UTC msdos date and time to local SYSTEMTIME structure */
  744. void UTCDosDateTimeToLocalSysTime(WORD msdos_date, WORD msdos_time, LPSYSTEMTIME pSysTime)
  745. {
  746. SYSTEMTIME utcSysTime;
  747. utcSysTime.wYear = (msdos_date >> 9) + 1980;
  748. utcSysTime.wMonth = ((msdos_date >> 5) & 0x0F);
  749. utcSysTime.wDay = (msdos_date & 0x1F);
  750. utcSysTime.wDayOfWeek = 0;
  751. utcSysTime.wHour = (msdos_time >> 11);
  752. utcSysTime.wMinute = ((msdos_time >> 5) & 0x3F);
  753. utcSysTime.wSecond = ((msdos_time & 0x1F) * 2);
  754. utcSysTime.wMilliseconds = 0;
  755. if (!SystemTimeToTzSpecificLocalTime(
  756. NULL, // [in] use active time zone
  757. &utcSysTime, // [in] utc system time
  758. pSysTime)) // [out] local time
  759. {
  760. // if the utc time could not be converted to local time,
  761. // just return the utc time
  762. memcpy(&utcSysTime, pSysTime, sizeof(SYSTEMTIME));
  763. }
  764. }
  765. /* AddSWInstalled - Add a row to HrSWInstalled Table */
  766. /* AddSWInstalled - Add a row to HrSWInstalled Table */
  767. /* AddSWInstalled - Add a row to HrSWInstalled Table */
  768. BOOL
  769. AddSWInstalled(
  770. HKEY sw_key,
  771. FILETIME *ft
  772. )
  773. /*
  774. | EXPLICIT INPUTS:
  775. |
  776. | "sw_key" - an opened key for a piece of software whose Values we
  777. | must enumerate looking for "DisplayName"
  778. |
  779. | "ft" - This is the time that the key was last written, and we
  780. | take it as the time the software was installed.
  781. |
  782. | IMPLICIT INPUTS:
  783. |
  784. | The module-local head of the cache for the HrSWInstalled table,
  785. | "hrSWInstalled_cache".
  786. |
  787. | OUTPUTS:
  788. |
  789. | On Success:
  790. | Function returns TRUE indicating that the cache has been fully
  791. | populated with all "static" cache-able values.
  792. |
  793. | On any Failure:
  794. | Function returns FALSE (indicating "not enough storage" or other
  795. | internal logic error).
  796. |
  797. | THE BIG PICTURE:
  798. |
  799. | The Gen_SWInstalled_cache() function has been invoked to populate
  800. | the cache, and this function is called when it has found another
  801. | piece of software for which a row-entry needs to be placed into
  802. | the cache.
  803. |
  804. | OTHER THINGS TO KNOW:
  805. |
  806. */
  807. #define VALUE_LEN 32 // Long enough for "UninstallString"
  808. #define VALUE_DATA_LEN 128 // Long enough for a long "casual" name
  809. {
  810. DWORD index; /* Index counter for enumerating subkeys */
  811. LONG enum_status=ERROR_SUCCESS; /* Status from subkey enumeration */
  812. CHAR value_name[VALUE_LEN+1]; /* Value name returned here */
  813. DWORD value_len; /* Value name buffer size */
  814. DWORD value_type; /* Type code for value string */
  815. CHAR value_data[VALUE_DATA_LEN+1]; /* Value's value returned here */
  816. DWORD value_data_len; /* Value's value buffer length resides here*/
  817. static /* NOTE: "static" is a 'must' */
  818. ULONG table_index=0; /* HrDeviceTable index counter */
  819. CACHEROW *row; /* --> Cache structure for row-being built */
  820. WORD msdos_date; /* Conversion area for software date/time */
  821. WORD msdos_time; /* Conversion area for software date/time */
  822. char *octet_string; /* Alias for building DateAndTime */
  823. UINT i; /* Loop index */
  824. // make sure null terminated buffer
  825. value_name[VALUE_LEN] = 0;
  826. value_data[VALUE_DATA_LEN] = 0;
  827. /*
  828. | Now go a-lookin' for "DisplayName", the value whose data will give us
  829. | the name of the installed software.
  830. |
  831. | For each Value associated with this software's key . . .
  832. */
  833. for (index = 0; enum_status != ERROR_NO_MORE_ITEMS; index += 1) {
  834. /* Make sure these cells continues to reflect the buffer size */
  835. value_len = VALUE_LEN;
  836. value_data_len = VALUE_DATA_LEN;
  837. enum_status = RegEnumValue(sw_key, // Key whose values we're enuming
  838. index, // index of next value
  839. value_name, // Value name buffer
  840. &value_len, // length of Value name buffer
  841. NULL, // reserved
  842. &value_type, // type of value data
  843. value_data, // Buffer for value's data
  844. &value_data_len// Length of data buffer
  845. );
  846. /* Only if we managed to fetch this key do we try to recognize it */
  847. if (enum_status == ERROR_SUCCESS) {
  848. /* If the value we just read is for "DisplayName" */
  849. if ( strcmp(value_name, REGSTR_VAL_UNINSTALLER_DISPLAYNAME) == 0) {
  850. /*
  851. | Get a row-entry created.
  852. */
  853. if ((row = CreateTableRow( HRIN_ATTRIB_COUNT ) ) == NULL) {
  854. return ( FALSE ); // Out of memory
  855. }
  856. /*
  857. | Set up the cached hrSWInstalled attributes in the new row
  858. */
  859. /* =========== hrSWInstalledIndex ==========*/
  860. row->attrib_list[HRIN_INDEX].attrib_type = CA_NUMBER;
  861. row->attrib_list[HRIN_INDEX].u.unumber_value = (table_index += 1) ;
  862. /* =========== hrSWInstalledName ==========*/
  863. row->attrib_list[HRIN_NAME].attrib_type = CA_STRING;
  864. if ( (row->attrib_list[HRIN_NAME].u.string_value
  865. = ( LPSTR ) malloc(value_data_len+1)) == NULL) {
  866. return ( FALSE ); /* out of memory */
  867. }
  868. strcpy(row->attrib_list[HRIN_NAME].u.string_value, value_data);
  869. /* =========== hrSWInstalledDate ==========
  870. |
  871. | Here's the deal on this one. We've got a 64-bit FILETIME
  872. | representation of when the Registry entry was made for the
  873. | software. We're taking this as the install time of the software.
  874. |
  875. | So we convert to MS-DOS time, then to DateAndTime (in the
  876. | 8-octet form) below:
  877. |========================== From RFC1514 ========================
  878. |
  879. | DateAndTime ::= OCTET STRING (SIZE (8 | 11))
  880. | -- A date-time specification for the local time of day.
  881. | -- This data type is intended to provide a consistent
  882. | -- method of reporting date information.
  883. | --
  884. | -- field octets contents range
  885. | -- _____ ______ ________ _____
  886. | -- 1 1-2 year 0..65536
  887. | -- (in network byte order)
  888. | -- 2 3 month 1..12
  889. | -- 3 4 day 1..31
  890. | -- 4 5 hour 0..23
  891. | -- 5 6 minutes 0..59
  892. | -- 6 7 seconds 0..60
  893. | -- (use 60 for leap-second)
  894. | -- 7 8 deci-seconds 0..9
  895. | -- 8 9 direction from UTC "+" / "-"
  896. | -- (in ascii notation)
  897. | -- 9 10 hours from UTC 0..11
  898. | -- 10 11 minutes from UTC 0..59
  899. | --
  900. | -- Note that if only local time is known, then
  901. | -- timezone information (fields 8-10) is not present.
  902. |
  903. | MS-DOS records file dates and times as packed 16-bit values.
  904. | An MS-DOS date has the following format:
  905. | Bits Contents
  906. | ---- --------
  907. | 0-4 Days of the month (1-31).
  908. | 5-8 Months (1 = January, 2 = February, and so forth).
  909. | 9-15 Year offset from 1980 (add 1980 to get actual year).
  910. |
  911. | An MS-DOS time has the following format:
  912. | Bits Contents
  913. | ---- --------
  914. | 0-4 Seconds divided by 2.
  915. | 5-10 Minutes (0-59).
  916. | 11-15 Hours (0-23 on a 24-hour clock).
  917. |
  918. */
  919. row->attrib_list[HRIN_DATE].attrib_type = CA_STRING;
  920. if ( (row->attrib_list[HRIN_DATE].u.string_value
  921. = octet_string = ( LPSTR ) malloc(8)) == NULL) {
  922. return ( FALSE ); /* out of memory */
  923. }
  924. for (i=0; i < 8; i += 1) octet_string[i] = '\0';
  925. if (CoFileTimeToDosDateTime(ft, &msdos_date, &msdos_time) == TRUE) {
  926. SYSTEMTIME localInstTime;
  927. USHORT year;
  928. UTCDosDateTimeToLocalSysTime(msdos_date, msdos_time, &localInstTime);
  929. year = htons(localInstTime.wYear);
  930. octet_string[0] = (year & 0xFF);
  931. octet_string[1] = (year >> 8);
  932. octet_string[2] = (char)localInstTime.wMonth;
  933. octet_string[3] = (char)localInstTime.wDay;
  934. octet_string[4] = (char)localInstTime.wHour;
  935. octet_string[5] = (char)localInstTime.wMinute;
  936. octet_string[6] = (char)localInstTime.wSecond;
  937. octet_string[7] = (char)localInstTime.wMilliseconds / 10;
  938. }
  939. /*
  940. | The other standard hrSWInstalled attributes are currently
  941. | "hardwired" in the Get functions.
  942. */
  943. /*
  944. | Now insert the filled-in CACHEROW structure into the
  945. | cache-list for the hrDeviceTable.
  946. */
  947. if (AddTableRow(row->attrib_list[HRIN_INDEX].u.unumber_value, /* Index */
  948. row, /* Row */
  949. &hrSWInstalled_cache /* Cache */
  950. ) == FALSE) {
  951. return ( FALSE ); /* Internal Logic Error! */
  952. }
  953. /*
  954. | Break from the Enumeration loop on the values, we've found
  955. | the one we want.
  956. */
  957. break;
  958. }
  959. }
  960. } /* for */
  961. /* Add succeeded */
  962. return ( TRUE );
  963. }
  964. #if defined(CACHE_DUMP)
  965. /* debug_print_hrswinstalled - Prints a Row from HrSWInstalled table */
  966. /* debug_print_hrswinstalled - Prints a Row from HrSWInstalled table */
  967. /* debug_print_hrswinstalled - Prints a Row from HrSWInstalled table */
  968. static void
  969. debug_print_hrswinstalled(
  970. CACHEROW *row /* Row in hrSWInstalled table */
  971. )
  972. /*
  973. | EXPLICIT INPUTS:
  974. |
  975. | "row" - points to the row to be dumped, if NULL, the function
  976. | merely prints a suitable title.
  977. |
  978. | IMPLICIT INPUTS:
  979. |
  980. | - Symbols used to reference the attributes in the row entry.
  981. | - File handle defined by OFILE, presumed to be open.
  982. |
  983. | OUTPUTS:
  984. |
  985. | On Success:
  986. | Function prints a dump of the row in ASCII for debugging purposes
  987. | on file handle OFILE.
  988. |
  989. | THE BIG PICTURE:
  990. |
  991. | Debugging only.
  992. |
  993. | OTHER THINGS TO KNOW:
  994. */
  995. {
  996. UINT i;
  997. if (row == NULL) {
  998. fprintf(OFILE, "=========================\n");
  999. fprintf(OFILE, "hrSWInstalled Table Cache\n");
  1000. fprintf(OFILE, "=========================\n");
  1001. return;
  1002. }
  1003. fprintf(OFILE, "hrSWInstalledIndex . . . . %d\n",
  1004. row->attrib_list[HRIN_INDEX].u.unumber_value);
  1005. fprintf(OFILE, "hrSWInstalledName . . . . %s\n",
  1006. row->attrib_list[HRIN_NAME].u.string_value);
  1007. fprintf(OFILE, "hrSWInstalledDate . . . . ");
  1008. for (i = 0; i < 8; i += 1) {
  1009. fprintf(OFILE, "%2.2x ",row->attrib_list[HRIN_DATE].u.string_value[i]);
  1010. }
  1011. fprintf(OFILE, "\n");
  1012. }
  1013. #endif