2
* winExtDLL Net-SNMP extension
7
* Purpose: To load Windows SNMP Service extension DLLs provided with Windows
8
* (such as hostmib.dll). This allows Net-SNMP to be a replacement
9
* for the Windows SNMP service.
11
* Notes: This extension requires the PSDK including the Snmp.h header file.
12
* Including Snmp.h will conflict with existing Net-SNMP defines for
13
* ASN_OCTETSTRING etc. To resolve this, create a copy of Snmp.h in
14
* the PSDK include/ folder called Snmp-winExtDLL.h and change all
15
* occurances of ASN_ to MS_ASN_
17
* This extension requires that the Windows SNMP Service is installed
18
* but set to disabled. This is required so that the extension DLLs
19
* are available for loading, and also because this extension and the
20
* existing Windows extensions use the Windows SNMP API from snmpapi.dll.
22
* This extension is NOT for dynamically loading Net-SNMP extensions.
27
#include <Snmp-winExtDLL.h> // Modified Windows SDK snmp.h. See Notes above
32
* include important headers
2
* @brief winExtDLL Net-SNMP agent extension module.
4
* Copyright (c) 2006-2009 Alex Burger.
5
* Copyright (c) 2009-2010 Bart Van Assche <bart.vanassche@gmail.com>.
7
* This Net-SNMP agent extension module loads Windows SNMP Extension Agent
8
* DLLs in the Net-SNMP agent. Not only extension DLLs provided with Windows
9
* (e.g. hostmib.dll) but also third-party extension DLLs are supported. This
10
* allows Net-SNMP to be a replacement for the Windows SNMP service, and makes
11
* it possible to use the SNMPv3 protocol.
13
* @see See also <a href="http://msdn.microsoft.com/en-us/library/aa378988(VS.85).aspx">SNMP Functions</a>
14
* for more information about Microsoft's SNMP Extension Agent API.
16
* @note In order to use this agent extension module, the Windows SNMP service
17
* must be installed first and must be disabled. Installing the Windows SNMP
18
* service is the only way to install the Windows Extension DLLs and to make
19
* sure that information about these DLLs is present in the registry.
21
* @note All Windows extension DLLs are loaded during startup of the Net-SNMP
22
* service. The Net-SNMP service must be restarted to load new modules. This
23
* extension is NOT for dynamically loading Net-SNMP extensions.
28
* * Multi-varbind set request PDUs are now handled correctly.
29
* * If loading an extension DLL fails, the reason why this failed is now
31
* * Fixed a memory leak that occurred when SnmpExtensionQuery() or
32
* SnmpExtensionQueryEx() failed while processing an SNMP PDU. Note:
33
* occurrence of an SNMP error does not make these functions fail, and
34
* it is not yet known whether or not it was possible to trigger this
36
* - 2010/03/17: Fixed bug 2971257. Multi-varbind getNext requests with OIDs
37
* in reverse lexicographical order are again processed correctly.
38
* - 2010/01/22: Compiles now with MinGW too.
40
* * The value of sysUpTime.0 reported by inetmib1.dll is now correct.
41
* * A linkUp or linkDown trap is now sent after the status of a network
42
* interface has changed.
44
* * Removed several artificial limits. Result: more than 100 SNMP extension
45
* DLLs can now be loaded simultaneously and more than 100 OID ranges can
46
* now be registered. Loading e.g. the Dell OpenManage SNMP extension DLL
47
* does no longer crash Net-SNMP.
48
* * Number of OID ranges registered during startup is now logged.
49
* * It is no longer attempted to free the Broadcom SNMP extension DLLs
50
* bcmif.dll and baspmgnt.dll since doing so triggers a deadlock.
51
* * Added support for reregistration of an OID prefix. As an example, both
52
* both Microsoft's inetmib1.dll and the Eicon Diva divasnmpx.dll register
53
* the OID prefix iso.org.dod.internet.mgmt.mib-2.interfaces
54
* (.1.3.6.1.2.1.2). WinExtDLL will process OIDs with this prefix by using
55
* the handler that was registered last for the OID prefix. A message will
56
* be logged indicating that a handler has been replaced.
58
* * Fixed several bugs in var_winExtDLL(): looking up extension DLL info
59
* based on the OID in a varbind is wrong. It does happen during GetNext
60
* processing that Net-SNMP passes intentionally varbinds to a handler
61
* with OIDs that are outside the range registered by the handler. Fixed
62
* this by filling in a pointer to the extension DLL info in
63
* netsnmp_mib_handler::myvoid and by using that information in the
64
* var_winExtDLL() handler function.
65
* * SetRequest PDUs are now passed once to an extension DLL instead of
67
* * The error status and error index of a multi-varbind set request is now
68
* filled in correctly.
69
* * Added support for the SNMP extension DLL three-phase SNMP set.
70
* * Made traps SNMPv2 compliant by adding the sysUpTime.0 varbind.
71
* * The varbind list generated by extension DLLs for e.g. linkUp and
72
* linkDown traps is now passed to Net-SNMP. Previously this varbind list
73
* was discarded for generic traps.
74
* * Fixed memory leaks triggered by Get and GetNext PDU processing.
75
* * Added missing RegCloseKey() calls.
76
* * Added shutdown function shutdown_winExtDLL().
77
* * Replaced #include <cstdio> by #include <stdio.h> such that this source
78
* file compiles with Visual Studio 2005.
79
* * Removed many unused local variables.
80
* * Fixed several other compiler warnings.
81
* - 2006/09/09: creation of this file.
34
84
#include <net-snmp/net-snmp-config.h>
85
#include <net-snmp/agent/mib_module_config.h>
87
#ifdef USING_WINEXTDLL_MODULE
89
#include <net-snmp/types.h>
36
93
#include <stdlib.h>
39
94
#include <string.h>
45
* needed by util_funcs.h
47
#if TIME_WITH_SYS_TIME
49
# include <sys/timeb.h>
51
# include <sys/time.h>
56
# include <sys/time.h>
66
#include <netinet/in.h>
97
#include "../../win32/Snmp-winExtDLL.h"
98
#include "../../win32/MgmtApi-winExtDLL.h"
69
100
#include <net-snmp/net-snmp-includes.h>
70
101
#include <net-snmp/agent/net-snmp-agent-includes.h>
72
102
#include "util_funcs.h"
74
103
#include "winExtDLL.h"
76
#define SZBUF_MAX 1024
77
#define SZBUF_DLLNAME_MAX 254
78
#define MAX_WINEXT_DLLS 100
79
#define MAX_KEY_LENGTH 255
80
106
#define MAX_VALUE_NAME 16383
81
#define MAX_WINEXT_TRAP_EVENTS 100
83
#define DEBUGMSGWINOID(x) do {if (_DBG_IF_) {__DBGMSGWINOID(x);} }while(0)
84
#define __DBGMSGWINOID(x) debugmsg_win_oid x
85
void debugmsg_win_oid(const char *token, const AsnObjectIdentifier * theoid);
87
/* Structure to hold name, pointers to functions and MIB tree supported by
88
* each Windows SNMP Extension DLL */
90
char dll_name[SZBUF_DLLNAME_MAX];
91
DWORD (WINAPI *xSnmpExtensionInit)(DWORD, HANDLE*, AsnObjectIdentifier*);
92
DWORD (WINAPI *xSnmpExtensionInitEx)(AsnObjectIdentifier*);
93
DWORD (WINAPI *xSnmpExtensionQuery)(BYTE, SnmpVarBindList* ,AsnInteger32* ,AsnInteger32*);
94
DWORD (WINAPI *xSnmpExtensionQueryEx)(DWORD, DWORD, SnmpVarBindList*, AsnOctetString*, AsnInteger32*, AsnInteger32*);
95
BOOL (WINAPI *xSnmpExtensionTrap)( AsnObjectIdentifier *, AsnInteger *, AsnInteger *, AsnTimeticks *, SnmpVarBindList * );
96
HANDLE *subagentTrapEvent;
97
netsnmp_handler_registration *my_handler;
98
oid name[MAX_OID_LEN]; // pSupportedView in Net-SNMP format
100
AsnObjectIdentifier pSupportedView;
101
} winExtensionAgents;
103
winExtensionAgents winExtensionAgent[MAX_WINEXT_DLLS];
104
winExtensionAgents winExtensionAgent_temp; /* For sorting */
105
int winExtensionAgent_index = 0;
107
char *extDLLs[MAX_WINEXT_DLLS];
108
int extDLLs_index = 0;
110
HANDLE *subagentTrapEvents[MAX_WINEXT_TRAP_EVENTS];
111
int subagentTrapEvents_index = 0;
113
void winExtDLL_free_config_winExtDLL(void);
115
void read_ExtensionAgents_list();
116
void read_ExtensionAgents_list2(const TCHAR *);
118
void subagentTrapCheck();
121
AsnObjectIdentifier *,
127
void init_winExtDLL(void)
130
DWORD dwUptimeReference = 0;
131
HANDLE subagentTrapEvent;
132
AsnObjectIdentifier pSupportedView;
137
char dll_name[SZBUF_DLLNAME_MAX];
138
DWORD (WINAPI *xSnmpExtensionInit)(DWORD, HANDLE*, AsnObjectIdentifier*);
139
DWORD (WINAPI *xSnmpExtensionInitEx)(AsnObjectIdentifier*);
140
DWORD (WINAPI *xSnmpExtensionQuery)(BYTE, SnmpVarBindList* ,AsnInteger32* ,AsnInteger32*);
141
DWORD (WINAPI *xSnmpExtensionQueryEx)(DWORD, DWORD, SnmpVarBindList*, AsnOctetString*, AsnInteger32*, AsnInteger32*);
142
BOOL (WINAPI *xSnmpExtensionTrap)( AsnObjectIdentifier *, AsnInteger *, AsnInteger *, AsnTimeticks *, SnmpVarBindList * );
145
oid name[MAX_OID_LEN];
149
int winExtensionAgent_num = 0;
153
netsnmp_handler_registration *my_handler;
157
DEBUGMSGTL(("winExtDLL", "init_winExtDLL called\n"));
159
read_ExtensionAgents_list();
161
DEBUGMSGTL(("winExtDLL", "winExtDLL enabled.\n"));
163
DEBUGMSGTL(("winExtDLL", "Size of winExtensionAgent: %d\n",sizeof(winExtensionAgent) / sizeof(winExtensionAgents)));
165
for(i=0; i <= sizeof(winExtensionAgent) / sizeof(winExtensionAgents); i++) {
166
winExtensionAgent[0].xSnmpExtensionInit = NULL;
167
winExtensionAgent[0].xSnmpExtensionInitEx = NULL;
170
/* Load all the DLLs */
171
for (DLLnum = 0; DLLnum <= extDLLs_index; DLLnum++) {
173
if (! (extDLLs[DLLnum]))
176
DEBUGMSGTL(("winExtDLL", "-----------------------------------------\n"));
177
DEBUGMSGTL(("winExtDLL", "DLL to load: %s, DLL number: %d, winExtensionAgent_num: %d\n", extDLLs[DLLnum], DLLnum,
178
winExtensionAgent_num));
179
DEBUGMSGTL(("winExtDLL", "Size of DLL to load: %d\n", strlen(extDLLs[DLLnum])));
181
hInst = LoadLibrary(extDLLs[DLLnum]);
185
DEBUGMSGTL(("winExtDLL","Could not load Windows extension DLL %s.\n", extDLLs[DLLnum]));
187
"Could not load Windows extension DLL: %s.\n", extDLLs[DLLnum]);
191
DEBUGMSGTL(("winExtDLL","DLL loaded.\n"));
194
// Create local copy of DLL name and functions
195
strncpy(dll_name, extDLLs[DLLnum], SZBUF_DLLNAME_MAX-1);
196
xSnmpExtensionInit = (DWORD (WINAPI *)(DWORD, HANDLE*, AsnObjectIdentifier*))
197
GetProcAddress ((HMODULE) hInst, "SnmpExtensionInit");
198
xSnmpExtensionInitEx = (DWORD (WINAPI *)(AsnObjectIdentifier*))
199
GetProcAddress ((HMODULE) hInst, "SnmpExtensionInitEx");
200
xSnmpExtensionQuery = (DWORD (WINAPI *)(BYTE, SnmpVarBindList* ,AsnInteger32* ,AsnInteger32*))
201
GetProcAddress ((HMODULE) hInst, "SnmpExtensionQuery");
202
xSnmpExtensionQueryEx = (DWORD (WINAPI *)(DWORD, DWORD, SnmpVarBindList*, AsnOctetString*, AsnInteger32*, AsnInteger32*))
203
GetProcAddress ((HMODULE) hInst, "SnmpExtensionQueryEx");
204
xSnmpExtensionTrap = (BOOL (WINAPI *)(AsnObjectIdentifier *, AsnInteger *, AsnInteger *, AsnTimeticks *, SnmpVarBindList * ))
205
GetProcAddress ((HMODULE) hInst, "SnmpExtensionTrap");
207
if (xSnmpExtensionQuery)
208
DEBUGMSGTL(("winExtDLL", "xSnmpExtensionQuery found\n"));
209
if (xSnmpExtensionQueryEx)
210
DEBUGMSGTL(("winExtDLL", "xSnmpExtensionQueryEx found\n"));
211
if (xSnmpExtensionQuery)
212
DEBUGMSGTL(("winExtDLL", "xSnmpExtensionTrap found\n"));
214
// Store DLL name and functions in winExtensionAgent array
215
strncpy(winExtensionAgent[winExtensionAgent_num].dll_name, dll_name, SZBUF_DLLNAME_MAX-1);
216
winExtensionAgent[winExtensionAgent_num].xSnmpExtensionInit = xSnmpExtensionInit;
217
winExtensionAgent[winExtensionAgent_num].xSnmpExtensionInitEx = xSnmpExtensionInitEx;
218
winExtensionAgent[winExtensionAgent_num].xSnmpExtensionQuery = xSnmpExtensionQuery;
219
winExtensionAgent[winExtensionAgent_num].xSnmpExtensionQueryEx = xSnmpExtensionQueryEx;
220
winExtensionAgent[winExtensionAgent_num].xSnmpExtensionTrap = xSnmpExtensionTrap;
222
// Init and get first supported view from Windows SNMP extension DLL
223
result = xSnmpExtensionInit(dwUptimeReference, &subagentTrapEvent, &pSupportedView);
225
DEBUGMSGTL(("winExtDLL", "Supported view: "));
226
DEBUGMSGWINOID(("winExtDLL", &pSupportedView));
227
DEBUGMSG(("winExtDLL", "\n"));
229
// Store the subagent's trap handler, even if it's NULL
230
winExtensionAgent[winExtensionAgent_num].subagentTrapEvent = subagentTrapEvent;
232
// Store the subagent's trap handler in a global array for use by waitformultipleobjects()
233
if (subagentTrapEvent) {
234
DEBUGMSGTL(("winExtDLL", "Trap handler defined. Storing...\n"));
235
subagentTrapEvents[subagentTrapEvents_index] = subagentTrapEvent;
236
subagentTrapEvents_index++;
239
// Convert OID from Windows 'supported view' to Net-SNMP
240
for (i = 0; i < (pSupportedView.idLength > MAX_OID_LEN?MAX_OID_LEN:pSupportedView.idLength); i++) {
241
name[i] = (oid)pSupportedView.ids[i];
245
// Store supported view in Net-SNMP format
246
memcpy(winExtensionAgent[winExtensionAgent_num].name, name, sizeof(name));
247
winExtensionAgent[winExtensionAgent_num].name_length = length;
249
DEBUGMSGTL(("winExtDLL", "Windows OID converted to Net-SNMP: "));
250
DEBUGMSGOID(("winExtDLL", name, length));
251
DEBUGMSG(("winExtDLL", "\n"));
253
// Store supported view in Windows format
254
SnmpUtilOidCpy(&winExtensionAgent[winExtensionAgent_num].pSupportedView,&pSupportedView);
256
// Create handler registration
257
winExtensionAgent[winExtensionAgent_num].my_handler = netsnmp_create_handler_registration("winExtDLL",
263
if (!winExtensionAgent[winExtensionAgent_num].my_handler) {
265
"malloc failed registering handler for winExtDLL");
266
DEBUGMSGTL(("winExtDLL", "malloc failed registering handler for winExtDLL"));
270
DEBUGMSGTL(("winExtDLL", "handler registered\n"));
273
// Register handler with Net-SNMP
274
netsnmp_register_handler(winExtensionAgent[winExtensionAgent_num].my_handler);
276
// Check for additional supported views and register them with the same handler
277
if (winExtensionAgent[winExtensionAgent_num].xSnmpExtensionInitEx) {
278
DEBUGMSGTL(("winExtDLL", "xSnmpExtensionInitEx found\n"));
280
winExtensionAgent_num++;
282
while (1) { // Loop looking for more supported views
283
// Store DLL name and functions in winExtensionAgent array
284
strncpy(winExtensionAgent[winExtensionAgent_num].dll_name, dll_name, SZBUF_DLLNAME_MAX-1);
285
winExtensionAgent[winExtensionAgent_num].xSnmpExtensionInit = xSnmpExtensionInit;
286
winExtensionAgent[winExtensionAgent_num].xSnmpExtensionInitEx = xSnmpExtensionInitEx;
287
winExtensionAgent[winExtensionAgent_num].xSnmpExtensionQuery = xSnmpExtensionQuery;
288
winExtensionAgent[winExtensionAgent_num].xSnmpExtensionQueryEx = xSnmpExtensionQueryEx;
289
winExtensionAgent[winExtensionAgent_num].xSnmpExtensionTrap = xSnmpExtensionTrap;
290
winExtensionAgent[winExtensionAgent_num].subagentTrapEvent = NULL;
291
// Get extra supported view
292
result = xSnmpExtensionInitEx(&pSupportedView);
295
winExtensionAgent_num--;
299
DEBUGMSGTL(("winExtDLL", "result of xSnmpExtensionInitEx: %d\n",result));
301
DEBUGMSGTL(("winExtDLL", "Supported view: "));
302
DEBUGMSGWINOID(("winExtDLL", &pSupportedView));
303
DEBUGMSG(("winExtDLL", "\n"));
305
// Convert OID from Windows 'supported view' to Net-SNMP
306
for (i = 0; i < (pSupportedView.idLength > MAX_OID_LEN?MAX_OID_LEN:pSupportedView.idLength); i++) {
307
name[i] = (oid)pSupportedView.ids[i];
311
// Store supported view in Net-SNMP format
312
memcpy(winExtensionAgent[winExtensionAgent_num].name, name, sizeof(name));
313
winExtensionAgent[winExtensionAgent_num].name_length = length;
315
DEBUGMSGTL(("winExtDLL", "Windows OID converted to Net-SNMP: "));
316
DEBUGMSGOID(("winExtDLL", name, length));
317
DEBUGMSG(("winExtDLL", "\n"));
319
// Store supported view in Windows format
320
SnmpUtilOidCpy(&winExtensionAgent[winExtensionAgent_num].pSupportedView,&pSupportedView);
107
#define MS_ASN_UINTEGER32 MS_ASN_UNSIGNED32
110
typedef BOOL(WINAPI *
111
PFNSNMPEXTENSIONINIT) (DWORD dwUpTimeReference,
112
HANDLE * phSubagentTrapEvent,
113
AsnObjectIdentifier *
114
pFirstSupportedRegion);
116
typedef BOOL(WINAPI *
117
PFNSNMPEXTENSIONINITEX) (AsnObjectIdentifier *
118
pNextSupportedRegion);
120
typedef BOOL(WINAPI *
121
PFNSNMPEXTENSIONMONITOR) (LPVOID pAgentMgmtData);
123
typedef BOOL(WINAPI * PFNSNMPEXTENSIONQUERY) (BYTE bPduType,
131
typedef BOOL(WINAPI * PFNSNMPEXTENSIONQUERYEX) (UINT nRequestType,
143
typedef BOOL(WINAPI * PFNSNMPEXTENSIONTRAP) (AsnObjectIdentifier *
154
typedef VOID(WINAPI * PFNSNMPEXTENSIONCLOSE) (void);
157
* Extensible array, a data structure similar to the C++ STL class
161
/** Pointer to the memory allocated for the array. */
163
/** Number of bytes occupied by a single element. */
165
/** Number of elements that have been allocated. */
167
/** Number of elements currently in use. */
172
* Information managed by winExtDLL about Windows SNMP extension DLL's.
175
char *dll_name; /**< Dynamically allocated DLL name. */
176
HANDLE dll_handle; /**< DLL handle. */
177
PFNSNMPEXTENSIONINIT pfSnmpExtensionInit;
178
PFNSNMPEXTENSIONINITEX pfSnmpExtensionInitEx;
179
PFNSNMPEXTENSIONQUERY pfSnmpExtensionQuery;
180
PFNSNMPEXTENSIONQUERYEX pfSnmpExtensionQueryEx;
181
PFNSNMPEXTENSIONTRAP pfSnmpExtensionTrap;
182
HANDLE subagentTrapEvent;
186
* Information managed by winExtDLL about a single view of a Windows SNMP
190
winextdll *winextdll_info;
191
netsnmp_handler_registration *my_handler;
192
oid name[MAX_OID_LEN]; /**< OID of this view. */
197
* Per varbind SNMP extension DLL context information for SNMP set operations.
199
typedef struct context_info_s {
200
struct context_info_s *next;
202
AsnOctetString context_info;
207
* External function declarations.
209
void __declspec(dllimport) WINAPI SnmpSvcInitUptime(void);
213
* Local functions declarations.
215
static int basename_equals(const char *path, const char *basename);
216
static int register_netsnmp_handler(winextdll_view *
217
const ext_dll_view_info);
218
static void read_extension_dlls_from_registry(void);
219
static void read_extension_dlls_from_registry_at(const char *const subkey);
220
static char *read_extension_dll_path_from_registry(const TCHAR *);
221
static void subagentTrapCheck(unsigned int clientreg, void *clientarg);
222
static int var_winExtDLL(netsnmp_mib_handler *handler,
223
netsnmp_handler_registration *reginfo,
224
netsnmp_agent_request_info *reqinfo,
225
netsnmp_request_info *requests);
226
static int append_windows_varbind_list(netsnmp_variable_list **
227
const net_snmp_varbinds,
228
const SnmpVarBindList *
230
static int append_windows_varbind(netsnmp_variable_list **
231
const net_snmp_varbinds,
234
static int convert_to_windows_varbind_list(SnmpVarBindList *
236
netsnmp_variable_list *
238
static int convert_win_snmp_err(const int win_snmp_err);
239
static winextdll_view *lookup_view_by_oid(oid * const name,
240
const size_t name_len);
241
static void copy_oid(oid * const to_name, size_t * const to_name_len,
242
const oid * const from_name,
243
const size_t from_name_len);
244
static UINT *copy_oid_to_new_windows_oid(AsnObjectIdentifier *
246
const oid * const name,
247
const size_t name_len);
248
static void send_trap(const AsnObjectIdentifier * const,
249
const AsnInteger, const AsnInteger,
251
const SnmpVarBindList * const);
252
static u_char *winsnmp_memdup(const void *src, const size_t len);
254
static void xarray_init(xarray * a, size_t elem_size);
256
static void xarray_destroy(xarray * a);
257
static void *xarray_push_back(xarray * a, const void *elem);
259
static void xarray_erase(xarray * a, void *const elem);
261
static void *xarray_reserve(xarray * a, int reserved);
265
* Local variable definitions.
267
#define WINEXTDLL(i) ((winextdll*)s_winextdll.p)[i]
268
#define WINEXTDLL_VIEW(i) ((winextdll_view*)s_winextdll_view.p)[i]
269
#define TRAPEVENT(i) ((HANDLE*)s_trapevent.p)[i]
270
#define TRAPEVENT_TO_DLLINFO(i) ((winextdll**)s_trapevent_to_dllinfo.p)[i]
271
static xarray s_winextdll = { 0, sizeof(winextdll) };
272
static xarray s_winextdll_view = { 0, sizeof(winextdll_view) };
273
static xarray s_trapevent = { 0, sizeof(HANDLE) };
274
static xarray s_trapevent_to_dllinfo = { 0, sizeof(winextdll *) };
275
static context_info *context_info_head;
279
* Function definitions.
282
/** Initialize the winExtDLL extension agent. */
289
DEBUGMSG(("winExtDLL", "init_winExtDLL started.\n"));
293
read_extension_dlls_from_registry();
295
DEBUGMSG(("winExtDLL",
296
"init_winExtDLL: found %d extension DLLs in the registry.\n",
299
xarray_reserve(&s_winextdll, 128);
304
for (i = 0; i < s_winextdll.size; i++) {
305
winextdll *const ext_dll_info = &WINEXTDLL(i);
306
AsnObjectIdentifier view;
307
winextdll_view ext_dll_view_info;
309
assert(ext_dll_info);
310
if (!ext_dll_info->dll_name)
313
DEBUGMSG(("winExtDLL", "loading DLL %s.\n",
314
ext_dll_info->dll_name));
315
ext_dll_info->dll_handle = LoadLibrary(ext_dll_info->dll_name);
317
if (ext_dll_info->dll_handle == NULL) {
318
const DWORD dwErrorcode = GetLastError();
321
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
322
FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErrorcode,
323
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
324
(LPTSTR) & lpMsgBuf, 0, NULL);
329
* Remove trailing "\r\n".
331
p = strchr(lpMsgBuf, '\r');
336
"init_winExtDLL: could not load SNMP extension"
338
ext_dll_info->dll_name, lpMsgBuf ? lpMsgBuf : "(?)");
345
* Store DLL name and functions in s_extension_dll_info array.
347
ext_dll_info->pfSnmpExtensionInit = (PFNSNMPEXTENSIONINIT)
348
GetProcAddress(ext_dll_info->dll_handle, "SnmpExtensionInit");
349
ext_dll_info->pfSnmpExtensionInitEx = (PFNSNMPEXTENSIONINITEX)
350
GetProcAddress(ext_dll_info->dll_handle,
351
"SnmpExtensionInitEx");
352
ext_dll_info->pfSnmpExtensionQuery = (PFNSNMPEXTENSIONQUERY)
353
GetProcAddress(ext_dll_info->dll_handle, "SnmpExtensionQuery");
354
ext_dll_info->pfSnmpExtensionQueryEx = (PFNSNMPEXTENSIONQUERYEX)
355
GetProcAddress(ext_dll_info->dll_handle,
356
"SnmpExtensionQueryEx");
357
ext_dll_info->pfSnmpExtensionTrap = (PFNSNMPEXTENSIONTRAP)
358
GetProcAddress(ext_dll_info->dll_handle, "SnmpExtensionTrap");
361
if (ext_dll_info->pfSnmpExtensionQuery == NULL
362
&& ext_dll_info->pfSnmpExtensionQueryEx == NULL) {
364
"error in extension DLL %s: SNMP query function missing.\n",
365
ext_dll_info->dll_name);
369
* Init and get first supported view from Windows SNMP extension DLL.
370
* Note: although according to the documentation of SnmpExtensionInit()
371
* the first argument of this function should be ignored by extension
372
* DLLs, passing the value GetTickCount() / 10 is necessary to make
373
* inetmib1.dll work correctly. Passing zero as the first argument
374
* causes inetmib1.dll to report an incorrect value for sysUpTime.0
375
* and also causes the same DLL not to send linkUp or linkDown traps.
377
ext_dll_info->subagentTrapEvent = NULL;
381
ext_dll_info->pfSnmpExtensionInit(GetTickCount() / 10,
383
subagentTrapEvent, &view);
387
"init_winExtDLL: initialization of DLL %s failed.\n",
388
ext_dll_info->dll_name);
389
FreeLibrary(ext_dll_info->dll_handle);
390
ext_dll_info->dll_handle = 0;
394
if (ext_dll_info->subagentTrapEvent != NULL) {
395
xarray_push_back(&s_trapevent,
396
&ext_dll_info->subagentTrapEvent);
397
xarray_push_back(&s_trapevent_to_dllinfo, &ext_dll_info);
400
memset(&ext_dll_view_info, 0, sizeof(ext_dll_view_info));
401
ext_dll_view_info.winextdll_info = ext_dll_info;
402
copy_oid(ext_dll_view_info.name, &ext_dll_view_info.name_length,
403
view.ids, view.idLength);
404
xarray_push_back(&s_winextdll_view, &ext_dll_view_info);
407
* Loop looking for more supported views.
409
while (ext_dll_info->pfSnmpExtensionInitEx
410
&& ext_dll_info->pfSnmpExtensionInitEx(&view)) {
411
memset(&ext_dll_view_info, 0, sizeof(ext_dll_view_info));
412
ext_dll_view_info.winextdll_info = ext_dll_info;
413
copy_oid(ext_dll_view_info.name,
414
&ext_dll_view_info.name_length, view.ids,
416
xarray_push_back(&s_winextdll_view, &ext_dll_view_info);
421
* Note: since register_netsnmp_handler() writes a pointer to the
422
* winextdll_view in one of the Net-SNMP data structures, it is not
423
* allowed to move winextdll_view data structures in memory after
424
* registration with Net-SNMP. Or: register_snmp_handler() must be called
425
* only once it is sure that the size of array s_winextdll_view won't change
428
for (i = 0; i < s_winextdll_view.size; i++)
429
register_netsnmp_handler(&WINEXTDLL_VIEW(i));
431
DEBUGMSG(("winExtDLL",
432
"init_winExtDLL: registered %d OID ranges.\n",
433
s_winextdll_view.size));
436
* Let Net-SNMP call subagentTrapCheck() once per second.
438
if (s_trapevent.size)
439
snmp_alarm_register(1, SA_REPEAT, subagentTrapCheck, NULL);
441
DEBUGMSG(("winExtDLL", "init_winExtDLL finished.\n"));
445
shutdown_winExtDLL(void)
449
DEBUGMSG(("winExtDLL", "shutdown_winExtDLL() started.\n"));
451
for (i = s_winextdll_view.size - 1; i >= 0; i--) {
452
winextdll_view *const v = &WINEXTDLL_VIEW(i);
453
if (v && v->my_handler) {
454
DEBUGIF("winExtDLL") {
455
DEBUGMSG(("winExtDLL",
456
"unregistering handler for DLL %s and OID prefix ",
457
v->winextdll_info->dll_name));
458
DEBUGMSGOID(("winExtDLL", v->name, v->name_length));
459
DEBUGMSG(("winExtDLL", " ("));
460
DEBUGMSGSUBOID(("winExtDLL", v->name, v->name_length));
461
DEBUGMSG(("winExtDLL", ").\n"));
463
netsnmp_unregister_handler(v->my_handler);
466
xarray_destroy(&s_winextdll_view);
468
for (i = s_winextdll.size - 1; i >= 0; i--) {
469
winextdll *const ext_dll_info = &WINEXTDLL(i);
471
* Freeing the Broadcom SNMP extension libraries triggers a deadlock,
472
* so skip bcmif.dll and baspmgnt.dll.
474
if (ext_dll_info->dll_handle != 0
475
&& !basename_equals(ext_dll_info->dll_name, "bcmif.dll")
476
&& !basename_equals(ext_dll_info->dll_name, "baspmgnt.dll")) {
477
DEBUGMSG(("winExtDLL", "unloading %s.\n",
478
ext_dll_info->dll_name));
479
FreeLibrary(ext_dll_info->dll_handle);
481
free(ext_dll_info->dll_name);
483
xarray_destroy(&s_winextdll);
485
xarray_destroy(&s_trapevent_to_dllinfo);
487
xarray_destroy(&s_trapevent);
489
DEBUGMSG(("winExtDLL", "shutdown_winExtDLL() finished.\n"));
493
* Compare the basename of a path with a given string.
495
* @return 1 if the basename matches, 0 if not.
498
basename_equals(const char *path, const char *basename)
500
const size_t path_len = strlen(path);
501
const size_t basename_len = strlen(basename);
503
assert(strchr(path, '/') == 0);
504
assert(strchr(basename, '/') == 0);
505
assert(strchr(basename, '\\') == 0);
507
return path_len >= basename_len + 1
508
&& path[path_len - basename_len - 1] == '\\'
509
&& stricmp(path + path_len - basename_len, basename) == 0;
513
* Register a single OID subtree with Net-SNMP.
515
* @return 1 if successful, 0 if not.
518
register_netsnmp_handler(winextdll_view * const ext_dll_view_info)
520
winextdll *ext_dll_info;
521
winextdll_view *previously_registered_view;
523
ext_dll_info = ext_dll_view_info->winextdll_info;
525
previously_registered_view
526
= lookup_view_by_oid(ext_dll_view_info->name,
527
ext_dll_view_info->name_length);
529
if (previously_registered_view) {
530
size_t oid_namelen, outlen;
532
int buffer_large_enough;
537
buffer_large_enough =
538
sprint_realloc_objid((u_char **) & oid_name, &oid_namelen,
539
&outlen, 1, ext_dll_view_info->name,
540
ext_dll_view_info->name_length);
541
snmp_log(LOG_INFO, "OID range %s%s: replacing handler %s by %s.\n",
542
oid_name ? oid_name : "",
543
buffer_large_enough ? "" : " [TRUNCATED]",
544
previously_registered_view->winextdll_info->dll_name,
545
ext_dll_view_info->winextdll_info->dll_name);
549
previously_registered_view->winextdll_info = ext_dll_info;
550
memset(ext_dll_view_info, 0, sizeof(*ext_dll_view_info));
322
553
// Create handler registration
323
winExtensionAgent[winExtensionAgent_num].my_handler = netsnmp_create_handler_registration("winExtDLL",
329
if (!winExtensionAgent[winExtensionAgent_num].my_handler) {
331
"malloc failed registering handler for winExtDLL");
332
DEBUGMSGTL(("winExtDLL", "malloc failed registering handler for winExtDLL"));
336
DEBUGMSGTL(("winExtDLL", "handler registered\n"));
339
// Register handler with Net-SNMP
340
netsnmp_register_handler(winExtensionAgent[winExtensionAgent_num].my_handler);
342
winExtensionAgent_num++;
345
winExtensionAgent_num++;
349
winExtensionAgent_index = winExtensionAgent_num-1; // Array index
350
DEBUGMSGTL(("winExtDLL", "winExtensionAgent_index: %d\n",winExtensionAgent_index));
352
/* Reverse sort array of winExtensionAgents */
353
i = sizeof(winExtensionAgent) / sizeof(winExtensionAgents);
354
//DEBUGMSGTL(("winExtDLL", "Sorting...\n"));
355
for (iter=0; iter < i-1; iter++) {
356
for (indx=0; indx < i-1; indx++) {
357
if (snmp_oidtree_compare(winExtensionAgent[indx].name, winExtensionAgent[indx].name_length,
358
winExtensionAgent[indx+1].name, winExtensionAgent[indx+1].name_length) < 0) {
359
winExtensionAgent_temp = winExtensionAgent[indx];
360
winExtensionAgent[indx] = winExtensionAgent[indx+1];
361
winExtensionAgent[indx+1] = winExtensionAgent_temp;
365
DEBUGMSGTL(("winExtDLL", "Dumping sorted Windows extension OIDs\n"));
366
for (i=0; winExtensionAgent[i].xSnmpExtensionInit; i++) {
367
DEBUGMSGTL(("winExtDLL", "DLL name: %s, view: ",winExtensionAgent[i].dll_name));
368
DEBUGMSGOID(("winExtDLL", winExtensionAgent[i].name, winExtensionAgent[i].name_length));
369
DEBUGMSG(("winExtDLL", "\n"));
372
DEBUGMSGTL(("winExtDLL", "Number of subagentTrapEvents: %d\n",subagentTrapEvents_index));
374
if (subagentTrapEvents_index) {
376
DEBUGMSGTL(("winExtDLL", "Setting alarm check for subagent trap events every 5 seconds\n"));
377
snmp_alarm_register(5, /* seconds */
378
SA_REPEAT, /* repeat (every x seconds). */
379
subagentTrapCheck, /* our callback */
380
NULL /* no callback data needed */
554
ext_dll_view_info->my_handler
555
= netsnmp_create_handler_registration(ext_dll_info->dll_name,
557
ext_dll_view_info->name,
562
if (ext_dll_view_info->my_handler) {
563
ext_dll_view_info->my_handler->handler->myvoid =
565
if (netsnmp_register_handler(ext_dll_view_info->my_handler)
566
== MIB_REGISTERED_OK) {
567
DEBUGIF("winExtDLL") {
568
DEBUGMSG(("winExtDLL",
569
"registering handler for DLL %s and OID prefix ",
570
ext_dll_info->dll_name));
571
DEBUGMSGOID(("winExtDLL", ext_dll_view_info->name,
572
ext_dll_view_info->name_length));
573
DEBUGMSG(("winExtDLL", " ("));
574
DEBUGMSGSUBOID(("winExtDLL", ext_dll_view_info->name,
575
ext_dll_view_info->name_length));
576
DEBUGMSG(("winExtDLL", ").\n"));
580
snmp_log(LOG_ERR, "handler registration failed.\n");
581
ext_dll_view_info->my_handler = 0;
584
snmp_log(LOG_ERR, "handler creation failed.\n");
592
* Allocate SNMP extension DLL context information. Such context information
593
* is necessary to allow an extension DLL to process a set request.
595
* @param[in] index Varbind index in original PDU.
597
* @return NULL if context information for the specified index was already
598
* allocated, and otherwise a pointer to the newly allocated context
601
static context_info *
602
alloc_context_info(const int index)
606
DEBUGMSG(("winExtDLL:context_info", "alloc_context_info(%d)\n",
609
for (p = context_info_head; p; p = p->next) {
610
if (p->index == index) {
616
p = calloc(1, sizeof(context_info));
617
p->next = context_info_head;
618
context_info_head = p;
625
* Deallocate SNMP extension DLL context information.
627
* @param[in] index Varbind index in original PDU.
630
free_context_info(const int index)
632
context_info **pprev = &context_info_head;
635
DEBUGMSG(("winExtDLL:context_info", "free_context_info(%d)\n", index));
637
for (p = context_info_head; p; p = p->next) {
638
if (p->index == index) {
648
* Look up SNMP extension DLL context information.
650
* @param[in] index Varbind index in original PDU.
652
static AsnOctetString *
653
get_context_info(const int index)
657
DEBUGMSG(("winExtDLL:context_info", "get_context_info(%d)\n", index));
659
for (p = context_info_head; p; p = p->next)
660
if (p->index == index)
661
return &p->context_info;
386
668
var_winExtDLL(netsnmp_mib_handler *handler,
387
669
netsnmp_handler_registration *reginfo,
388
670
netsnmp_agent_request_info *reqinfo,
389
671
netsnmp_request_info *requests)
392
netsnmp_request_info *request = requests;
393
netsnmp_variable_list *var;
394
oid oid_requested[MAX_OID_LEN];
395
size_t oid_requested_length;
397
static char ret_szbuf_temp[SZBUF_MAX]; // Holder for return strings
398
static oid ret_oid[MAX_OID_LEN]; // Holder for return OIDs
399
static size_t ret_oid_length = 0; // Holder for return OIDs
400
static long ret_long; // Holder for all other returns
402
static char set_szbuf_temp[SZBUF_MAX]; // Holder for set strings
403
static oid set_oid[MAX_OID_LEN]; // Holder for set OIDs
404
static size_t set_oid_length = 0; // Holder for set OIDs
406
size_t temp_oid_length;
409
static u_long accesses = 7;
410
u_char netsnmp_ASN_type;
411
u_char windows_ASN_type;
415
// WinSNMP variables:
417
SnmpVarBind *mySnmpVarBind;
418
AsnInteger32 pErrorStatus;
419
AsnInteger32 pErrorIndex;
420
SnmpVarBindList pVarBindList;
424
DWORD (WINAPI *xSnmpExtensionQuery)(BYTE, SnmpVarBindList* ,AsnInteger32* ,AsnInteger32*);
425
DWORD (WINAPI *xSnmpExtensionQueryEx)(DWORD, DWORD, SnmpVarBindList*, AsnOctetString*, AsnInteger32*, AsnInteger32*);
426
DWORD (WINAPI *next_xSnmpExtensionQuery)(BYTE, SnmpVarBindList* ,AsnInteger32* ,AsnInteger32*);
427
DWORD (WINAPI *next_xSnmpExtensionQueryEx)(DWORD, DWORD, SnmpVarBindList*, AsnOctetString*, AsnInteger32*, AsnInteger32*);
428
AsnObjectIdentifier winExtensionAgent_pSupportedView; // Support view of this extension agent
429
oid winExtensionAgent_name[MAX_OID_LEN]; // Support view of this extension agent
430
size_t winExtensionAgent_name_length; // Support view of this extension agent
432
int match_winExtensionAgent_index = -1;
434
DEBUGMSGTL(("winExtDLL", "-----------------------------------------\n"));
435
DEBUGMSGTL(("winExtDLL", "var_winExtDLL handler starting, mode = %d\n",
673
winextdll_view *const ext_dll_view_info = handler->myvoid;
674
winextdll *ext_dll_info;
675
netsnmp_request_info *request;
677
const char *mode_name;
680
assert(ext_dll_view_info);
681
ext_dll_info = ext_dll_view_info->winextdll_info;
682
#if ! defined(NDEBUG)
683
assert(ext_dll_view_info ==
684
lookup_view_by_oid(reginfo->rootoid, reginfo->rootoid_len));
687
if (ext_dll_info == 0) {
688
DEBUGMSG(("winExtDLL",
689
"internal error: no matching extension DLL found.\n"));
691
return SNMP_ERR_GENERR;
438
694
switch (reqinfo->mode) {
697
nRequestType = SNMP_EXTENSION_GET;
698
assert(!context_info_head);
440
700
case MODE_GETNEXT:
442
if (reqinfo->mode == MODE_GET)
443
DEBUGMSGTL(("winExtDLL", "GET requested\n"));
444
else if (reqinfo->mode == MODE_GETNEXT)
445
DEBUGMSGTL(("winExtDLL", "GETNEXT requested\n"));
447
for (request = requests; request; request=request->next) {
449
var = request->requestvb;
451
// Make copy of requested OID
452
for (i = 0; i < (var->name_length > MAX_OID_LEN? MAX_OID_LEN: var->name_length); i++) {
453
oid_requested[i] = var->name[i];
455
oid_requested_length = i;
457
DEBUGMSGTL(("winExtDLL", "Requested: "));
458
DEBUGMSGOID(("winExtDLL", oid_requested, oid_requested_length));
459
DEBUGMSG(("winExtDLL", "\n"));
461
DEBUGMSGTL(("winExtDLL", "Var type requested: %d\n",var->type));
463
/* Loop through all the winExtensionAgent's looking for a matching handler */
464
xSnmpExtensionQuery = NULL;
465
xSnmpExtensionQueryEx = NULL;
466
next_xSnmpExtensionQuery = NULL;
467
next_xSnmpExtensionQueryEx = NULL;
469
DEBUGMSGTL(("winExtDLL", "Looping through all the winExtensionAgent's looking for a matching handler (exact).\n"));
470
// Search starting with lowest so a walk of .1.3 starts with the lowest extension
471
for (i = winExtensionAgent_index; winExtensionAgent[i].xSnmpExtensionInit && i >= 0; i--) {
473
/*DEBUGMSGTL(("winExtDLL", "Comparing: "));
474
DEBUGMSGOID(("winExtDLL", var->name, var->name_length));
475
DEBUGMSG(("winExtDLL", "\n"));
477
DEBUGMSGTL(("winExtDLL", "to: "));
478
DEBUGMSGOID(("winExtDLL", winExtensionAgent[i].name, winExtensionAgent[i].name_length));
479
DEBUGMSG(("winExtDLL", "\n"));*/
481
if (snmp_oidtree_compare(var->name, var->name_length, winExtensionAgent[i].name,
482
winExtensionAgent[i].name_length) == 0) {
484
DEBUGMSGTL(("winExtDLL", "Found exact match: "));
485
DEBUGMSGOID(("winExtDLL", winExtensionAgent[i].name, winExtensionAgent[i].name_length));
486
DEBUGMSG(("winExtDLL", "\n"));
487
match_winExtensionAgent_index = i;
488
//DEBUGMSGTL(("winExtDLL", "Index: %d\n",match_winExtensionAgent_index));
493
if (match_winExtensionAgent_index == -1) {
494
DEBUGMSGTL(("winExtDLL", "Looping through all the winExtensionAgent's looking for a matching handler (next best).\n"));
495
for (i=0; winExtensionAgent[i].xSnmpExtensionInit && i < MAX_WINEXT_DLLS; i++) {
497
/*DEBUGMSGTL(("winExtDLL", "Comparing: "));
498
DEBUGMSGOID(("winExtDLL", var->name, var->name_length));
499
DEBUGMSG(("winExtDLL", "\n"));
501
DEBUGMSGTL(("winExtDLL", "to: "));
502
DEBUGMSGOID(("winExtDLL", winExtensionAgent[i].name, winExtensionAgent[i].name_length));
503
DEBUGMSG(("winExtDLL", "\n"));
504
DEBUGMSGTL(("winExtDLL", "and: "));
505
DEBUGMSGOID(("winExtDLL", winExtensionAgent[i+1].name, winExtensionAgent[i+1].name_length));
506
DEBUGMSG(("winExtDLL", "\n")); */
508
if (snmp_oidtree_compare(var->name, var->name_length, winExtensionAgent[i].name,
509
winExtensionAgent[i].name_length) <= 0 &&
510
snmp_oidtree_compare(var->name, var->name_length, winExtensionAgent[i+1].name,
511
winExtensionAgent[i+1].name_length) >= 0 // FIXME: Checking past the last extension?
513
DEBUGMSGTL(("winExtDLL", "Found best match: "));
514
DEBUGMSGOID(("winExtDLL", winExtensionAgent[i].name, winExtensionAgent[i].name_length));
515
DEBUGMSG(("winExtDLL", "\n"));
516
match_winExtensionAgent_index = i;
517
//DEBUGMSGTL(("winExtDLL", "Index: %d\n",match_winExtensionAgent_index));
523
//DEBUGMSG(("winExtDLL", "Index: %d\n",match_winExtensionAgent_index));
525
if (match_winExtensionAgent_index == -1) {
526
DEBUGMSGTL(("winExtDLL","Could not find a handler for the requested OID. This should never happen!!\n"));
527
return SNMP_ERR_GENERR;
530
// Make copy of current extension's OID
531
for (j = 0; j < (winExtensionAgent[i].name_length > MAX_OID_LEN? MAX_OID_LEN: winExtensionAgent[i].name_length); j++) {
532
winExtensionAgent_name[j] = winExtensionAgent[i].name[j];
534
winExtensionAgent_name_length = j;
536
xSnmpExtensionQuery = winExtensionAgent[i].xSnmpExtensionQuery;
537
xSnmpExtensionQueryEx = winExtensionAgent[i].xSnmpExtensionQueryEx;
538
SnmpUtilOidCpy(&winExtensionAgent_pSupportedView, &winExtensionAgent[i].pSupportedView);
540
if (! (xSnmpExtensionQuery || xSnmpExtensionQueryEx)) {
541
if (reqinfo->mode == MODE_GET) {
542
DEBUGMSGTL(("winExtDLL","Could not find a handler for the requested OID. This should never happen!!\n"));
543
return SNMP_ERR_GENERR;
546
DEBUGMSGTL(("winExtDLL","Could not find a handler for the requested OID. Returning SNMP_ERR_NOSUCHNAME.\n"));
547
return SNMP_ERR_NOSUCHNAME;
552
pVarBindList.list = (SnmpVarBind *) SnmpUtilMemAlloc(sizeof (SnmpVarBind));
553
if (pVarBindList.list) {
555
// Convert OID from Net-SNMP to Windows
557
pVarBindList.list->name.ids = (UINT *) SnmpUtilMemAlloc(sizeof (UINT) *var->name_length);
559
if (pVarBindList.list->name.ids) {
562
for (i = 0; i < var->name_length; i++) {
563
pVarBindList.list->name.ids[i] = (UINT)var->name[i];
565
pVarBindList.list->name.idLength = i;
567
DEBUGMSGTL(("winExtDLL", "Windows OID: "));
568
DEBUGMSGWINOID(("winExtDLL", pVarBindList.list));
569
DEBUGMSG(("winExtDLL", "\n"));
573
DEBUGMSGTL(("winExtDLL", "\nyCould not allocate memory for Windows SNMP varbind.\n"));
577
//pVarBindList.list = pVarBindList.list;
579
pVarBindList.len = 1;
582
DEBUGMSGTL(("winExtDLL", "Could not allocate memory for Windows SNMP varbind list.\n"));
586
if (reqinfo->mode == MODE_GET) {
587
DEBUGMSGTL(("winExtDLL", "win: MODE_GET\n"));
588
if (xSnmpExtensionQueryEx) {
589
DEBUGMSGTL(("winExtDLL", "Calling xSnmpExtensionQueryEx\n"));
590
result = xSnmpExtensionQueryEx(SNMP_PDU_GET, 1, &pVarBindList, NULL, &pErrorStatus, &pErrorIndex);
593
DEBUGMSGTL(("winExtDLL", "Calling xSnmpExtensionQuery\n"));
594
result = xSnmpExtensionQuery(SNMP_PDU_GET, &pVarBindList, &pErrorStatus, &pErrorIndex);
597
else if (reqinfo->mode == MODE_GETNEXT) {
598
DEBUGMSGTL(("winExtDLL", "win: MODE_GETNEXT -\n"));
599
if (xSnmpExtensionQueryEx) {
600
DEBUGMSGTL(("winExtDLL", "Calling xSnmpExtensionQueryEx\n"));
601
result = xSnmpExtensionQueryEx(SNMP_PDU_GETNEXT, 1, &pVarBindList, NULL, &pErrorStatus, &pErrorIndex);
604
DEBUGMSGTL(("winExtDLL", "Calling xSnmpExtensionQuery\n"));
605
result = xSnmpExtensionQuery(SNMP_PDU_GETNEXT, &pVarBindList, &pErrorStatus, &pErrorIndex);
608
DEBUGMSGTL(("winExtDLL", "Windows OID returned from xSnmpExtensionQuery(Ex): "));
609
DEBUGMSGWINOID(("winExtDLL", pVarBindList.list));
610
DEBUGMSG(("winExtDLL", "\n"));
612
// Convert OID from Windows to Net-SNMP so Net-SNMP has the new 'next' OID
613
// FIXME: Do we need to realloc var->name or is is MAX_OID_LEN?
614
for (i = 0; i < (pVarBindList.list->name.idLength > MAX_OID_LEN?MAX_OID_LEN:pVarBindList.list->name.idLength); i++) {
615
var->name[i] = (oid)pVarBindList.list->name.ids[i];
617
var->name_length = i;
619
DEBUGMSGTL(("winExtDLL", "Comparing: "));
620
DEBUGMSGOID(("winExtDLL", var->name, var->name_length));
621
DEBUGMSG(("winExtDLL", "\n"));
623
DEBUGMSGTL(("winExtDLL", "to: "));
624
DEBUGMSGOID(("winExtDLL", winExtensionAgent_name, winExtensionAgent_name_length));
625
DEBUGMSG(("winExtDLL", "\n"));
628
// If the OID we got back is less than or equal to what we requested, increment the current supported view
629
// and send it back instead.
630
if (snmp_oid_compare(var->name, var->name_length, oid_requested, oid_requested_length) <= 0) {
631
DEBUGMSGTL(("winExtDLL", "xSnmpExtensionQuery(Ex) returned an OID less than or equal to what we requested\n"));
632
DEBUGMSGTL(("winExtDLL", " Setting return OID to be equal to current supported view, plus one\n"));
634
// Set var->name to be equal to current supported view, plus one
635
for (i = 0; i < (winExtensionAgent_name_length > MAX_OID_LEN? MAX_OID_LEN: winExtensionAgent_name_length); i++) {
636
var->name[i] = winExtensionAgent_name[i];
638
var->name_length = i;
641
//return SNMP_ERR_NOSUCHNAME;
645
// If the OID we got back is outside our view, increment the current supported view and send it back instead.
646
// This is for Windows extension agents that support multiple views. We want Net-SNMP to decide if we should be
647
// called for this OID, not the extension agent, just in case there is a Net-SNMP agent in between.
648
else if (snmp_oidtree_compare(var->name, var->name_length, winExtensionAgent_name, winExtensionAgent_name_length) > 0) {
649
DEBUGMSGTL(("winExtDLL", "xSnmpExtensionQuery(Ex) returned an OID outside our view\n"));
650
DEBUGMSGTL(("winExtDLL", " Setting return OID to be equal to current supported view, plus one\n"));
652
// Set var->name to be equal to current supported view, plus one
653
for (i = 0; i < (winExtensionAgent_name_length > MAX_OID_LEN? MAX_OID_LEN: winExtensionAgent_name_length); i++) {
654
var->name[i] = winExtensionAgent_name[i];
656
var->name_length = i;
659
//return SNMP_ERR_NOSUCHNAME;
663
DEBUGMSGTL(("winExtDLL", "OID being sent back to Net-SNMP: "));
664
DEBUGMSGOID(("winExtDLL", var->name, var->name_length));
665
DEBUGMSG(("winExtDLL", "\n"));
667
DEBUGMSGTL(("winExtDLL", "win: Result of xSnmpExtensionQuery(Ex): %d\n",result));
669
DEBUGMSGTL(("winExtDLL", "win: Error status of xSnmpExtensionQuery(Ex): %d\n",pErrorStatus));
671
DEBUGMSGTL(("winExtDLL", "win: asnType: %d\n",pVarBindList.list->value.asnType));
673
// Set Net-SNMP ASN type based on closest match to Windows ASN type
674
switch (pVarBindList.list->value.asnType) {
675
case MS_ASN_OCTETSTRING:
676
netsnmp_ASN_type = ASN_OCTET_STR;
677
DEBUGMSGTL(("winExtDLL", "MS_ASN_OCTETSTRING = ASN_OCTET_STR\n"));
679
case MS_ASN_INTEGER: // And MS_ASN_INTEGER32
680
netsnmp_ASN_type = ASN_INTEGER;
681
DEBUGMSGTL(("winExtDLL", "MS_ASN_INTEGER = ASN_INTEGER\n"));
683
case MS_ASN_UNSIGNED32: // SNMP v2
684
netsnmp_ASN_type = ASN_UNSIGNED;
685
DEBUGMSGTL(("winExtDLL", "MS_ASN_UNSIGNED32 = ASN_UNSIGNED\n"));
687
case MS_ASN_COUNTER64: // SNMP v2
688
netsnmp_ASN_type = ASN_COUNTER64;
689
DEBUGMSGTL(("winExtDLL", "MS_ASN_COUNTER64 = ASN_COUNTER64\n"));
692
netsnmp_ASN_type = ASN_BIT_STR;
693
DEBUGMSGTL(("winExtDLL", "MS_ASN_BITS = ASN_BIT_STR\n"));
695
case MS_ASN_OBJECTIDENTIFIER:
696
netsnmp_ASN_type = ASN_OBJECT_ID;
697
DEBUGMSGTL(("winExtDLL", "MS_ASN_OBJECTIDENTIFIER = ASN_OBJECT_ID\n"));
699
case MS_ASN_SEQUENCE:
700
netsnmp_ASN_type = ASN_SEQUENCE;
701
DEBUGMSGTL(("winExtDLL", "MS_ASN_SEQUENCE = ASN_SEQUENCE\n"));
703
case MS_ASN_IPADDRESS:
704
netsnmp_ASN_type = ASN_IPADDRESS;
705
DEBUGMSGTL(("winExtDLL", "MS_ASN_IPADDRESS = ASN_IPADDRESS\n"));
707
case MS_ASN_COUNTER32:
708
netsnmp_ASN_type = ASN_COUNTER;
709
DEBUGMSGTL(("winExtDLL", "MS_ASN_COUNTER32 = ASN_COUNTER\n"));
712
netsnmp_ASN_type = ASN_GAUGE;
713
DEBUGMSGTL(("winExtDLL", "MS_ASN_GAUGE32 = ASN_GAUGE\n"));
715
case MS_ASN_TIMETICKS:
716
netsnmp_ASN_type = ASN_TIMETICKS;
717
DEBUGMSGTL(("winExtDLL", "MS_ASN_TIMETICKS = ASN_TIMETICKS\n"));
720
netsnmp_ASN_type = ASN_OPAQUE;
721
DEBUGMSGTL(("winExtDLL", "MS_ASN_OPAQUE = ASN_OPAQUE\n"));
724
netsnmp_ASN_type = ASN_INTEGER;
725
DEBUGMSGTL(("winExtDLL", "unknown MS ASN type. Defaulting to ASN_INTEGER\n"));
729
DEBUGMSGTL(("winExtDLL", "Net-SNMP object type for returned value: %d\n",netsnmp_ASN_type));
731
switch (pVarBindList.list->value.asnType) {
732
case MS_ASN_IPADDRESS:
733
case MS_ASN_OCTETSTRING:
735
strncpy(ret_szbuf_temp, pVarBindList.list->value.asnValue.string.stream, (pVarBindList.list->value.asnValue.string.length >
736
SZBUF_MAX?SZBUF_MAX:pVarBindList.list->value.asnValue.string.length));
738
if (pVarBindList.list->value.asnValue.string.length < SZBUF_MAX)
739
ret_szbuf_temp[pVarBindList.list->value.asnValue.string.length] = '\0';
741
ret_szbuf_temp[SZBUF_MAX-1] = '\0';
743
// Printing strings that have a comma in them via DEBUGMSGTL doesn't work..
744
DEBUGMSGTL(("winExtDLL", "Note: Sometimes junk is outputted here even though the string is fine. Problem with DEBUGMSGTL?\n",ret_szbuf_temp));
745
DEBUGMSGTL(("winExtDLL", "win: String: %s\n",ret_szbuf_temp));
746
DEBUGMSGTL(("winExtDLL", "win: length of string response: %d\n",strlen(ret_szbuf_temp)));
748
snmp_set_var_typed_value(var, netsnmp_ASN_type,
750
strlen(ret_szbuf_temp));
751
//return SNMP_ERR_NOERROR;
754
case MS_ASN_INTEGER: // And MS_ASN_INTEGER32
755
case MS_ASN_UNSIGNED32:
756
case MS_ASN_COUNTER64:
758
case MS_ASN_SEQUENCE:
759
case MS_ASN_COUNTER32:
761
case MS_ASN_TIMETICKS:
764
DEBUGMSGTL(("winExtDLL", "win: Long: %ld\n",pVarBindList.list->value.asnValue.number));
766
ret_long = pVarBindList.list->value.asnValue.number;
769
snmp_set_var_typed_value(var, netsnmp_ASN_type,
772
//return SNMP_ERR_NOERROR;
775
case MS_ASN_OBJECTIDENTIFIER:
776
// Convert OID to Net-SNMP
778
DEBUGMSGTL(("winExtDLL", "Returned OID: "));
779
DEBUGMSGWINOID(("winExtDLL", &pVarBindList.list->value.asnValue.object));
780
DEBUGMSG(("winExtDLL", "\n"));
782
// Convert OID from Windows to Net-SNMP
783
for (i = 0; i < (pVarBindList.list->value.asnValue.object.idLength > MAX_OID_LEN?MAX_OID_LEN:
784
pVarBindList.list->value.asnValue.object.idLength); i++) {
785
ret_oid[i] = (oid)pVarBindList.list->value.asnValue.object.ids[i];
789
DEBUGMSGTL(("winExtDLL", "Windows OID converted to Net-SNMP: "));
790
DEBUGMSGOID(("winExtDLL", ret_oid, ret_oid_length));
791
DEBUGMSG(("winExtDLL", "\n"));
793
snmp_set_var_typed_value(var, netsnmp_ASN_type,
795
ret_oid_length * sizeof(oid));
796
//return SNMP_ERR_NOERROR;
801
// The Windows agent didn't return data so set values to NULL
802
// FIXME: We never get here. We set it to INTEGER above..
803
snmp_set_var_typed_value(var, NULL,
809
SnmpUtilVarBindListFree(&pVarBindList);
813
case MODE_SET_RESERVE1:
701
mode_name = "GETNEXT";
702
nRequestType = SNMP_EXTENSION_GET_NEXT;
703
assert(!context_info_head);
705
case MODE_SET_RESERVE1:
706
mode_name = "SET_RESERVE1";
707
nRequestType = SNMP_EXTENSION_SET_TEST;
814
709
case MODE_SET_RESERVE2:
710
mode_name = "SET_RESERVE2";
711
return SNMP_ERR_NOERROR;
815
712
case MODE_SET_ACTION:
817
DEBUGMSGTL(("winExtDLL", "SET requested\n"));
819
for (request = requests; request; request=request->next) {
821
var = request->requestvb;
823
DEBUGMSGTL(("winExtDLL", "requested: "));
824
DEBUGMSGOID(("winExtDLL", var->name, var->name_length));
825
DEBUGMSG(("winExtDLL", "\n"));
827
DEBUGMSGTL(("winExtDLL", "Var type requested: %d\n",var->type));
829
/* Loop through all the winExtensionAgent's looking for a matching handler */
830
xSnmpExtensionQuery = NULL;
831
xSnmpExtensionQueryEx = NULL;
832
for (i=0; winExtensionAgent[i].xSnmpExtensionInit && i < MAX_WINEXT_DLLS; i++) {
833
DEBUGMSGTL(("winExtDLL", "Looping through all the winExtensionAgent's looking for a matching handler.\n"));
835
if (snmp_oidtree_compare(var->name, var->name_length, winExtensionAgent[i].name,
836
winExtensionAgent[i].name_length) >= 0) {
837
DEBUGMSGTL(("winExtDLL", "Found match: "));
838
DEBUGMSGOID(("winExtDLL", winExtensionAgent[i].name, winExtensionAgent[i].name_length));
839
DEBUGMSG(("winExtDLL", "\n"));
840
xSnmpExtensionQuery = winExtensionAgent[i].xSnmpExtensionQuery;
841
xSnmpExtensionQueryEx = winExtensionAgent[i].xSnmpExtensionQueryEx;
846
if (! (xSnmpExtensionQuery || xSnmpExtensionQueryEx)) {
847
DEBUGMSGTL(("winExtDLL","Could not find a handler for the requested OID. This should never happen!!\n"));
848
return SNMP_ERR_GENERR;
851
// Set Windows ASN type based on closest match to Net-SNMP ASN type
854
windows_ASN_type = MS_ASN_OCTETSTRING;
855
DEBUGMSGTL(("winExtDLL", "MS_ASN_OCTETSTRING = ASN_OCTET_STR\n"));
857
case ASN_INTEGER: // And MS_ASN_INTEGER32
858
windows_ASN_type = MS_ASN_INTEGER;
859
DEBUGMSGTL(("winExtDLL", "MS_ASN_INTEGER = ASN_INTEGER\n"));
862
windows_ASN_type = MS_ASN_UNSIGNED32;
863
DEBUGMSGTL(("winExtDLL", "MS_ASN_UNSIGNED32 = ASN_UNSIGNED\n"));
866
windows_ASN_type = MS_ASN_COUNTER64;
867
DEBUGMSGTL(("winExtDLL", "MS_ASN_COUNTER64 = ASN_COUNTER64\n"));
870
windows_ASN_type = MS_ASN_BITS;
871
DEBUGMSGTL(("winExtDLL", "MS_ASN_BITS = ASN_BIT_STR\n"));
874
windows_ASN_type = MS_ASN_OBJECTIDENTIFIER;
875
DEBUGMSGTL(("winExtDLL", "MS_ASN_OBJECTIDENTIFIER = ASN_OBJECT_ID\n"));
878
windows_ASN_type = MS_ASN_SEQUENCE;
879
DEBUGMSGTL(("winExtDLL", "MS_ASN_SEQUENCE = ASN_SEQUENCE\n"));
882
windows_ASN_type = MS_ASN_IPADDRESS;
883
DEBUGMSGTL(("winExtDLL", "MS_ASN_IPADDRESS = ASN_IPADDRESS\n"));
886
windows_ASN_type = MS_ASN_COUNTER32;
887
DEBUGMSGTL(("winExtDLL", "MS_ASN_COUNTER32 = ASN_COUNTER\n"));
889
// case ASN_GAUGE: // Same as UNSIGNED
890
// windows_ASN_type = MS_ASN_GAUGE32;
891
// DEBUGMSGTL(("winExtDLL", "MS_ASN_GAUGE32 = ASN_GAUGE\n"));
894
windows_ASN_type = MS_ASN_TIMETICKS;
895
DEBUGMSGTL(("winExtDLL", "MS_ASN_TIMETICKS = ASN_TIMETICKS\n"));
898
windows_ASN_type = MS_ASN_OPAQUE;
899
DEBUGMSGTL(("winExtDLL", "MS_ASN_OPAQUE = ASN_OPAQUE\n"));
902
windows_ASN_type = MS_ASN_INTEGER;
903
DEBUGMSGTL(("winExtDLL", "unknown MS ASN type. Defaulting to ASN_INTEGER\n"));
907
DEBUGMSGTL(("winExtDLL", "Net-SNMP object type for returned value: %d\n",windows_ASN_type));
910
pVarBindList.list = (SnmpVarBind *) SnmpUtilMemAlloc(sizeof (SnmpVarBind));
911
if (pVarBindList.list) {
912
// Convert OID from Net-SNMP to Windows
913
pVarBindList.list->name.ids = (UINT *) SnmpUtilMemAlloc(sizeof (UINT) *var->name_length);
915
if (pVarBindList.list->name.ids) {
917
for (i = 0; i < var->name_length; i++) {
918
pVarBindList.list->name.ids[i] = (UINT)var->name[i];
920
pVarBindList.list->name.idLength = i;
923
DEBUGMSGTL(("winExtDLL","Windows OID length: %d\n",pVarBindList.list->name.idLength));
924
DEBUGMSGTL(("winExtDLL","Windows OID: "));
925
DEBUGMSGWINOID(("winExtDLL", pVarBindList.list));
926
DEBUGMSG(("winExtDLL", "\n"));
929
DEBUGMSGTL(("winExtDLL", "\nyCould not allocate memory for Windows SNMP varbind.\n"));
932
//pVarBindList.list = pVarBindList.list;
933
pVarBindList.len = 1;
936
DEBUGMSGTL(("winExtDLL", "\nyCould not allocate memory for Windows SNMP varbind list.\n"));
940
// Set Windows ASN type
941
pVarBindList.list->value.asnType = windows_ASN_type;
947
strncpy(set_szbuf_temp, var->val.string, (var->val_len > SZBUF_MAX?SZBUF_MAX:var->val_len));
949
// Make sure string is terminated
950
set_szbuf_temp[var->val_len > SZBUF_MAX?SZBUF_MAX:var->val_len] = '\0';
952
DEBUGMSGTL(("winExtDLL", "String to write: %s\n",set_szbuf_temp));
953
DEBUGMSGTL(("winExtDLL", "Length of string to write: %d\n",strlen(set_szbuf_temp)));
955
pVarBindList.list->value.asnValue.string.stream = set_szbuf_temp;
956
pVarBindList.list->value.asnValue.string.length = strlen(set_szbuf_temp);
957
pVarBindList.list->value.asnValue.string.dynamic = 0;
961
case ASN_INTEGER: // And MS_ASN_INTEGER32
970
pVarBindList.list->value.asnValue.number = *(var->val.integer);
975
// Convert OID from Net-SNMP to Windows
976
temp_oid = var->val.objid;
977
temp_oid_length = var->val_len / sizeof(oid);
979
DEBUGMSGTL(("winExtDLL","Sizeof var->val.objid: %d\n", temp_oid_length));
981
DEBUGMSGTL(("winExtDLL","OID: from user "));
982
DEBUGMSGOID(("winExtDLL", temp_oid, temp_oid_length));
983
DEBUGMSG(("winExtDLL","\n"));
985
mySnmpVarBind->name.ids = (UINT *) SnmpUtilMemAlloc(sizeof (UINT) * temp_oid_length);
987
if (mySnmpVarBind->name.ids) {
989
for (i = 0; i < temp_oid_length; i++) {
990
mySnmpVarBind->name.ids[i] = (UINT)temp_oid[i];
992
mySnmpVarBind->name.idLength = i;
995
DEBUGMSGTL(("winExtDLL","Windows OID length: %d\n",mySnmpVarBind->name.idLength));
996
DEBUGMSGTL(("winExtDLL","Windows OID: "));
997
DEBUGMSGWINOID(("winExtDLL", mySnmpVarBind));
998
DEBUGMSG(("winExtDLL", "\n"));
1001
DEBUGMSGTL(("winExtDLL", "\nyCould not allocate memory for Windows SNMP varbind.\n"));
1002
return SNMP_ERR_GENERR;
1004
SnmpUtilOidCpy(&pVarBindList.list->value.asnValue.object, &mySnmpVarBind->name);
1005
//pVarBindList.list->value.asnValue.object = mySnmpVarBind->name;
1007
SnmpUtilVarBindFree(mySnmpVarBind);
1013
if (xSnmpExtensionQueryEx) {
1014
DEBUGMSGTL(("winExtDLL", "Calling xSnmpExtensionQueryEx\n"));
1015
result = xSnmpExtensionQueryEx(SNMP_PDU_SET, 1, &pVarBindList, NULL, &pErrorStatus, &pErrorIndex);
1018
DEBUGMSGTL(("winExtDLL", "Calling xSnmpExtensionQuery\n"));
1019
result = xSnmpExtensionQuery(SNMP_PDU_SET, &pVarBindList, &pErrorStatus, &pErrorIndex);
1022
DEBUGMSGTL(("winExtDLL", "win: Result of xSnmpExtensionQuery: %d\n",result));
1023
DEBUGMSGTL(("winExtDLL", "win: Error status of xSnmpExtensionQuery: %d\n",pErrorStatus));
1024
DEBUGMSGTL(("winExtDLL", "win: asnType: %d\n",pVarBindList.list->value.asnType));
1027
DEBUGMSGTL(("winExtDLL", "\nyxWindows SnmpExtensionQuery failure.\n"));
1028
return SNMP_ERR_GENERR;
1032
SnmpUtilVarBindListFree(&pVarBindList);
1035
switch (pErrorStatus) {
1036
case SNMP_ERRORSTATUS_INCONSISTENTNAME:
1037
return SNMP_ERR_GENERR;
1039
return pErrorStatus;
713
mode_name = "SET_ACTION";
714
return SNMP_ERR_NOERROR;
1046
715
case MODE_SET_UNDO:
716
mode_name = "SET_UNDO";
717
nRequestType = SNMP_EXTENSION_SET_UNDO;
1047
719
case MODE_SET_COMMIT:
720
mode_name = "SET_COMMIT";
721
nRequestType = SNMP_EXTENSION_SET_COMMIT;
1048
723
case MODE_SET_FREE:
724
mode_name = "SET_FREE";
725
nRequestType = SNMP_EXTENSION_SET_CLEANUP;
1053
snmp_log(LOG_WARNING, "unsupported mode for winExtDLL called (%d)\n",
728
DEBUGMSG(("winExtDLL",
729
"internal error: invalid mode %d.\n", reqinfo->mode));
1055
731
return SNMP_ERR_NOERROR;
1058
return SNMP_ERR_NOERROR;
1061
void winExtDLL_free_config_winExtDLL(void) {
1064
void read_ExtensionAgents_list() {
1066
unsigned char * key_value = NULL;
1067
DWORD key_value_size = 0;
1068
DWORD key_value_type = 0;
1069
DWORD valueSize = MAX_VALUE_NAME;
1071
TCHAR valueName[MAX_VALUE_NAME];
1072
TCHAR valueName2[MAX_VALUE_NAME];
1075
DEBUGMSGTL(("winExtDLL", "read_ExtensionAgents_list called\n"));
1077
/* The Windows SNMP service stores the list of extension agents to be loaded in the
1078
* registry under HKLM\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\ExtensionAgents.
1079
* This list contains a list of other keys that contain the actual file path to the DLL.
1082
/* Open SYSTEM\\CurrentControlSet\\Services\\SNMP\\Parameters\\ExtensionAgent */
1083
retCode = RegOpenKeyExA(
1085
"SYSTEM\\CurrentControlSet\\Services\\SNMP\\Parameters\\ExtensionAgents",
1090
if (retCode == ERROR_SUCCESS) {
1091
/* Enumerate list of extension agents. This is a list of other keys that contain the
1092
* actual filename of the extension agent. */
1093
for (i=0; retCode==ERROR_SUCCESS; i++)
1095
valueSize = MAX_VALUE_NAME;
1096
valueName[0] = '\0';
1097
retCode = RegEnumValue(
1107
if (retCode == ERROR_SUCCESS )
1109
/* Get key name that contains the actual filename of the extension agent */
1110
DEBUGMSGTL(("winExtDLL", "-----------------------------------------\n"));
1111
DEBUGMSGTL(("winExtDLL", "Registry: (%d) %s\n", i+1, valueName));
1113
key_value_size = MAX_VALUE_NAME;
1114
if (RegQueryValueExA(
1120
&key_value_size) == ERROR_SUCCESS) {
1122
DEBUGMSGTL(("winExtDLL", "key_value: %s\n",valueName2));
1123
read_ExtensionAgents_list2(valueName2);
734
rc = SNMP_ERR_NOERROR;
736
for (request = requests; request; request = request->next) {
737
netsnmp_variable_list *varbind;
738
SnmpVarBindList win_varbinds;
739
AsnInteger32 ErrorStatus;
740
AsnInteger32 ErrorIndex;
744
memset(&win_varbinds, 0, sizeof(win_varbinds));
746
if (request->processed || rc != SNMP_ERR_NOERROR)
747
goto free_win_varbinds;
749
if (reqinfo->mode == MODE_SET_RESERVE1)
750
alloc_context_info(request->index);
752
varbind = request->requestvb;
756
* Convert the Net-SNMP varbind to a Windows SNMP varbind list.
758
rc = convert_to_windows_varbind_list(&win_varbinds, varbind);
759
if (rc != SNMP_ERR_NOERROR) {
760
DEBUGMSG(("winExtDLL",
761
"converting varbind list to Windows format failed with"
762
" error code %d.\n", request->status));
763
netsnmp_request_set_error(requests, rc);
764
goto free_win_varbinds;
767
assert(win_varbinds.len == 1);
770
* For a GetNext PDU, if the varbind OID comes lexicographically
771
* before the root OID of this handler, replace it by the root OID.
773
if (reqinfo->mode == MODE_GETNEXT
774
&& snmp_oid_compare(win_varbinds.list[0].name.ids,
775
win_varbinds.list[0].name.idLength,
777
reginfo->rootoid_len) < 0) {
778
AsnObjectIdentifier Root =
779
{ reginfo->rootoid_len, reginfo->rootoid };
780
SnmpUtilOidCpy(&win_varbinds.list[0].name, &Root);
783
if (ext_dll_info->pfSnmpExtensionQueryEx) {
784
result = ext_dll_info->pfSnmpExtensionQueryEx(nRequestType,
787
get_context_info(request->index),
790
} else if (ext_dll_info->pfSnmpExtensionQuery) {
792
ext_dll_info->pfSnmpExtensionQuery((BYTE) nRequestType,
798
"error in extension DLL %s: SNMP query function missing.\n",
799
ext_dll_info->dll_name);
805
"extension DLL %s: SNMP query function failed.\n",
806
ext_dll_info->dll_name);
807
rc = SNMP_ERR_GENERR;
808
goto free_win_varbinds;
811
rc = convert_win_snmp_err(ErrorStatus);
812
if (rc != SNMP_ERR_NOERROR) {
813
DEBUGMSG(("winExtDLL",
814
"extension DLL %s: SNMP query function returned error code %lu (Windows) / %d (Net-SNMP).\n",
815
ext_dll_info->dll_name, ErrorStatus, rc));
816
assert(ErrorIndex == 1);
817
netsnmp_request_set_error(requests, rc);
818
if (rc == SNMP_NOSUCHOBJECT || rc == SNMP_NOSUCHINSTANCE
819
|| rc == SNMP_ERR_NOSUCHNAME)
820
rc = SNMP_ERR_NOERROR;
821
goto free_win_varbinds;
825
if (reqinfo->mode == MODE_GET)
827
else if (reqinfo->mode == MODE_GETNEXT) {
828
const SnmpVarBind *win_varbind;
830
win_varbind = &win_varbinds.list[0];
833
* Verify whether the OID returned by the extension DLL fits
834
* inside the OID range this handler has been registered
835
* with. Also compare the OID passed to the extension DLL with
836
* the OID returned by the same DLL. If the DLL returned a
837
* lexicographically earlier OID, this means that there is no
838
* next OID in the MIB implemented by the DLL.
840
* Note: for some GetNext requests BoundsChecker will report
841
* that the code below accesses a dangling pointer. This is
842
* a limitation of BoundsChecker: apparently BoundsChecker is
843
* not able to cope with reallocation of memory for
844
* win_varbind by an SNMP extension DLL that has not been
845
* instrumented by BoundsChecker.
847
if (netsnmp_oid_is_subtree(ext_dll_view_info->name,
848
ext_dll_view_info->name_length,
849
win_varbind->name.ids,
850
win_varbind->name.idLength) == 0
851
&& snmp_oid_compare(varbind->name, varbind->name_length,
852
win_varbind->name.ids,
853
win_varbind->name.idLength) < 0) {
855
* Copy the OID returned by the extension DLL to the
858
snmp_set_var_objid(varbind,
859
win_varbind->name.ids,
860
win_varbind->name.idLength);
865
netsnmp_variable_list *result_vb;
868
* Copy the value returned by the extension DLL to the Net-SNMP
872
rc = append_windows_varbind(&result_vb, &win_varbinds.list[0]);
873
assert(result_vb || rc != SNMP_ERR_NOERROR);
875
snmp_set_var_typed_value(varbind,
877
result_vb->val.string,
879
snmp_free_varbind(result_vb);
881
netsnmp_request_set_error(requests, rc);
882
goto free_win_varbinds;
887
if (reqinfo->mode == MODE_SET_COMMIT
888
|| reqinfo->mode == MODE_SET_UNDO
889
|| reqinfo->mode == MODE_SET_FREE)
890
free_context_info(request->index);
891
if (win_varbinds.list)
892
SnmpUtilVarBindListFree(&win_varbinds);
1132
void read_ExtensionAgents_list2(const TCHAR *keyName) {
1134
unsigned char * key_value = NULL;
1135
DWORD key_value_size = 0;
1136
DWORD key_value_type = 0;
1137
DWORD valueSize = MAX_VALUE_NAME;
1138
TCHAR valueName[MAX_VALUE_NAME];
1139
TCHAR valueNameExpanded[MAX_VALUE_NAME];
1143
DEBUGMSGTL(("winExtDLL", "read_ExtensionAgents_list2 called\n"));
1144
DEBUGMSGTL(("winExtDLL", "Registry: Opening key %s\n", keyName));
1146
/* Open extension agent's key */
1147
retCode = RegOpenKeyExA(
1154
if (retCode == ERROR_SUCCESS) {
1155
/* Read Pathname value */
1157
DEBUGMSGTL(("winExtDLL", "Registry: Reading value for %s\n", keyName));
1159
key_value_size = MAX_VALUE_NAME;
1160
retCode = RegQueryValueExA(
899
* Iterate over the SNMP extension DLL information in the registry and store
900
* the retrieved information in s_winextdll[].
902
* At the time an SNMP extension DLL is installed, some information about the
903
* DLL is written to the registry at one of the two following locations:
904
* HKLM\SYSTEM\CurrentControlSet\Control\SNMP\Parameters\ExtensionAgents for
905
* Windows Vista, Windows 7 and Windows 2008 or
906
* HKLM\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\ExtensionAgents for
907
* earlier Windows versions. Under this key zero or more REG_SZ values are
908
* stored with the names of registry keys containing the DLL path.
911
read_extension_dlls_from_registry()
913
DEBUGMSGTL(("winExtDLL",
914
"read_extension_dlls_from_registry called\n"));
916
read_extension_dlls_from_registry_at
917
("SYSTEM\\CurrentControlSet\\Services\\SNMP\\Parameters\\ExtensionAgents");
918
read_extension_dlls_from_registry_at
919
("SYSTEM\\CurrentControlSet\\Control\\SNMP\\Parameters\\ExtensionAgents");
923
read_extension_dlls_from_registry_at(const char *const subkey)
929
TCHAR valueName[MAX_VALUE_NAME];
931
TCHAR data[MAX_VALUE_NAME];
934
retCode = RegOpenKeyExA(HKEY_LOCAL_MACHINE, subkey,
935
0, KEY_QUERY_VALUE, &hKey);
1168
937
if (retCode == ERROR_SUCCESS) {
1169
valueName[key_value_size-1] = NULL; /* Make sure last element is a NULL */
1170
DEBUGMSGTL(("winExtDLL", "Extension agent Pathname size: %d\n",key_value_size));
1171
DEBUGMSGTL(("winExtDLL", "Extension agent Pathname: %s\n",valueName));
1173
if (ExpandEnvironmentStrings(valueName, valueNameExpanded, MAX_VALUE_NAME)) {
1174
DEBUGMSGTL(("winExtDLL", "Extension agent Pathname expanded: %s\n",valueNameExpanded));
1175
if (extDLLs_index < MAX_WINEXT_DLLS) {
1177
extDLLs[extDLLs_index] = strdup(valueNameExpanded);
1179
if (extDLLs[extDLLs_index]) {
1180
strcpy(extDLLs[extDLLs_index], valueNameExpanded );
1181
DEBUGMSGTL(("winExtDLL", "Extension agent Pathname expanded extDLLs: %s\n",extDLLs[extDLLs_index]));
1182
DEBUGMSGTL(("winExtDLL", "Extension agent Pathname size: %d\n",strlen(extDLLs[extDLLs_index])));
1185
DEBUGMSGTL(("winExtDLL", "Could not allocate memory for extDLLs[%d]\n",extDLLs_index));
1190
DEBUGMSGTL(("winExtDLL", "ExpandEnvironmentStrings failed\n"));
1196
// Called by alarm to check for traps waiting to be processed.
1197
void subagentTrapCheck() {
1201
netsnmp_variable_list *notification_vars = NULL;
1204
AsnObjectIdentifier pEnterprise;
1205
AsnInteger pGenericTrap;
1206
AsnInteger pSpecificTrap;
1207
AsnTimeticks pTimeStamp;
1208
SnmpVarBindList pVariableBindings;
1210
DEBUGMSGTL(("winExtDLL", "subagentTrapMonitor called\n"));
1212
dwWaitResult = WaitForMultipleObjects(
1213
subagentTrapEvents_index,
1218
if (! (dwWaitResult) || (dwWaitResult == WAIT_TIMEOUT))
1221
DEBUGMSGTL(("winExtDLL", "---------------------------------------------\n"));
1222
DEBUGMSGTL(("winExtDLL", "subagentTrapCheck found a trap event (index: %d)\n",dwWaitResult));
1224
/* Loop through all the winExtensionAgent's looking for a matching handler */
1225
for (i=0; winExtensionAgent[i].xSnmpExtensionInit && i < MAX_WINEXT_DLLS; i++) {
1226
DEBUGMSGTL(("winExtDLL", "Looping through all the winExtensionAgent's looking for a matching trap handler.\n"));
1228
if (winExtensionAgent[i].subagentTrapEvent == subagentTrapEvents[dwWaitResult]) {
1229
DEBUGMSGTL(("winExtDLL", "Found match: "));
1230
DEBUGMSGOID(("winExtDLL", winExtensionAgent[i].name, winExtensionAgent[i].name_length));
1231
DEBUGMSG(("winExtDLL", "\n"));
1233
if (winExtensionAgent[i].xSnmpExtensionTrap)
1234
DEBUGMSGTL(("winExtDLL", "xSnmpExtensionTrap exists for this subagent\n"));
1236
DEBUGMSGTL(("winExtDLL", "xSnmpExtensionTrap does NOT exist for this subagent\n"));
1240
pEnterprise.ids = NULL;
1241
pEnterprise.idLength = 0;
1242
pGenericTrap = pSpecificTrap = NULL;
1244
pVariableBindings.list = NULL;
1245
pVariableBindings.len = 0;
1247
DEBUGMSGTL(("winExtDLL", "Calling SnmpExtensionTrap\n"));
1248
bResult = winExtensionAgent[i].xSnmpExtensionTrap(
1253
&pVariableBindings);
1255
DEBUGMSGTL(("winExtDLL", "result of SnmpExtensionTrap call: %d\n",bResult));
1258
DEBUGMSGTL(("winExtDLL", "GenericTrap: %d\n",pGenericTrap));
1259
DEBUGMSGTL(("winExtDLL", "SpecificTrap: %d\n",pSpecificTrap));
1261
if (pEnterprise.idLength)
1262
DEBUGMSGTL(("winExtDLL", "pEnterprise is not 0\n"));
1264
DEBUGMSGTL(("winExtDLL", "pEnterprise is 0\n"));
1266
// Assume that if enterprise length is >0, it's a real trap and not a cleanup call
1267
// FIXME: Not sure if this is correct. Need to test with agent that sends a non-enterprise trap
1268
if (pEnterprise.idLength) {
1276
&pVariableBindings);
1279
// Look for more traps from this agent (if result is TRUE there are more traps)
1281
DEBUGMSGTL(("winExtDLL", "More traps to process. Calling SnmpExtensionTrap again\n"));
1283
pEnterprise.ids = NULL;
1284
pEnterprise.idLength = 0;
1285
pGenericTrap = pSpecificTrap = NULL;
1287
pVariableBindings.list = NULL;
1288
pVariableBindings.len = 0;
1290
bResult = winExtensionAgent[i].xSnmpExtensionTrap(
1295
&pVariableBindings);
1297
DEBUGMSGTL(("winExtDLL", "result of SnmpExtensionTrap call: %d\n",bResult));
1299
// Assume that if enterprise length is >0, it's a real trap and not a cleanup call
1300
// FIXME: Not sure if this is correct. Need to test with agent that sends a non-enterprise trap
1301
if (pEnterprise.idLength) {
1303
DEBUGMSGTL(("winExtDLL", "GenericTrap: %d\n",pGenericTrap));
1304
DEBUGMSGTL(("winExtDLL", "SpecificTrap: %d\n",pSpecificTrap));
1306
if (pEnterprise.idLength)
1307
DEBUGMSGTL(("winExtDLL", "pEnterprise is not 0\n"));
1309
DEBUGMSGTL(("winExtDLL", "pEnterprise is 0\n"));
1317
&pVariableBindings);
1319
SnmpUtilVarBindListFree(&pVariableBindings);
1325
// Events should be auto-reset, but just in case..
1326
ResetEvent(dwWaitResult);
1333
AsnObjectIdentifier *pEnterprise,
1334
AsnInteger *pGenericTrap,
1335
AsnInteger *pSpecificTrap,
1336
AsnTimeticks *pTimeStamp,
1337
SnmpVarBindList *pVariableBindings) {
1340
SnmpVarBind mySnmpVarBind;
1341
oid my_oid[MAX_OID_LEN]; // Holder for pVariableBindings OIDs
1342
size_t my_oid_length = 0; // Holder for pVariableBindings OIDs
1344
oid enterprise_oid[MAX_OID_LEN]; // Holder for enterprise OID
1345
size_t enterprise_oid_length = 0; // Holder for enterprise OID
1347
oid ret_oid[MAX_OID_LEN]; // Holder for return OIDs
1348
size_t ret_oid_length = 0; // Holder for return OIDs
1353
* here is where we store the variables to be sent in the trap
1355
netsnmp_variable_list *notification_vars = NULL;
1358
* In the notification, we have to assign our notification OID to
1359
* the snmpTrapOID.0 object. Here is it's definition.
1361
oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
1362
size_t objid_snmptrap_len = OID_LENGTH(objid_snmptrap);
1364
DEBUGMSGTL(("winExtDLL", "send_trap() called\n"));
1365
DEBUGMSGTL(("winExtDLL", "pVariableBindings length: %d\n",pVariableBindings->len));
1367
if (*pGenericTrap != 6) {
1368
DEBUGMSGTL(("winExtDLL", "Working on generic trap\n"));
1369
DEBUGMSGTL(("winExtDLL", "sending v1 trap\n"));
1370
send_easy_trap(*pGenericTrap, *pSpecificTrap);
1374
// Convert enterprise OID from Windows to Net-SNMP so Net-SNMP
1375
for (j = 0; j < (pEnterprise->idLength > MAX_OID_LEN?MAX_OID_LEN:pEnterprise->idLength); j++) {
1376
enterprise_oid[j] = (oid)pEnterprise->ids[j];
1378
enterprise_oid_length = j;
1380
DEBUGMSGTL(("winExtDLL", "Enterprise OID: "));
1381
DEBUGMSGOID(("winExtDLL", enterprise_oid, enterprise_oid_length));
1382
DEBUGMSG(("winExtDLL", "\n"));
1384
// We need to copy .0.specific trap to copy of enterprise and use that for objid_snmptrap!!
1386
for (i = 0; i < enterprise_oid_length; i++) {
1387
my_oid[i] = enterprise_oid[i];
1391
my_oid[my_oid_length] = 0;
1394
my_oid[my_oid_length] = *pSpecificTrap;
1397
DEBUGMSGTL(("winExtDLL", "Trap OID (snmpTrapOID.0): "));
1398
DEBUGMSGOID(("winExtDLL", my_oid, my_oid_length));
1399
DEBUGMSG(("winExtDLL", "\n"));
1402
* add in the trap definition object
1404
snmp_varlist_add_variable(¬ification_vars,
1406
* the snmpTrapOID.0 variable
1408
objid_snmptrap, objid_snmptrap_len,
1410
* value type is an OID
1414
* value contents is our notification OID
1420
my_oid_length * sizeof(oid));
1422
for (i = 0; i< pVariableBindings->len; i++) {
1424
mySnmpVarBind = pVariableBindings->list[i];
1426
// Convert OID from Windows to Net-SNMP so Net-SNMP
1427
for (j = 0; j < (mySnmpVarBind.name.idLength > MAX_OID_LEN?MAX_OID_LEN:mySnmpVarBind.name.idLength); j++) {
1428
my_oid[j] = (oid)mySnmpVarBind.name.ids[j];
1432
DEBUGMSGTL(("winExtDLL", "OID in trap variable binding: "));
1433
DEBUGMSGOID(("winExtDLL", my_oid, my_oid_length));
1434
DEBUGMSG(("winExtDLL", "\n"));
1436
// Set Net-SNMP ASN type based on closest match to Windows ASN type
1437
switch (mySnmpVarBind.value.asnType) {
1438
case MS_ASN_OCTETSTRING: // AsnOctetString
1439
stringtemp = netsnmp_strdup_and_null(mySnmpVarBind.value.asnValue.string.stream, mySnmpVarBind.value.asnValue.string.length);
1440
DEBUGMSGTL(("winExtDLL", "MS_ASN_OCTETSTRING = ASN_OCTET_STR\n"));
1441
DEBUGMSGTL(("winExtDLL", "MS_ASN_OCTETSTRING = %s\n",stringtemp));
1442
snmp_varlist_add_variable(¬ification_vars,
1443
my_oid, my_oid_length,
1446
strlen(stringtemp));
1448
case MS_ASN_INTEGER: // And MS_ASN_INTEGER32
1449
DEBUGMSGTL(("winExtDLL", "MS_ASN_INTEGER = ASN_INTEGER\n"));
1450
DEBUGMSGTL(("winExtDLL", "MS_ASN_INTEGER = %d\n",mySnmpVarBind.value.asnValue.number));
1451
snmp_varlist_add_variable(¬ification_vars,
1452
my_oid, my_oid_length,
1454
(u_char *)&mySnmpVarBind.value.asnValue.number,
1455
sizeof(mySnmpVarBind.value.asnValue.number));
1457
case MS_ASN_UNSIGNED32: // SNMP v2
1458
DEBUGMSGTL(("winExtDLL", "MS_ASN_UNSIGNED32 = ASN_UNSIGNED\n"));
1459
DEBUGMSGTL(("winExtDLL", "MS_ASN_UNSIGNED32 = %d\n",mySnmpVarBind.value.asnValue.unsigned32));
1460
snmp_varlist_add_variable(¬ification_vars,
1461
my_oid, my_oid_length,
1463
(u_char *)&mySnmpVarBind.value.asnValue.unsigned32,
1464
sizeof(mySnmpVarBind.value.asnValue.unsigned32));
1466
case MS_ASN_COUNTER64: // SNMP v2
1467
DEBUGMSGTL(("winExtDLL", "MS_ASN_COUNTER64 = ASN_COUNTER64\n"));
1468
DEBUGMSGTL(("winExtDLL", "MS_ASN_COUNTER64 = %d\n",mySnmpVarBind.value.asnValue.counter64));
1469
snmp_varlist_add_variable(¬ification_vars,
1470
my_oid, my_oid_length,
1472
(u_char *)&mySnmpVarBind.value.asnValue.counter64,
1473
sizeof(mySnmpVarBind.value.asnValue.counter64));
1475
case MS_ASN_BITS: // AsnOctetString
1476
stringtemp = netsnmp_strdup_and_null(mySnmpVarBind.value.asnValue.bits.stream, mySnmpVarBind.value.asnValue.bits.length);
1477
DEBUGMSGTL(("winExtDLL", "MS_ASN_BITS = ASN_BIT_STR\n"));
1478
DEBUGMSGTL(("winExtDLL", "MS_ASN_BITS = %s\n",stringtemp));
1479
snmp_varlist_add_variable(¬ification_vars,
1480
my_oid, my_oid_length,
1483
strlen(stringtemp));
1485
case MS_ASN_OBJECTIDENTIFIER: // AsnObjectIdentifier
1486
DEBUGMSGTL(("winExtDLL", "MS_ASN_OBJECTIDENTIFIER = ASN_OBJECT_ID\n"));
1487
// Convert OID to Net-SNMP
1489
DEBUGMSGTL(("winExtDLL", "Returned OID: "));
1490
DEBUGMSGWINOID(("winExtDLL", &mySnmpVarBind.value.asnValue.object));
1491
DEBUGMSG(("winExtDLL", "\n"));
1493
// Convert OID from Windows to Net-SNMP
1494
for (i = 0; i < (mySnmpVarBind.value.asnValue.object.idLength > MAX_OID_LEN?MAX_OID_LEN:
1495
mySnmpVarBind.value.asnValue.object.idLength); i++) {
1496
ret_oid[i] = (oid)mySnmpVarBind.value.asnValue.object.ids[i];
1500
DEBUGMSGTL(("winExtDLL", "Windows OID converted to Net-SNMP: "));
1501
DEBUGMSGOID(("winExtDLL", ret_oid, ret_oid_length));
1502
DEBUGMSG(("winExtDLL", "\n"));
1504
snmp_varlist_add_variable(¬ification_vars,
1505
my_oid, my_oid_length,
1508
ret_oid_length * sizeof(oid));
1510
case MS_ASN_SEQUENCE: // AsnOctetString
1511
stringtemp = netsnmp_strdup_and_null(mySnmpVarBind.value.asnValue.sequence.stream, mySnmpVarBind.value.asnValue.sequence.length);
1512
DEBUGMSGTL(("winExtDLL", "MS_ASN_SEQUENCE = ASN_SEQUENCE\n"));
1513
snmp_varlist_add_variable(¬ification_vars,
1514
my_oid, my_oid_length,
1517
strlen(stringtemp));
1519
case MS_ASN_IPADDRESS: // AsnOctetString
1520
stringtemp = netsnmp_strdup_and_null(mySnmpVarBind.value.asnValue.address.stream, mySnmpVarBind.value.asnValue.address.length);
1521
DEBUGMSGTL(("winExtDLL", "MS_ASN_IPADDRESS = ASN_IPADDRESS\n"));
1522
snmp_varlist_add_variable(¬ification_vars,
1523
my_oid, my_oid_length,
1526
strlen(stringtemp));
1528
case MS_ASN_COUNTER32:
1529
DEBUGMSGTL(("winExtDLL", "MS_ASN_COUNTER32 = ASN_COUNTER\n"));
1530
DEBUGMSGTL(("winExtDLL", "MS_ASN_COUNTER32 = %d\n",mySnmpVarBind.value.asnValue.counter));
1531
snmp_varlist_add_variable(¬ification_vars,
1532
my_oid, my_oid_length,
1534
(u_char *)&mySnmpVarBind.value.asnValue.counter,
1535
sizeof(mySnmpVarBind.value.asnValue.counter));
1537
case MS_ASN_GAUGE32:
1538
DEBUGMSGTL(("winExtDLL", "MS_ASN_GAUGE32 = ASN_GAUGE\n"));
1539
DEBUGMSGTL(("winExtDLL", "MS_ASN_GAUGE32 = %d\n",mySnmpVarBind.value.asnValue.gauge));
1540
snmp_varlist_add_variable(¬ification_vars,
1541
my_oid, my_oid_length,
1543
(u_char *)&mySnmpVarBind.value.asnValue.gauge,
1544
sizeof(mySnmpVarBind.value.asnValue.gauge));
1546
case MS_ASN_TIMETICKS:
1547
DEBUGMSGTL(("winExtDLL", "MS_ASN_TIMETICKS = ASN_TIMETICKS\n"));
1548
DEBUGMSGTL(("winExtDLL", "MS_ASN_TIMETICKS = %d\n",mySnmpVarBind.value.asnValue.ticks));
1549
snmp_varlist_add_variable(¬ification_vars,
1550
my_oid, my_oid_length,
1552
(u_char *)&mySnmpVarBind.value.asnValue.ticks,
1553
sizeof(mySnmpVarBind.value.asnValue.ticks));
1555
case MS_ASN_OPAQUE: // AsnOctetString
1556
stringtemp = netsnmp_strdup_and_null(mySnmpVarBind.value.asnValue.arbitrary.stream, mySnmpVarBind.value.asnValue.arbitrary.length);
1557
DEBUGMSGTL(("winExtDLL", "MS_ASN_OPAQUE = ASN_OPAQUE\n"));
1558
snmp_varlist_add_variable(¬ification_vars,
1559
my_oid, my_oid_length,
1562
strlen(stringtemp)); break;
1564
DEBUGMSGTL(("winExtDLL", "Defaulting to ASN_INTEGER\n"));
1569
* send the trap out. This will send it to all registered
1570
* receivers (see the "SETTING UP TRAP AND/OR INFORM DESTINATIONS"
1571
* section of the snmpd.conf manual page.
1574
DEBUGMSGTL(("winExtDLL", "sending v2 trap\n"));
1575
send_v2trap(notification_vars);
1578
* free the created notification variable list
1580
DEBUGMSGTL(("winExtDLL", "cleaning up\n"));
1581
snmp_free_varbind(notification_vars);
1584
/* DEBUGMSGWINOID */
1586
debugmsg_win_oid(const char *token, const AsnObjectIdentifier * theoid)
1590
size_t buf_len = 0, out_len = 0;
939
valueSize = sizeof(valueName);
940
dataSize = sizeof(data);
941
retCode = RegEnumValue(hKey, i, valueName, &valueSize, NULL,
942
&dataType, (BYTE *) data, &dataSize);
944
if (retCode != ERROR_SUCCESS)
946
if (dataType == REG_SZ) {
947
winextdll ext_dll_info;
949
memset(&ext_dll_info, 0, sizeof(ext_dll_info));
950
ext_dll_info.dll_name =
951
read_extension_dll_path_from_registry(data);
952
if (ext_dll_info.dll_name) {
953
xarray_push_back(&s_winextdll, &ext_dll_info);
954
DEBUGMSG(("winExtDLL", "registry key %s: DLL %s.\n",
955
data, ext_dll_info.dll_name));
963
/** Store the DLL path in dynamically allocated memory. */
965
read_extension_dll_path_from_registry(const TCHAR * keyName)
968
DWORD key_value_type = 0;
969
TCHAR valueName[MAX_VALUE_NAME];
970
DWORD key_value_size = MAX_VALUE_NAME;
971
TCHAR valueNameExpanded[MAX_VALUE_NAME];
975
retCode = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
976
keyName, 0, KEY_QUERY_VALUE, &hKey);
978
if (retCode != ERROR_SUCCESS)
981
retCode = RegQueryValueExA(hKey,
985
(BYTE *) valueName, &key_value_size);
987
if (retCode != ERROR_SUCCESS) {
992
if (key_value_type == REG_EXPAND_SZ) {
993
if (ExpandEnvironmentStrings
994
(valueName, valueNameExpanded, MAX_VALUE_NAME))
995
result = strdup(valueNameExpanded);
996
} else if (key_value_type == REG_SZ)
997
result = strdup(valueName);
1004
* Callback function called by the Net-SNMP agent to check for traps waiting
1008
subagentTrapCheck(unsigned int clientreg, void *clientarg)
1015
const winextdll *ext_dll_info;
1017
dwWaitResult = WaitForMultipleObjects(s_trapevent.size,
1018
&TRAPEVENT(0), FALSE, 0);
1020
i = dwWaitResult - WAIT_OBJECT_0;
1021
if (i < 0 || i >= s_trapevent.size) {
1022
assert(dwWaitResult == WAIT_TIMEOUT);
1026
assert(s_trapevent.size == s_trapevent_to_dllinfo.size);
1027
ext_dll_info = TRAPEVENT_TO_DLLINFO(i);
1028
assert(ext_dll_info->subagentTrapEvent == TRAPEVENT(i));
1031
* Reset the signalled event just in case the extension DLL erroneously
1032
* allocated a manual-reset event instead of an auto-reset event. It is
1033
* important to reset the event BEFORE traps are processed, otherwise a
1034
* race condition is triggered between the extension DLL setting the
1035
* event and this code resetting the event.
1037
ResetEvent(TRAPEVENT(i));
1039
if (!ext_dll_info->pfSnmpExtensionTrap) {
1041
"internal error in SNMP extension DLL %s: a trap is ready"
1042
" but the function SnmpExtensionTrap() is missing.\n",
1043
ext_dll_info->dll_name);
1048
* Process at most hundred traps per extension DLL. If the extension DLL
1049
* has more traps waiting, that's probably a bug in the extension DLL.
1051
for (j = 0; j < 100; j++) {
1052
AsnObjectIdentifier Enterprise = { 0, NULL };
1053
AsnInteger GenericTrap = 0;
1054
AsnInteger SpecificTrap = 0;
1055
AsnTimeticks TimeStamp = 0;
1056
SnmpVarBindList TrapVarbinds = { NULL, 0 };
1058
bResult = ext_dll_info->pfSnmpExtensionTrap(&Enterprise,
1067
send_trap(&Enterprise, GenericTrap, SpecificTrap, TimeStamp,
1070
SnmpUtilVarBindListFree(&TrapVarbinds);
1076
send_trap(const AsnObjectIdentifier * const pEnterprise,
1077
const AsnInteger GenericTrap,
1078
const AsnInteger SpecificTrap,
1079
const AsnTimeticks TimeStamp,
1080
const SnmpVarBindList * const pTrapVarbinds)
1083
* A quote from the paragraph in RFC 1908 about SNMPv1 to SNMPv2c
1084
* trap translation (http://www.ietf.org/rfc/rfc1908.txt):
1086
* If a Trap-PDU is received, then it is mapped into a SNMPv2-Trap-
1087
* PDU. This is done by prepending onto the variable-bindings field
1088
* two new bindings: sysUpTime.0 [6], which takes its value from the
1089
* timestamp field of the Trap-PDU; and, snmpTrapOID.0 [6], which is
1090
* calculated thusly: if the value of generic-trap field is
1091
* `enterpriseSpecific', then the value used is the concatenation of
1092
* the enterprise field from the Trap-PDU with two additional sub-
1093
* identifiers, `0', and the value of the specific-trap field;
1094
* otherwise, the value of the corresponding trap defined in [6] is
1098
* Reference [6] refers to RFC 1907 (http://www.ietf.org/rfc/rfc1907.txt),
1099
* where the generic trap OIDs have been defined as follows:
1100
* coldStart ::= { snmpTraps 1 }
1101
* warmStart ::= { snmpTraps 2 }
1102
* linkDown ::= { snmpTraps 3 }
1103
* linkUp ::= { snmpTraps 4 }
1104
* authenticationFailure ::= { snmpTraps 5 }
1105
* egpNeighborLoss ::= { snmpTraps 6 }
1107
static const oid sysuptime_oid[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
1108
static const size_t sysuptime_oid_len = OID_LENGTH(sysuptime_oid);
1110
static const oid snmptrap_oid[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
1111
static const size_t snmptrap_oid_len = OID_LENGTH(snmptrap_oid);
1113
static const oid snmptraps_oid[] = { 1, 3, 6, 1, 6, 3, 1, 1, 5 };
1114
static const size_t snmptraps_oid_len = OID_LENGTH(snmptraps_oid);
1116
oid vb2_oid[MAX_OID_LEN];
1119
netsnmp_variable_list *notification_vars = NULL;
1123
* Append the varbind (sysUpTime.0, TimeStamp).
1125
snmp_varlist_add_variable(¬ification_vars,
1126
sysuptime_oid, sysuptime_oid_len,
1128
(const u_char *) &TimeStamp,
1131
if (GenericTrap == SNMP_GENERICTRAP_ENTERSPECIFIC) {
1133
* Enterprise specific trap: compute the OID
1134
* *pEnterprise + ".0." + SpecificTrap.
1136
copy_oid(vb2_oid, &vb2_oid_len,
1137
pEnterprise->ids, pEnterprise->idLength);
1138
vb2_oid[vb2_oid_len++] = 0;
1139
vb2_oid[vb2_oid_len++] = SpecificTrap;
1142
* Generic trap: compute the OID snmpTraps + "." + GenericTrap.
1143
* Since the GenericTrap values are those defined in SNMPv1, since
1144
* these values start at zero, and since the corresponding values in
1145
* SNMPv2 start at one, translate the GenericTrap value accordingly.
1146
* See also http://www.ietf.org/rfc/rfc1214.txt and
1147
* http://www.ietf.org/rfc/rfc3418.txt.
1149
copy_oid(vb2_oid, &vb2_oid_len, snmptraps_oid, snmptraps_oid_len);
1150
vb2_oid[vb2_oid_len++] = GenericTrap + 1;
1154
* Append the varbind (snmpTrap, vb2_oid).
1156
snmp_varlist_add_variable(¬ification_vars,
1157
snmptrap_oid, snmptrap_oid_len,
1160
vb2_oid_len * sizeof(vb2_oid[0]));
1163
* Append all the varbinds in pTrapVarbinds.
1165
append_windows_varbind_list(¬ification_vars, pTrapVarbinds);
1170
send_v2trap(notification_vars);
1173
* Free the memory allocated for notification_vars.
1175
snmp_free_varbind(notification_vars);
1179
* Convert a Windows varbind to a Net-SNMP varbind and add it to the list of
1180
* varbinds 'net_snmp_varbinds'.
1182
* @note The memory allocated inside this function must be freed by the caller
1183
* as follows: snmp_free_varbind(*net_snmp_varbinds).
1186
append_windows_varbind_list(netsnmp_variable_list **
1187
const net_snmp_varbinds,
1188
const SnmpVarBindList * const win_varbinds)
1190
int i, status = SNMP_ERR_NOERROR;
1192
for (i = 0; i < win_varbinds->len; i++) {
1194
append_windows_varbind(net_snmp_varbinds,
1195
&win_varbinds->list[i]);
1196
if (status != SNMP_ERR_NOERROR)
1203
append_windows_varbind(netsnmp_variable_list ** const net_snmp_varbinds,
1204
const SnmpVarBind * const win_varbind)
1206
switch (win_varbind->value.asnType) {
1207
case MS_ASN_INTEGER:
1208
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1209
win_varbind->name.idLength,
1211
(const u_char *) &win_varbind->value.
1213
sizeof(win_varbind->value.asnValue.
1217
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1218
win_varbind->name.idLength,
1220
win_varbind->value.asnValue.bits.stream,
1221
win_varbind->value.asnValue.bits.length);
1223
case MS_ASN_OCTETSTRING:
1224
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1225
win_varbind->name.idLength,
1227
win_varbind->value.asnValue.string.
1229
win_varbind->value.asnValue.string.
1233
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1234
win_varbind->name.idLength,
1237
case MS_ASN_OBJECTIDENTIFIER:
1238
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1239
win_varbind->name.idLength,
1241
(u_char *) win_varbind->value.asnValue.
1243
win_varbind->value.asnValue.object.
1244
idLength * sizeof(oid));
1248
* MS_ASN_INTEGER32: synonym for MS_ASN_INTEGER.
1251
case MS_ASN_SEQUENCE:
1252
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1253
win_varbind->name.idLength,
1255
win_varbind->value.asnValue.sequence.
1257
win_varbind->value.asnValue.sequence.
1260
case MS_ASN_IPADDRESS:
1261
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1262
win_varbind->name.idLength,
1264
win_varbind->value.asnValue.address.
1266
win_varbind->value.asnValue.address.
1269
case MS_ASN_COUNTER32:
1270
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1271
win_varbind->name.idLength,
1273
(const u_char *) &win_varbind->value.
1275
sizeof(win_varbind->value.asnValue.
1278
case MS_ASN_GAUGE32:
1279
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1280
win_varbind->name.idLength,
1282
(const u_char *) &win_varbind->value.
1284
sizeof(win_varbind->value.asnValue.
1287
case MS_ASN_TIMETICKS:
1288
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1289
win_varbind->name.idLength,
1291
(const u_char *) &win_varbind->value.
1293
sizeof(win_varbind->value.asnValue.
1296
case MS_ASN_OPAQUE: // AsnOctetString
1297
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1298
win_varbind->name.idLength,
1300
win_varbind->value.asnValue.arbitrary.
1302
win_varbind->value.asnValue.arbitrary.
1305
case MS_ASN_COUNTER64:
1306
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1307
win_varbind->name.idLength,
1309
(const u_char *) &win_varbind->value.
1311
sizeof(win_varbind->value.asnValue.
1314
case MS_ASN_UINTEGER32:
1315
snmp_varlist_add_variable(net_snmp_varbinds, win_varbind->name.ids,
1316
win_varbind->name.idLength,
1318
(const u_char *) &win_varbind->value.
1319
asnValue.unsigned32,
1320
sizeof(win_varbind->value.asnValue.
1324
return SNMP_ERR_GENERR;
1327
return SNMP_ERR_NOERROR;
1331
* Convert a Net-SNMP varbind to a WinSNMP varbind list.
1333
* @param[out] pVarBindList WinSNMP varbind list, initialized by this
1335
* @param[in] varbind Net-SNMP varbind.
1338
convert_to_windows_varbind_list(SnmpVarBindList * pVarBindList,
1339
netsnmp_variable_list * varbind)
1341
SnmpVarBind *win_varbind;
1343
assert(pVarBindList);
1346
pVarBindList->len = 1;
1348
= (SnmpVarBind *) SnmpUtilMemAlloc(pVarBindList->len
1350
sizeof(pVarBindList->list[0]));
1351
if (pVarBindList->list == 0)
1354
memset(&pVarBindList->list[0], 0, sizeof(pVarBindList->list[0]));
1356
win_varbind = &pVarBindList->list[0];
1359
&& !copy_oid_to_new_windows_oid(&win_varbind->name,
1361
varbind->name_length))
1364
switch (varbind->type) {
1366
// There is no equivalent type in Microsoft's <snmp.h>.
1368
win_varbind->value.asnType = MS_ASN_INTEGER;
1369
win_varbind->value.asnValue.number = *(varbind->val.integer);
1372
win_varbind->value.asnType = MS_ASN_INTEGER;
1373
win_varbind->value.asnValue.number = *(varbind->val.integer);
1376
win_varbind->value.asnType = MS_ASN_BITS;
1377
win_varbind->value.asnValue.string.stream
1378
= winsnmp_memdup(varbind->val.string, varbind->val_len);
1379
win_varbind->value.asnValue.string.length =
1380
(UINT) (varbind->val_len);
1381
win_varbind->value.asnValue.string.dynamic = TRUE;
1384
win_varbind->value.asnType = MS_ASN_OCTETSTRING;
1385
win_varbind->value.asnValue.string.stream
1386
= winsnmp_memdup(varbind->val.string, varbind->val_len);
1387
win_varbind->value.asnValue.string.length =
1388
(UINT) (varbind->val_len);
1389
win_varbind->value.asnValue.string.dynamic = TRUE;
1392
win_varbind->value.asnType = MS_ASN_NULL;
1393
memset(&win_varbind->value, 0, sizeof(win_varbind->value));
1396
win_varbind->value.asnType = MS_ASN_OBJECTIDENTIFIER;
1397
if (!copy_oid_to_new_windows_oid
1398
(&win_varbind->value.asnValue.object, varbind->val.objid,
1399
varbind->val_len / sizeof(varbind->val.objid[0])))
1400
return SNMP_ERR_GENERR;
1403
win_varbind->value.asnType = MS_ASN_SEQUENCE;
1404
win_varbind->value.asnValue.string.stream
1405
= winsnmp_memdup(varbind->val.string, varbind->val_len);
1406
win_varbind->value.asnValue.string.length =
1407
(UINT) (varbind->val_len);
1408
win_varbind->value.asnValue.string.dynamic = TRUE;
1411
// There is no equivalent type in Microsoft's <snmp.h>.
1413
win_varbind->value.asnType = MS_ASN_INTEGER;
1414
win_varbind->value.asnValue.number = *(varbind->val.integer);
1417
win_varbind->value.asnType = MS_ASN_IPADDRESS;
1418
win_varbind->value.asnValue.string.stream
1419
= winsnmp_memdup(varbind->val.string, varbind->val_len);
1420
win_varbind->value.asnValue.string.length =
1421
(UINT) (varbind->val_len);
1422
win_varbind->value.asnValue.string.dynamic = TRUE;
1425
win_varbind->value.asnType = MS_ASN_COUNTER32;
1426
win_varbind->value.asnValue.counter = *(varbind->val.integer);
1429
* ASN_GAUGE == ASN_UNSIGNED
1432
win_varbind->value.asnType = MS_ASN_UNSIGNED32;
1433
win_varbind->value.asnValue.unsigned32 = *(varbind->val.integer);
1436
win_varbind->value.asnType = MS_ASN_TIMETICKS;
1437
win_varbind->value.asnValue.ticks = *(varbind->val.integer);
1440
win_varbind->value.asnType = MS_ASN_OPAQUE;
1441
win_varbind->value.asnValue.string.stream
1442
= winsnmp_memdup(varbind->val.string, varbind->val_len);
1443
win_varbind->value.asnValue.string.length =
1444
(UINT) (varbind->val_len);
1445
win_varbind->value.asnValue.string.dynamic = TRUE;
1448
win_varbind->value.asnType = MS_ASN_COUNTER64;
1449
win_varbind->value.asnValue.counter64.HighPart
1450
= varbind->val.counter64->high;
1451
win_varbind->value.asnValue.counter64.LowPart
1452
= varbind->val.counter64->low;
1459
return SNMP_ERR_NOERROR;
1462
SnmpUtilVarBindListFree(pVarBindList);
1463
memset(pVarBindList, 0, sizeof(*pVarBindList));
1464
return SNMP_ERR_GENERR;
1467
/** Convert a Windows SNMP error code to the equivalent Net-SNMP error code. */
1469
convert_win_snmp_err(const int win_snmp_err)
1471
switch (win_snmp_err) {
1472
case SNMP_ERRORSTATUS_NOERROR:
1473
return SNMP_ERR_NOERROR;
1474
case SNMP_ERRORSTATUS_TOOBIG:
1475
return SNMP_ERR_TOOBIG;
1476
case SNMP_ERRORSTATUS_NOSUCHNAME:
1478
* Note: SNMP extension DLLs return SNMP_ERRORSTATUS_NOSUCHNAME
1479
* when either noSuchObject or noSuchInstance should be returned to
1480
* the SNMP manager (assuming SNMPv2c or SNMPv3). Unfortunately it
1481
* is not possible without consulting the MIB to find out whether
1482
* either SNMP_NOSUCHINSTANCE or SNMP_NOSUCHOBJECT should be returned.
1483
* See also RFC 1448.
1485
return SNMP_NOSUCHINSTANCE;
1486
case SNMP_ERRORSTATUS_BADVALUE:
1487
return SNMP_ERR_BADVALUE;
1488
case SNMP_ERRORSTATUS_READONLY:
1489
return SNMP_ERR_READONLY;
1490
case SNMP_ERRORSTATUS_GENERR:
1491
return SNMP_ERR_GENERR;
1492
case SNMP_ERRORSTATUS_NOACCESS:
1493
return SNMP_ERR_NOACCESS;
1494
case SNMP_ERRORSTATUS_WRONGTYPE:
1495
return SNMP_ERR_WRONGTYPE;
1496
case SNMP_ERRORSTATUS_WRONGLENGTH:
1497
return SNMP_ERR_WRONGLENGTH;
1498
case SNMP_ERRORSTATUS_WRONGENCODING:
1499
return SNMP_ERR_WRONGENCODING;
1500
case SNMP_ERRORSTATUS_WRONGVALUE:
1501
return SNMP_ERR_WRONGVALUE;
1502
case SNMP_ERRORSTATUS_NOCREATION:
1503
return SNMP_ERR_NOCREATION;
1504
case SNMP_ERRORSTATUS_INCONSISTENTVALUE:
1505
return SNMP_ERR_INCONSISTENTVALUE;
1506
case SNMP_ERRORSTATUS_RESOURCEUNAVAILABLE:
1507
return SNMP_ERR_RESOURCEUNAVAILABLE;
1508
case SNMP_ERRORSTATUS_COMMITFAILED:
1509
return SNMP_ERR_COMMITFAILED;
1510
case SNMP_ERRORSTATUS_UNDOFAILED:
1511
return SNMP_ERR_UNDOFAILED;
1512
case SNMP_ERRORSTATUS_AUTHORIZATIONERROR:
1513
return SNMP_ERR_AUTHORIZATIONERROR;
1514
case SNMP_ERRORSTATUS_NOTWRITABLE:
1515
return SNMP_ERR_NOTWRITABLE;
1516
case SNMP_ERRORSTATUS_INCONSISTENTNAME:
1517
return SNMP_ERR_INCONSISTENTNAME;
1520
return SNMP_ERR_GENERR;
1524
* Look up the extension DLL view that was registered with the given OID.
1526
static winextdll_view *
1527
lookup_view_by_oid(oid * const name, const size_t name_len)
1595
for (i = 0; i < theoid->idLength; i++) {
1596
sprintf(temp, ".%d", theoid->ids[i]);
1601
debugmsg(token, "%s", buf);
1602
//DEBUGMSGTL((token, "%s\n", buf));
1531
for (i = 0; i < s_winextdll_view.size; i++) {
1532
if (netsnmp_oid_equals(WINEXTDLL_VIEW(i).name,
1533
WINEXTDLL_VIEW(i).name_length,
1534
name, name_len) == 0
1535
&& WINEXTDLL_VIEW(i).my_handler) {
1536
return &WINEXTDLL_VIEW(i);
1546
* @param[out] to_name Number of elements written to destination OID.
1547
* @param[out] to_name_len Length of destination OID. Must have at least
1548
* min(from_name_len, MAX_OID_LEN) elements.
1549
* @param[in] from_name Original OID.
1550
* @param[in] from_name_len Length of original OID.
1553
copy_oid(oid * const to_name, size_t * const to_name_len,
1554
const oid * const from_name, const size_t from_name_len)
1559
assert(to_name_len);
1562
for (j = 0; j < from_name_len && j < MAX_OID_LEN; j++)
1563
to_name[j] = from_name[j];
1569
* Convert a Net-SNMP OID into a Windows OID and allocate memory for the
1572
* @param[out] windows_oid Pointer to a AsnObjectIdentifier.
1573
* @param[in] name Pointer to an array with elements of type oid
1574
* and length name_len.
1575
* @param[in] name_len Number of elements of input and output OID.
1578
copy_oid_to_new_windows_oid(AsnObjectIdentifier * const windows_oid,
1579
const oid * const name, const size_t name_len)
1581
assert(windows_oid);
1582
assert(windows_oid->ids == 0);
1583
assert(windows_oid->idLength == 0);
1588
(UINT *) winsnmp_memdup(name,
1589
sizeof(windows_oid->ids[0]) * name_len);
1590
windows_oid->idLength = (UINT) name_len;
1591
return windows_oid->ids;
1595
winsnmp_memdup(const void *src, const size_t len)
1599
assert(len == (UINT) len);
1601
p = SnmpUtilMemAlloc((UINT) len);
1603
memcpy(p, src, len);
1608
/** Initialize array 'a'. */
1610
xarray_init(xarray * a, size_t elem_size)
1614
memset(a, 0, sizeof(*a));
1615
a->elem_size = elem_size;
1619
/** Deallocate any memory that was dynamically allocated for 'a'. */
1621
xarray_destroy(xarray * a)
1625
xarray_reserve(a, 0);
1629
* Append the contents of the address range [ elem, elem + a->elem_size [ to a.
1631
* Resize a if necessary.
1633
* @return A pointer to the address where the data has been copied upon success,
1634
* or NULL upon failure.
1637
xarray_push_back(xarray * a, const void *elem)
1641
assert(a->size <= a->reserved);
1643
if (a->size == a->reserved)
1644
xarray_reserve(a, a->reserved == 0 ? 16 : 2 * a->reserved);
1645
if (a->size < a->reserved) {
1646
assert(a->size < a->reserved);
1647
return memcpy((char *) (a->p) + a->elem_size * a->size++, elem,
1654
/** Erase [ elem, elem + a->elem_size [ from a. */
1656
xarray_erase(xarray * a, void *const elem)
1659
assert(a->size >= 1);
1660
assert(a->p <= elem);
1661
assert((const char *) elem + a->elem_size <=
1662
(char *) a->p + a->size * a->elem_size);
1663
assert(((const char *) elem - (char *) a->p) % a->elem_size == 0);
1666
memmove((char *) elem, (char *) elem + a->elem_size,
1667
a->size - ((const char *) elem -
1668
(char *) a->p) / a->elem_size);
1673
* Change the number of allocated elements to 'reserved'.
1675
* Can be used either for enlarging or for shrinking the memory allocated for
1676
* 'a'. Does not modify 'a' if memory allocation fails. Newly allocted memory
1677
* is not initialized.
1679
* @return != NULL upon success, NULL upon failure.
1682
xarray_reserve(xarray * a, int reserved)
1685
assert(a->size <= a->reserved);
1687
if ((a->p = realloc(a->p, a->elem_size * reserved)))
1688
a->reserved = reserved;
1694
#endif /* USING_WINEXTDLL_MODULE */