xref: /PHP-5.3/ext/snmp/snmp.c (revision a2045ff3)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
16    |          Mike Jackson <mhjack@tscnet.com>                            |
17    |          Steven Lawrance <slawrance@technologist.com>                |
18    |          Harrie Hazewinkel <harrie@lisanza.net>                      |
19    |          Johann Hanne <jonny@nurfuerspam.de>                         |
20    +----------------------------------------------------------------------+
21  */
22 
23 /* $Id$ */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include "php.h"
30 #include "ext/standard/info.h"
31 #include "php_snmp.h"
32 
33 #if HAVE_SNMP
34 
35 #include <sys/types.h>
36 #ifdef PHP_WIN32
37 #include <winsock2.h>
38 #include <errno.h>
39 #include <process.h>
40 #include "win32/time.h"
41 #elif defined(NETWARE)
42 #ifdef USE_WINSOCK
43 #include <novsock2.h>
44 #else
45 #include <sys/socket.h>
46 #endif
47 #include <errno.h>
48 #include <sys/timeval.h>
49 #else
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #ifndef _OSD_POSIX
54 #include <sys/errno.h>
55 #else
56 #include <errno.h>  /* BS2000/OSD uses <errno.h>, not <sys/errno.h> */
57 #endif
58 #include <netdb.h>
59 #endif
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 
64 #ifndef __P
65 #ifdef __GNUC__
66 #define __P(args) args
67 #else
68 #define __P(args) ()
69 #endif
70 #endif
71 
72 #ifdef HAVE_NET_SNMP
73 #include <net-snmp/net-snmp-config.h>
74 #include <net-snmp/net-snmp-includes.h>
75 #else
76 #ifdef HAVE_DEFAULT_STORE_H
77 #include "default_store.h"
78 #endif
79 #include "asn1.h"
80 #include "snmp_api.h"
81 #include "snmp_client.h"
82 #include "snmp_impl.h"
83 #include "snmp.h"
84 #include "snmpv3.h"
85 #include "keytools.h"
86 #include "parse.h"
87 #include "mib.h"
88 #ifndef PHP_WIN32
89 /* this doesn't appear to be needed under win32 (perhaps at all)
90  * and the header file is not present in my UCD-SNMP headers */
91 # include "version.h"
92 #endif
93 #include "transform_oids.h"
94 #endif
95 /* Ugly macro, since the length of OIDs in UCD-SNMP and NET-SNMP
96  * is different and this way the code is not full of 'ifdef's.
97  */
98 #define OIDSIZE(p) (sizeof(p)/sizeof(oid))
99 
100 /* For really old ucd-snmp versions.. */
101 #ifndef HAVE_SNMP_PARSE_OID
102 #define snmp_parse_oid read_objid
103 #endif
104 
105 #define SNMP_VALUE_LIBRARY	0
106 #define SNMP_VALUE_PLAIN	1
107 #define SNMP_VALUE_OBJECT	2
108 
109 ZEND_DECLARE_MODULE_GLOBALS(snmp)
110 static PHP_GINIT_FUNCTION(snmp);
111 
112 /* constant - can be shared among threads */
113 static oid objid_mib[] = {1, 3, 6, 1, 2, 1};
114 
115 /* {{{ arginfo */
116 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpget, 0, 0, 3)
117 	ZEND_ARG_INFO(0, host)
118 	ZEND_ARG_INFO(0, community)
119 	ZEND_ARG_INFO(0, object_id)
120 	ZEND_ARG_INFO(0, timeout)
121 	ZEND_ARG_INFO(0, retries)
122 ZEND_END_ARG_INFO()
123 
124 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpgetnext, 0, 0, 3)
125 	ZEND_ARG_INFO(0, host)
126 	ZEND_ARG_INFO(0, community)
127 	ZEND_ARG_INFO(0, object_id)
128 	ZEND_ARG_INFO(0, timeout)
129 	ZEND_ARG_INFO(0, retries)
130 ZEND_END_ARG_INFO()
131 
132 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpwalk, 0, 0, 3)
133 	ZEND_ARG_INFO(0, host)
134 	ZEND_ARG_INFO(0, community)
135 	ZEND_ARG_INFO(0, object_id)
136 	ZEND_ARG_INFO(0, timeout)
137 	ZEND_ARG_INFO(0, retries)
138 ZEND_END_ARG_INFO()
139 
140 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmprealwalk, 0, 0, 3)
141 	ZEND_ARG_INFO(0, host)
142 	ZEND_ARG_INFO(0, community)
143 	ZEND_ARG_INFO(0, object_id)
144 	ZEND_ARG_INFO(0, timeout)
145 	ZEND_ARG_INFO(0, retries)
146 ZEND_END_ARG_INFO()
147 
148 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_get_quick_print, 0, 0, 1)
149 	ZEND_ARG_INFO(0, d)
150 ZEND_END_ARG_INFO()
151 
152 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_quick_print, 0, 0, 1)
153 	ZEND_ARG_INFO(0, quick_print)
154 ZEND_END_ARG_INFO()
155 
156 #ifdef HAVE_NET_SNMP
157 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_enum_print, 0, 0, 1)
158 	ZEND_ARG_INFO(0, enum_print)
159 ZEND_END_ARG_INFO()
160 
161 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_oid_output_format, 0, 0, 1)
162 	ZEND_ARG_INFO(0, oid_format)
163 ZEND_END_ARG_INFO()
164 #endif
165 
166 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpset, 0, 0, 5)
167 	ZEND_ARG_INFO(0, host)
168 	ZEND_ARG_INFO(0, community)
169 	ZEND_ARG_INFO(0, object_id)
170 	ZEND_ARG_INFO(0, type)
171 	ZEND_ARG_INFO(0, value)
172 	ZEND_ARG_INFO(0, timeout)
173 	ZEND_ARG_INFO(0, retries)
174 ZEND_END_ARG_INFO()
175 
176 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_get, 0, 0, 3)
177 	ZEND_ARG_INFO(0, host)
178 	ZEND_ARG_INFO(0, community)
179 	ZEND_ARG_INFO(0, object_id)
180 	ZEND_ARG_INFO(0, timeout)
181 	ZEND_ARG_INFO(0, retries)
182 ZEND_END_ARG_INFO()
183 
184 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_getnext, 0, 0, 3)
185 	ZEND_ARG_INFO(0, host)
186 	ZEND_ARG_INFO(0, community)
187 	ZEND_ARG_INFO(0, object_id)
188 	ZEND_ARG_INFO(0, timeout)
189 	ZEND_ARG_INFO(0, retries)
190 ZEND_END_ARG_INFO()
191 
192 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_walk, 0, 0, 3)
193 	ZEND_ARG_INFO(0, host)
194 	ZEND_ARG_INFO(0, community)
195 	ZEND_ARG_INFO(0, object_id)
196 	ZEND_ARG_INFO(0, timeout)
197 	ZEND_ARG_INFO(0, retries)
198 ZEND_END_ARG_INFO()
199 
200 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_real_walk, 0, 0, 3)
201 	ZEND_ARG_INFO(0, host)
202 	ZEND_ARG_INFO(0, community)
203 	ZEND_ARG_INFO(0, object_id)
204 	ZEND_ARG_INFO(0, timeout)
205 	ZEND_ARG_INFO(0, retries)
206 ZEND_END_ARG_INFO()
207 
208 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_set, 0, 0, 5)
209 	ZEND_ARG_INFO(0, host)
210 	ZEND_ARG_INFO(0, community)
211 	ZEND_ARG_INFO(0, object_id)
212 	ZEND_ARG_INFO(0, type)
213 	ZEND_ARG_INFO(0, value)
214 	ZEND_ARG_INFO(0, timeout)
215 	ZEND_ARG_INFO(0, retries)
216 ZEND_END_ARG_INFO()
217 
218 ZEND_BEGIN_ARG_INFO_EX(arginfo_php_snmpv3, 0, 0, 2)
219 	ZEND_ARG_INFO(0, s)
220 	ZEND_ARG_INFO(0, st)
221 ZEND_END_ARG_INFO()
222 
223 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_get, 0, 0, 8)
224 	ZEND_ARG_INFO(0, host)
225 	ZEND_ARG_INFO(0, sec_name)
226 	ZEND_ARG_INFO(0, sec_level)
227 	ZEND_ARG_INFO(0, auth_protocol)
228 	ZEND_ARG_INFO(0, auth_passphrase)
229 	ZEND_ARG_INFO(0, priv_protocol)
230 	ZEND_ARG_INFO(0, priv_passphrase)
231 	ZEND_ARG_INFO(0, object_id)
232 	ZEND_ARG_INFO(0, timeout)
233 	ZEND_ARG_INFO(0, retries)
234 ZEND_END_ARG_INFO()
235 
236 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_getnext, 0, 0, 8)
237 	ZEND_ARG_INFO(0, host)
238 	ZEND_ARG_INFO(0, sec_name)
239 	ZEND_ARG_INFO(0, sec_level)
240 	ZEND_ARG_INFO(0, auth_protocol)
241 	ZEND_ARG_INFO(0, auth_passphrase)
242 	ZEND_ARG_INFO(0, priv_protocol)
243 	ZEND_ARG_INFO(0, priv_passphrase)
244 	ZEND_ARG_INFO(0, object_id)
245 	ZEND_ARG_INFO(0, timeout)
246 	ZEND_ARG_INFO(0, retries)
247 ZEND_END_ARG_INFO()
248 
249 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_walk, 0, 0, 8)
250 	ZEND_ARG_INFO(0, host)
251 	ZEND_ARG_INFO(0, sec_name)
252 	ZEND_ARG_INFO(0, sec_level)
253 	ZEND_ARG_INFO(0, auth_protocol)
254 	ZEND_ARG_INFO(0, auth_passphrase)
255 	ZEND_ARG_INFO(0, priv_protocol)
256 	ZEND_ARG_INFO(0, priv_passphrase)
257 	ZEND_ARG_INFO(0, object_id)
258 	ZEND_ARG_INFO(0, timeout)
259 	ZEND_ARG_INFO(0, retries)
260 ZEND_END_ARG_INFO()
261 
262 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_real_walk, 0, 0, 8)
263 	ZEND_ARG_INFO(0, host)
264 	ZEND_ARG_INFO(0, sec_name)
265 	ZEND_ARG_INFO(0, sec_level)
266 	ZEND_ARG_INFO(0, auth_protocol)
267 	ZEND_ARG_INFO(0, auth_passphrase)
268 	ZEND_ARG_INFO(0, priv_protocol)
269 	ZEND_ARG_INFO(0, priv_passphrase)
270 	ZEND_ARG_INFO(0, object_id)
271 	ZEND_ARG_INFO(0, timeout)
272 	ZEND_ARG_INFO(0, retries)
273 ZEND_END_ARG_INFO()
274 
275 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_set, 0, 0, 10)
276 	ZEND_ARG_INFO(0, host)
277 	ZEND_ARG_INFO(0, sec_name)
278 	ZEND_ARG_INFO(0, sec_level)
279 	ZEND_ARG_INFO(0, auth_protocol)
280 	ZEND_ARG_INFO(0, auth_passphrase)
281 	ZEND_ARG_INFO(0, priv_protocol)
282 	ZEND_ARG_INFO(0, priv_passphrase)
283 	ZEND_ARG_INFO(0, object_id)
284 	ZEND_ARG_INFO(0, type)
285 	ZEND_ARG_INFO(0, value)
286 	ZEND_ARG_INFO(0, timeout)
287 	ZEND_ARG_INFO(0, retries)
288 ZEND_END_ARG_INFO()
289 
290 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_valueretrieval, 0, 0, 1)
291 	ZEND_ARG_INFO(0, method)
292 ZEND_END_ARG_INFO()
293 
294 ZEND_BEGIN_ARG_INFO(arginfo_snmp_get_valueretrieval, 0)
295 ZEND_END_ARG_INFO()
296 
297 ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_read_mib, 0, 0, 1)
298 	ZEND_ARG_INFO(0, filename)
299 ZEND_END_ARG_INFO()
300 /* }}} */
301 
302 /* {{{ snmp_functions[]
303  */
304 const zend_function_entry snmp_functions[] = {
305 	PHP_FE(snmpget, 						arginfo_snmpget)
306 	PHP_FE(snmpgetnext, 					arginfo_snmpgetnext)
307 	PHP_FE(snmpwalk, 						arginfo_snmpwalk)
308 	PHP_FE(snmprealwalk, 					arginfo_snmprealwalk)
309 	PHP_FALIAS(snmpwalkoid, snmprealwalk, 	arginfo_snmprealwalk)
310 	PHP_FE(snmp_get_quick_print, 			arginfo_snmp_get_quick_print)
311 	PHP_FE(snmp_set_quick_print, 			arginfo_snmp_set_quick_print)
312 #ifdef HAVE_NET_SNMP
313 	PHP_FE(snmp_set_enum_print, 			arginfo_snmp_set_enum_print)
314 	PHP_FE(snmp_set_oid_output_format, 		arginfo_snmp_set_oid_output_format)
315 	PHP_FALIAS(snmp_set_oid_numeric_print, snmp_set_oid_output_format, arginfo_snmp_set_oid_output_format)
316 #endif
317 	PHP_FE(snmpset, 				arginfo_snmpset)
318 
319 	PHP_FE(snmp2_get, 				arginfo_snmp2_get)
320 	PHP_FE(snmp2_getnext, 			arginfo_snmp2_getnext)
321 	PHP_FE(snmp2_walk, 				arginfo_snmp2_walk)
322 	PHP_FE(snmp2_real_walk, 		arginfo_snmp2_real_walk)
323 	PHP_FE(snmp2_set, 				arginfo_snmp2_set)
324 
325 	PHP_FE(snmp3_get, 				arginfo_snmp3_get)
326 	PHP_FE(snmp3_getnext, 			arginfo_snmp3_getnext)
327 	PHP_FE(snmp3_walk, 				arginfo_snmp3_walk)
328 	PHP_FE(snmp3_real_walk, 		arginfo_snmp3_real_walk)
329 	PHP_FE(snmp3_set, 				arginfo_snmp3_set)
330 	PHP_FE(snmp_set_valueretrieval, arginfo_snmp_set_valueretrieval)
331 	PHP_FE(snmp_get_valueretrieval, arginfo_snmp_get_valueretrieval)
332 
333 	PHP_FE(snmp_read_mib, 			arginfo_snmp_read_mib)
334 	PHP_FE_END
335 };
336 /* }}} */
337 
338 #define SNMP_CMD_GET		1
339 #define SNMP_CMD_GETNEXT	2
340 #define SNMP_CMD_WALK		3
341 #define SNMP_CMD_REALWALK	4
342 #define SNMP_CMD_SET		11
343 
344 /* {{{ snmp_module_entry
345  */
346 zend_module_entry snmp_module_entry = {
347 	STANDARD_MODULE_HEADER,
348 	"snmp",
349 	snmp_functions,
350 	PHP_MINIT(snmp),
351 	PHP_MSHUTDOWN(snmp),
352 	NULL,
353 	NULL,
354 	PHP_MINFO(snmp),
355 	NO_VERSION_YET,
356 	PHP_MODULE_GLOBALS(snmp),
357 	PHP_GINIT(snmp),
358 	NULL,
359 	NULL,
360 	STANDARD_MODULE_PROPERTIES_EX
361 };
362 /* }}} */
363 
364 #ifdef COMPILE_DL_SNMP
365 ZEND_GET_MODULE(snmp)
366 #endif
367 
368 /* THREAD_LS snmp_module php_snmp_module; - may need one of these at some point */
369 
370 /* {{{ PHP_GINIT_FUNCTION
371  */
PHP_GINIT_FUNCTION(snmp)372 static PHP_GINIT_FUNCTION(snmp)
373 {
374 	snmp_globals->valueretrieval = SNMP_VALUE_LIBRARY;
375 }
376 /* }}} */
377 
378 /* {{{ PHP_MINIT_FUNCTION
379  */
PHP_MINIT_FUNCTION(snmp)380 PHP_MINIT_FUNCTION(snmp)
381 {
382 	init_snmp("snmpapp");
383 
384 #ifdef NETSNMP_DS_LIB_DONT_PERSIST_STATE
385 	/* Prevent update of the snmpapp.conf file */
386 	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
387 #endif
388 
389 #ifdef HAVE_NET_SNMP
390 	REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_FULL", NETSNMP_OID_OUTPUT_FULL, CONST_CS | CONST_PERSISTENT);
391 	REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_NUMERIC", NETSNMP_OID_OUTPUT_NUMERIC, CONST_CS | CONST_PERSISTENT);
392 #endif
393 
394 	REGISTER_LONG_CONSTANT("SNMP_VALUE_LIBRARY", SNMP_VALUE_LIBRARY, CONST_CS | CONST_PERSISTENT);
395 	REGISTER_LONG_CONSTANT("SNMP_VALUE_PLAIN", SNMP_VALUE_PLAIN, CONST_CS | CONST_PERSISTENT);
396 	REGISTER_LONG_CONSTANT("SNMP_VALUE_OBJECT", SNMP_VALUE_OBJECT, CONST_CS | CONST_PERSISTENT);
397 
398 	REGISTER_LONG_CONSTANT("SNMP_BIT_STR", ASN_BIT_STR, CONST_CS | CONST_PERSISTENT);
399 	REGISTER_LONG_CONSTANT("SNMP_OCTET_STR", ASN_OCTET_STR, CONST_CS | CONST_PERSISTENT);
400 	REGISTER_LONG_CONSTANT("SNMP_OPAQUE", ASN_OPAQUE, CONST_CS | CONST_PERSISTENT);
401 	REGISTER_LONG_CONSTANT("SNMP_NULL", ASN_NULL, CONST_CS | CONST_PERSISTENT);
402 	REGISTER_LONG_CONSTANT("SNMP_OBJECT_ID", ASN_OBJECT_ID, CONST_CS | CONST_PERSISTENT);
403 	REGISTER_LONG_CONSTANT("SNMP_IPADDRESS", ASN_IPADDRESS, CONST_CS | CONST_PERSISTENT);
404 	REGISTER_LONG_CONSTANT("SNMP_COUNTER", ASN_GAUGE, CONST_CS | CONST_PERSISTENT);
405 	REGISTER_LONG_CONSTANT("SNMP_UNSIGNED", ASN_UNSIGNED, CONST_CS | CONST_PERSISTENT);
406 	REGISTER_LONG_CONSTANT("SNMP_TIMETICKS", ASN_TIMETICKS, CONST_CS | CONST_PERSISTENT);
407 	REGISTER_LONG_CONSTANT("SNMP_UINTEGER", ASN_UINTEGER, CONST_CS | CONST_PERSISTENT);
408 	REGISTER_LONG_CONSTANT("SNMP_INTEGER", ASN_INTEGER, CONST_CS | CONST_PERSISTENT);
409 	REGISTER_LONG_CONSTANT("SNMP_COUNTER64", ASN_COUNTER64, CONST_CS | CONST_PERSISTENT);
410 
411 	return SUCCESS;
412 }
413 /* }}} */
414 
415 /* {{{ PHP_MSHUTDOWN_FUNCTION
416  */
PHP_MSHUTDOWN_FUNCTION(snmp)417 PHP_MSHUTDOWN_FUNCTION(snmp)
418 {
419 	snmp_shutdown("snmpapp");
420 
421 	return SUCCESS;
422 }
423 /* }}} */
424 
425 /* {{{ PHP_MINFO_FUNCTION
426  */
PHP_MINFO_FUNCTION(snmp)427 PHP_MINFO_FUNCTION(snmp)
428 {
429 	php_info_print_table_start();
430 #ifdef HAVE_NET_SNMP
431 	php_info_print_table_row(2, "NET-SNMP Support", "enabled");
432 	php_info_print_table_row(2, "NET-SNMP Version", netsnmp_get_version());
433 #else
434 	php_info_print_table_row(2, "UCD-SNMP Support", "enabled");
435 	php_info_print_table_row(2, "UCD-SNMP Version", VersionInfo);
436 #endif
437 	php_info_print_table_end();
438 }
439 /* }}} */
440 
php_snmp_getvalue(struct variable_list * vars,zval * snmpval TSRMLS_DC)441 static void php_snmp_getvalue(struct variable_list *vars, zval *snmpval TSRMLS_DC)
442 {
443 	zval *val;
444 #if I64CHARSZ > 2047
445 	char buf[I64CHARSZ + 1];
446 #else
447 	char buf[2048];
448 #endif
449 
450 	buf[0] = 0;
451 
452 	if (SNMP_G(valueretrieval) == SNMP_VALUE_LIBRARY) {
453 #ifdef HAVE_NET_SNMP
454 		snprint_value(buf, sizeof(buf), vars->name, vars->name_length, vars);
455 #else
456 		sprint_value(buf,vars->name, vars->name_length, vars);
457 #endif
458 		ZVAL_STRING(snmpval, buf, 1);
459 		return;
460 	}
461 
462 	MAKE_STD_ZVAL(val);
463 
464 	switch (vars->type) {
465 	case ASN_BIT_STR:		/* 0x03, asn1.h */
466 		ZVAL_STRINGL(val, vars->val.bitstring, vars->val_len, 1);
467 		break;
468 
469 	case ASN_OCTET_STR:		/* 0x04, asn1.h */
470 	case ASN_OPAQUE:		/* 0x44, snmp_impl.h */
471 		ZVAL_STRINGL(val, vars->val.string, vars->val_len, 1);
472 		break;
473 
474 	case ASN_NULL:			/* 0x05, asn1.h */
475 		ZVAL_NULL(val);
476 		break;
477 
478 	case ASN_OBJECT_ID:		/* 0x06, asn1.h */
479 #ifdef HAVE_NET_SNMP
480 		snprint_objid(buf, sizeof(buf), vars->val.objid, vars->val_len / sizeof(oid));
481 #else
482 		sprint_objid(buf, vars->val.objid, vars->val_len / sizeof(oid));
483 #endif
484 
485 		ZVAL_STRING(val, buf, 1);
486 		break;
487 
488 	case ASN_IPADDRESS:		/* 0x40, snmp_impl.h */
489 		snprintf(buf, sizeof(buf)-1, "%d.%d.%d.%d",
490 		         (vars->val.string)[0], (vars->val.string)[1],
491 		         (vars->val.string)[2], (vars->val.string)[3]);
492 		buf[sizeof(buf)-1]=0;
493 		ZVAL_STRING(val, buf, 1);
494 		break;
495 
496 	case ASN_COUNTER:		/* 0x41, snmp_impl.h */
497 	case ASN_GAUGE:			/* 0x42, snmp_impl.h */
498 	/* ASN_UNSIGNED is the same as ASN_GAUGE */
499 	case ASN_TIMETICKS:		/* 0x43, snmp_impl.h */
500 	case ASN_UINTEGER:		/* 0x47, snmp_impl.h */
501 		snprintf(buf, sizeof(buf)-1, "%lu", *vars->val.integer);
502 		buf[sizeof(buf)-1]=0;
503 		ZVAL_STRING(val, buf, 1);
504 		break;
505 
506 	case ASN_INTEGER:		/* 0x02, asn1.h */
507 		snprintf(buf, sizeof(buf)-1, "%ld", *vars->val.integer);
508 		buf[sizeof(buf)-1]=0;
509 		ZVAL_STRING(val, buf, 1);
510 		break;
511 
512 	case ASN_COUNTER64:		/* 0x46, snmp_impl.h */
513 		printU64(buf, vars->val.counter64);
514 		ZVAL_STRING(val, buf, 1);
515 		break;
516 
517 	default:
518 		ZVAL_STRING(val, "Unknown value type", 1);
519 		break;
520 	}
521 
522 	if (SNMP_G(valueretrieval) == SNMP_VALUE_PLAIN) {
523 		*snmpval = *val;
524 		zval_copy_ctor(snmpval);
525 	} else {
526 		object_init(snmpval);
527 		add_property_long(snmpval, "type", vars->type);
528 		add_property_zval(snmpval, "value", val);
529 	}
530 }
531 
532 /* {{{ php_snmp_internal
533 *
534 * Generic SNMP object fetcher (for all SNMP versions)
535 *
536 * st=SNMP_CMD_GET   get - query an agent with SNMP-GET.
537 * st=SNMP_CMD_GETNEXT   getnext - query an agent with SNMP-GETNEXT.
538 * st=SNMP_CMD_WALK   walk - walk the mib and return a single dimensional array
539 *          containing the values.
540 * st=SNMP_CMD_REALWALK   realwalk() and walkoid() - walk the mib and return an
541 *          array of oid,value pairs.
542 * st=SNMP_CMD_SET  set() - query an agent and set a single value
543 *
544 */
php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS,int st,struct snmp_session * session,char * objid,char type,char * value)545 static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st,
546 							struct snmp_session *session,
547 							char *objid,
548 							char type,
549 							char* value)
550 {
551 	struct snmp_session *ss;
552 	struct snmp_pdu *pdu=NULL, *response;
553 	struct variable_list *vars;
554 	oid name[MAX_NAME_LEN];
555 	size_t name_length;
556 	oid root[MAX_NAME_LEN];
557 	size_t rootlen = 0;
558 	int gotroot = 0;
559 	int status, count;
560 	char buf[2048];
561 	char buf2[2048];
562 	int keepwalking=1;
563 	char *err;
564 	zval *snmpval = NULL;
565 
566 	if (st >= SNMP_CMD_WALK) { /* walk */
567 		rootlen = MAX_NAME_LEN;
568 		if (strlen(objid)) { /* on a walk, an empty string means top of tree - no error */
569 			if (snmp_parse_oid(objid, root, &rootlen)) {
570 				gotroot = 1;
571 			} else {
572 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid object identifier: %s", objid);
573 			}
574 		}
575 
576 		if (!gotroot) {
577 			memmove((char *) root, (char *) objid_mib, sizeof(objid_mib));
578 			rootlen = sizeof(objid_mib) / sizeof(oid);
579 			gotroot = 1;
580 		}
581 	}
582 
583 	if ((ss = snmp_open(session)) == NULL) {
584 		snmp_error(session, NULL, NULL, &err);
585 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not open snmp connection: %s", err);
586 		free(err);
587 		RETURN_FALSE;
588 	}
589 
590 	if (st >= SNMP_CMD_WALK) {
591 		memmove((char *)name, (char *)root, rootlen * sizeof(oid));
592 		name_length = rootlen;
593 		switch(st) {
594 			case SNMP_CMD_WALK:
595 			case SNMP_CMD_REALWALK:
596 				array_init(return_value);
597 				break;
598 			default:
599 				RETVAL_TRUE;
600 				break;
601 		}
602 	}
603 
604 	while (keepwalking) {
605 		keepwalking = 0;
606 		if ((st == SNMP_CMD_GET) || (st == SNMP_CMD_GETNEXT)) {
607 			name_length = MAX_OID_LEN;
608 			if (!snmp_parse_oid(objid, name, &name_length)) {
609 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid object identifier: %s", objid);
610 				snmp_close(ss);
611 				RETURN_FALSE;
612 			}
613 			pdu = snmp_pdu_create((st == SNMP_CMD_GET) ? SNMP_MSG_GET : SNMP_MSG_GETNEXT);
614 			snmp_add_null_var(pdu, name, name_length);
615 		} else if (st == SNMP_CMD_SET) {
616 			pdu = snmp_pdu_create(SNMP_MSG_SET);
617 			if (snmp_add_var(pdu, name, name_length, type, value)) {
618 #ifdef HAVE_NET_SNMP
619 				snprint_objid(buf, sizeof(buf), name, name_length);
620 #else
621 				sprint_objid(buf, name, name_length);
622 #endif
623 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not add variable: %s %c %s", buf, type, value);
624 				snmp_free_pdu(pdu);
625 				snmp_close(ss);
626 				RETURN_FALSE;
627 			}
628 		} else if (st >= SNMP_CMD_WALK) {
629 			if (session->version == SNMP_VERSION_1) {
630 				pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
631 			} else {
632 				pdu = snmp_pdu_create(SNMP_MSG_GETBULK);
633 				pdu->non_repeaters = 0;
634 				pdu->max_repetitions = 20;
635 			}
636 			snmp_add_null_var(pdu, name, name_length);
637 		}
638 
639 retry:
640 		status = snmp_synch_response(ss, pdu, &response);
641 		if (status == STAT_SUCCESS) {
642 			if (response->errstat == SNMP_ERR_NOERROR) {
643 				for (vars = response->variables; vars; vars = vars->next_variable) {
644 					if (st >= SNMP_CMD_WALK && st != SNMP_CMD_SET &&
645 						(vars->name_length < rootlen || memcmp(root, vars->name, rootlen * sizeof(oid)))) {
646 						continue;       /* not part of this subtree */
647 					}
648 
649 					if (st != SNMP_CMD_SET) {
650 						MAKE_STD_ZVAL(snmpval);
651 						php_snmp_getvalue(vars, snmpval TSRMLS_CC);
652 					}
653 
654 					if (st == SNMP_CMD_GET) {
655 						*return_value = *snmpval;
656 						zval_copy_ctor(return_value);
657 						zval_ptr_dtor(&snmpval);
658 						snmp_free_pdu(response);
659 						snmp_close(ss);
660 						return;
661 					} else if (st == SNMP_CMD_GETNEXT) {
662 						*return_value = *snmpval;
663 						zval_copy_ctor(return_value);
664 						snmp_free_pdu(response);
665 						snmp_close(ss);
666 						return;
667 					} else if (st == SNMP_CMD_WALK) {
668 						add_next_index_zval(return_value,snmpval); /* Add to returned array */
669 					} else if (st == SNMP_CMD_REALWALK && vars->type != SNMP_ENDOFMIBVIEW && vars->type != SNMP_NOSUCHOBJECT && vars->type != SNMP_NOSUCHINSTANCE) {
670 #ifdef HAVE_NET_SNMP
671 						snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
672 #else
673 						sprint_objid(buf2, vars->name, vars->name_length);
674 #endif
675 						add_assoc_zval(return_value,buf2,snmpval);
676 					}
677 					if (st >= SNMP_CMD_WALK && st != SNMP_CMD_SET) {
678 						if (vars->type != SNMP_ENDOFMIBVIEW &&
679 							vars->type != SNMP_NOSUCHOBJECT && vars->type != SNMP_NOSUCHINSTANCE) {
680 							if (snmp_oid_compare(name, name_length, vars->name, vars->name_length) >= 0) {
681 								php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error: OID not increasing: %s",name);
682 								keepwalking = 0;
683 							} else {
684 								memmove((char *)name, (char *)vars->name,vars->name_length * sizeof(oid));
685 								name_length = vars->name_length;
686 								keepwalking = 1;
687 							}
688 						}
689 					}
690 				}
691 			} else {
692 				if ((st != SNMP_CMD_WALK && st != SNMP_CMD_REALWALK) || response->errstat != SNMP_ERR_NOSUCHNAME) {
693 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error in packet: %s", snmp_errstring(response->errstat));
694 					if (response->errstat == SNMP_ERR_NOSUCHNAME) {
695 						for (count=1, vars = response->variables; vars && count != response->errindex;
696 						vars = vars->next_variable, count++);
697 						if (vars) {
698 #ifdef HAVE_NET_SNMP
699 							snprint_objid(buf, sizeof(buf), vars->name, vars->name_length);
700 #else
701 							sprint_objid(buf,vars->name, vars->name_length);
702 #endif
703 						}
704 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "This name does not exist: %s",buf);
705 					}
706 					if (st == SNMP_CMD_GET) {
707 						if ((pdu = snmp_fix_pdu(response, SNMP_MSG_GET)) != NULL) {
708 							snmp_free_pdu(response);
709 							goto retry;
710 						}
711 					} else if (st == SNMP_CMD_SET) {
712 						if ((pdu = snmp_fix_pdu(response, SNMP_MSG_SET)) != NULL) {
713 							snmp_free_pdu(response);
714 							goto retry;
715 						}
716 					} else if (st == SNMP_CMD_GETNEXT) {
717 						if ((pdu = snmp_fix_pdu(response, SNMP_MSG_GETNEXT)) != NULL) {
718 							snmp_free_pdu(response);
719 							goto retry;
720 						}
721 					} else if (st >= SNMP_CMD_WALK) { /* Here we do walks. */
722 						if ((pdu = snmp_fix_pdu(response, ((session->version == SNMP_VERSION_1)
723 										? SNMP_MSG_GETNEXT
724 										: SNMP_MSG_GETBULK))) != NULL) {
725 							snmp_free_pdu(response);
726 							goto retry;
727 						}
728 					}
729 					snmp_free_pdu(response);
730 					snmp_close(ss);
731 					if (st == SNMP_CMD_WALK || st == SNMP_CMD_REALWALK) {
732 						zval_dtor(return_value);
733 					}
734 					RETURN_FALSE;
735 				}
736 			}
737 		} else if (status == STAT_TIMEOUT) {
738 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "No response from %s", session->peername);
739 			if (st == SNMP_CMD_WALK || st == SNMP_CMD_REALWALK) {
740 				zval_dtor(return_value);
741 			}
742 			snmp_close(ss);
743 			RETURN_FALSE;
744 		} else {    /* status == STAT_ERROR */
745 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred, quitting");
746 			if (st == SNMP_CMD_WALK || st == SNMP_CMD_REALWALK) {
747 				zval_dtor(return_value);
748 			}
749 			snmp_close(ss);
750 			RETURN_FALSE;
751 		}
752 		if (response) {
753 			snmp_free_pdu(response);
754 		}
755 	} /* keepwalking */
756 	snmp_close(ss);
757 }
758 /* }}} */
759 
760 /* {{{ php_snmp
761 *
762 * Generic community based SNMP handler for version 1 and 2.
763 * This function makes use of the internal SNMP object fetcher.
764 * The object fetcher is shared with SNMPv3.
765 *
766 * st=SNMP_CMD_GET   get - query an agent with SNMP-GET.
767 * st=SNMP_CMD_GETNEXT   getnext - query an agent with SNMP-GETNEXT.
768 * st=SNMP_CMD_WALK   walk - walk the mib and return a single dimensional array
769 *          containing the values.
770 * st=SNMP_CMD_REALWALK   realwalk() and walkoid() - walk the mib and return an
771 *          array of oid,value pairs.
772 * st=5-8 ** Reserved **
773 * st=SNMP_CMD_SET  set() - query an agent and set a single value
774 *
775 */
php_snmp(INTERNAL_FUNCTION_PARAMETERS,int st,int version)776 static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version)
777 {
778 	char *a1, *a2, *a3;
779 	int a1_len, a2_len, a3_len;
780 	struct snmp_session session;
781 	long timeout = SNMP_DEFAULT_TIMEOUT;
782 	long retries = SNMP_DEFAULT_RETRIES;
783 	char type = (char) 0;
784 	char *value = (char *) 0, *stype = "";
785 	int value_len, stype_len;
786 	char hostname[MAX_NAME_LEN];
787 	int remote_port = 161;
788 	char *pptr;
789 	int argc = ZEND_NUM_ARGS();
790 
791 	if (st == SNMP_CMD_SET) {
792 		if (zend_parse_parameters(argc TSRMLS_CC, "sssss|ll", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len, &stype, &stype_len, &value, &value_len, &timeout, &retries) == FAILURE) {
793 			return;
794 		}
795 	} else {
796 		/* SNMP_CMD_GET
797 		 * SNMP_CMD_GETNEXT
798 		 * SNMP_CMD_WALK
799 		 * SNMP_CMD_REALWALK
800 		 */
801 		if (zend_parse_parameters(argc TSRMLS_CC, "sss|ll", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len, &timeout, &retries) == FAILURE) {
802 			return;
803 		}
804 	}
805 
806 	if (st == SNMP_CMD_SET) {
807 		type = stype[0];
808 	}
809 
810 	snmp_sess_init(&session);
811 	strlcpy(hostname, a1, sizeof(hostname));
812 	if ((pptr = strchr (hostname, ':'))) {
813 		remote_port = strtol (pptr + 1, NULL, 0);
814 	}
815 
816 	session.peername = hostname;
817 	session.remote_port = remote_port;
818 	session.version = version;
819 	/*
820 	* FIXME: potential memory leak
821 	* This is a workaround for an "artifact" (Mike Slifcak)
822 	* in (at least) ucd-snmp 3.6.1 which frees
823 	* memory it did not allocate
824 	*/
825 #ifdef UCD_SNMP_HACK
826 	session.community = (u_char *)strdup(a2); /* memory freed by SNMP library, strdup NOT estrdup */
827 #else
828 	session.community = (u_char *)a2;
829 #endif
830 	session.community_len = a2_len;
831 	session.retries = retries;
832 	session.timeout = timeout;
833 
834 	session.authenticator = NULL;
835 
836 	php_snmp_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, st, &session, a3, type, value);
837 }
838 /* }}} */
839 
840 /* {{{ proto string snmpget(string host, string community, string object_id [, int timeout [, int retries]])
841    Fetch a SNMP object */
PHP_FUNCTION(snmpget)842 PHP_FUNCTION(snmpget)
843 {
844 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU,SNMP_CMD_GET, SNMP_VERSION_1);
845 }
846 /* }}} */
847 
848 /* {{{ proto string snmpgetnext(string host, string community, string object_id [, int timeout [, int retries]])
849    Fetch a SNMP object */
PHP_FUNCTION(snmpgetnext)850 PHP_FUNCTION(snmpgetnext)
851 {
852 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU,SNMP_CMD_GETNEXT, SNMP_VERSION_1);
853 }
854 /* }}} */
855 
856 /* {{{ proto array snmpwalk(string host, string community, string object_id [, int timeout [, int retries]])
857    Return all objects under the specified object id */
PHP_FUNCTION(snmpwalk)858 PHP_FUNCTION(snmpwalk)
859 {
860 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU,SNMP_CMD_WALK, SNMP_VERSION_1);
861 }
862 /* }}} */
863 
864 /* {{{ proto array snmprealwalk(string host, string community, string object_id [, int timeout [, int retries]])
865    Return all objects including their respective object id withing the specified one */
PHP_FUNCTION(snmprealwalk)866 PHP_FUNCTION(snmprealwalk)
867 {
868 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU,SNMP_CMD_REALWALK, SNMP_VERSION_1);
869 }
870 /* }}} */
871 
872 /* {{{ proto bool snmp_get_quick_print(void)
873    Return the current status of quick_print */
PHP_FUNCTION(snmp_get_quick_print)874 PHP_FUNCTION(snmp_get_quick_print)
875 {
876 	if (zend_parse_parameters_none() == FAILURE) {
877 		return;
878 	}
879 
880 #ifdef HAVE_NET_SNMP
881 	RETURN_BOOL(netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT));
882 #else
883 	RETURN_BOOL(snmp_get_quick_print());
884 #endif
885 }
886 /* }}} */
887 
888 /* {{{ proto void snmp_set_quick_print(int quick_print)
889    Return all objects including their respective object id withing the specified one */
PHP_FUNCTION(snmp_set_quick_print)890 PHP_FUNCTION(snmp_set_quick_print)
891 {
892 	long a1;
893 
894 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &a1) == FAILURE) {
895 		return;
896 	}
897 
898 #ifdef HAVE_NET_SNMP
899 	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, (int) a1);
900 #else
901 	snmp_set_quick_print((int)a1);
902 #endif
903 }
904 /* }}} */
905 
906 #ifdef HAVE_NET_SNMP
907 /* {{{ proto void snmp_set_enum_print(int enum_print)
908    Return all values that are enums with their enum value instead of the raw integer */
PHP_FUNCTION(snmp_set_enum_print)909 PHP_FUNCTION(snmp_set_enum_print)
910 {
911 	long a1;
912 
913 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &a1) == FAILURE) {
914 		return;
915 	}
916 
917 	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, (int) a1);
918 }
919 /* }}} */
920 
921 /* {{{ proto void snmp_set_oid_output_format(int oid_format)
922    Set the OID output format. */
PHP_FUNCTION(snmp_set_oid_output_format)923 PHP_FUNCTION(snmp_set_oid_output_format)
924 {
925 	long a1;
926 
927 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &a1) == FAILURE) {
928 		return;
929 	}
930 
931 	switch ((int) a1) {
932 		case 0:
933 		case NETSNMP_OID_OUTPUT_FULL:
934 			a1 = NETSNMP_OID_OUTPUT_FULL;
935 			break;
936 
937 		default:
938 		case NETSNMP_OID_OUTPUT_NUMERIC:
939 			a1 = NETSNMP_OID_OUTPUT_NUMERIC;
940 			break;
941 	}
942 
943 	netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, a1);
944 }
945 /* }}} */
946 #endif
947 
948 /* {{{ proto int snmpset(string host, string community, string object_id, string type, mixed value [, int timeout [, int retries]])
949    Set the value of a SNMP object */
PHP_FUNCTION(snmpset)950 PHP_FUNCTION(snmpset)
951 {
952 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU,SNMP_CMD_SET, SNMP_VERSION_1);
953 }
954 /* }}} */
955 
956 /* {{{ int netsnmp_session_set_sec_name(struct snmp_session *s, char *name)
957    Set the security name in the snmpv3 session */
netsnmp_session_set_sec_name(struct snmp_session * s,char * name)958 static int netsnmp_session_set_sec_name(struct snmp_session *s, char *name)
959 {
960 	if ((s) && (name)) {
961 		s->securityName = strdup(name);
962 		s->securityNameLen = strlen(s->securityName);
963 		return (0);
964 	}
965 	return (-1);
966 }
967 /* }}} */
968 
969 /* {{{ int netsnmp_session_set_sec_level(struct snmp_session *s, char *level)
970    Set the security level in the snmpv3 session */
netsnmp_session_set_sec_level(struct snmp_session * s,char * level TSRMLS_DC)971 static int netsnmp_session_set_sec_level(struct snmp_session *s, char *level TSRMLS_DC)
972 {
973 	if ((s) && (level)) {
974 		if (!strcasecmp(level, "noAuthNoPriv") || !strcasecmp(level, "nanp")) {
975 			s->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
976 			return (0);
977 		} else if (!strcasecmp(level, "authNoPriv") || !strcasecmp(level, "anp")) {
978 			s->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
979 			return (0);
980 		} else if (!strcasecmp(level, "authPriv") || !strcasecmp(level, "ap")) {
981 			s->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
982 			return (0);
983 		}
984 	}
985 	return (-1);
986 }
987 /* }}} */
988 
989 /* {{{ int netsnmp_session_set_auth_protocol(struct snmp_session *s, char *prot)
990    Set the authentication protocol in the snmpv3 session */
netsnmp_session_set_auth_protocol(struct snmp_session * s,char * prot TSRMLS_DC)991 static int netsnmp_session_set_auth_protocol(struct snmp_session *s, char *prot TSRMLS_DC)
992 {
993 	if ((s) && (prot)) {
994 		if (!strcasecmp(prot, "MD5")) {
995 			s->securityAuthProto = usmHMACMD5AuthProtocol;
996 			s->securityAuthProtoLen = OIDSIZE(usmHMACMD5AuthProtocol);
997 			return (0);
998 		} else if (!strcasecmp(prot, "SHA")) {
999 			s->securityAuthProto = usmHMACSHA1AuthProtocol;
1000 			s->securityAuthProtoLen = OIDSIZE(usmHMACSHA1AuthProtocol);
1001 			return (0);
1002 		}
1003 	}
1004 	return (-1);
1005 }
1006 /* }}} */
1007 
1008 /* {{{ int netsnmp_session_set_sec_protocol(struct snmp_session *s, char *prot)
1009    Set the security protocol in the snmpv3 session */
netsnmp_session_set_sec_protocol(struct snmp_session * s,char * prot TSRMLS_DC)1010 static int netsnmp_session_set_sec_protocol(struct snmp_session *s, char *prot TSRMLS_DC)
1011 {
1012 	if ((s) && (prot)) {
1013 		if (!strcasecmp(prot, "DES")) {
1014 			s->securityPrivProto = usmDESPrivProtocol;
1015 			s->securityPrivProtoLen = OIDSIZE(usmDESPrivProtocol);
1016 			return (0);
1017 #ifdef HAVE_AES
1018 		} else if (!strcasecmp(prot, "AES128")
1019 #ifdef SNMP_VALIDATE_ERR
1020 /*
1021 * In Net-SNMP before 5.2, the following symbols exist:
1022 * usmAES128PrivProtocol, usmAES192PrivProtocol, usmAES256PrivProtocol
1023 * In an effort to be more standards-compliant, 5.2 removed the last two.
1024 * As of 5.2, the symbols are:
1025 * usmAESPrivProtocol, usmAES128PrivProtocol
1026 *
1027 * As we want this extension to compile on both versions, we use the latter
1028 * symbol on purpose, as it's defined to be the same as the former.
1029 *
1030 * However, in 5.2 the type of usmAES128PrivProtocol is a pointer, not an
1031 * array, so we cannot use the OIDSIZE macro because it uses sizeof().
1032 *
1033 */
1034 			|| !strcasecmp(prot, "AES")) {
1035 			s->securityPrivProto = usmAES128PrivProtocol;
1036 			s->securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN;
1037 			return (0);
1038 #else
1039 		) {
1040 			s->securityPrivProto = usmAES128PrivProtocol;
1041 			s->securityPrivProtoLen = OIDSIZE(usmAES128PrivProtocol);
1042 			return (0);
1043 		} else if (!strcasecmp(prot, "AES192")) {
1044 			s->securityPrivProto = usmAES192PrivProtocol;
1045 			s->securityPrivProtoLen = OIDSIZE(usmAES192PrivProtocol);
1046 			return (0);
1047 		} else if (!strcasecmp(prot, "AES256")) {
1048 			s->securityPrivProto = usmAES256PrivProtocol;
1049 			s->securityPrivProtoLen = OIDSIZE(usmAES256PrivProtocol);
1050 			return (0);
1051 #endif
1052 #endif
1053 		}
1054 	}
1055 	return (-1);
1056 }
1057 /* }}} */
1058 
1059 /* {{{ int netsnmp_session_gen_auth_key(struct snmp_session *s, char *pass)
1060    Make key from pass phrase in the snmpv3 session */
1061 static int netsnmp_session_gen_auth_key(struct snmp_session *s, char *pass TSRMLS_DC)
1062 {
1063 	/*
1064 	 * make master key from pass phrases
1065 	 */
1066 	if ((s) && (pass) && strlen(pass)) {
1067 		s->securityAuthKeyLen = USM_AUTH_KU_LEN;
1068 		if (s->securityAuthProto == NULL) {
1069 			/* get .conf set default */
1070 			const oid *def = get_default_authtype(&(s->securityAuthProtoLen));
1071 			s->securityAuthProto = snmp_duplicate_objid(def, s->securityAuthProtoLen);
1072 		}
1073 		if (s->securityAuthProto == NULL) {
1074 			/* assume MD5 */
1075 			s->securityAuthProto =
1076 				snmp_duplicate_objid(usmHMACMD5AuthProtocol, OIDSIZE(usmHMACMD5AuthProtocol));
1077 			s->securityAuthProtoLen = OIDSIZE(usmHMACMD5AuthProtocol);
1078 		}
1079 		if (generate_Ku(s->securityAuthProto, s->securityAuthProtoLen,
1080 				(u_char *) pass, strlen(pass),
1081 				s->securityAuthKey, &(s->securityAuthKeyLen)) != SNMPERR_SUCCESS) {
1082 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error generating a key for authentication pass phrase");
1083 			return (-2);
1084 		}
1085 		return (0);
1086 	}
1087 	return (-1);
1088 }
1089 /* }}} */
1090 
1091 /* {{{ int netsnmp_session_gen_sec_key(struct snmp_session *s, u_char *pass)
1092    Make key from pass phrase in the snmpv3 session */
1093 static int netsnmp_session_gen_sec_key(struct snmp_session *s, u_char *pass TSRMLS_DC)
1094 {
1095 	if ((s) && (pass) && strlen(pass)) {
1096 		s->securityPrivKeyLen = USM_PRIV_KU_LEN;
1097 		if (s->securityPrivProto == NULL) {
1098 			/* get .conf set default */
1099 			const oid *def = get_default_privtype(&(s->securityPrivProtoLen));
1100 			s->securityPrivProto = snmp_duplicate_objid(def, s->securityPrivProtoLen);
1101 		}
1102 		if (s->securityPrivProto == NULL) {
1103 			/* assume DES */
1104 			s->securityPrivProto = snmp_duplicate_objid(usmDESPrivProtocol,
1105 				OIDSIZE(usmDESPrivProtocol));
1106 			s->securityPrivProtoLen = OIDSIZE(usmDESPrivProtocol);
1107 		}
1108 		if (generate_Ku(s->securityAuthProto, s->securityAuthProtoLen,
1109 				pass, strlen(pass),
1110 				s->securityPrivKey, &(s->securityPrivKeyLen)) != SNMPERR_SUCCESS) {
1111 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error generating a key for privacy pass phrase");
1112 			return (-2);
1113 		}
1114 		return (0);
1115 	}
1116 	return (-1);
1117 }
1118 /* }}} */
1119 
1120 /* {{{ proto string snmp2_get(string host, string community, string object_id [, int timeout [, int retries]])
1121    Fetch a SNMP object */
1122 PHP_FUNCTION(snmp2_get)
1123 {
1124 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU,SNMP_CMD_GET, SNMP_VERSION_2c);
1125 }
1126 /* }}} */
1127 
1128 /* {{{ proto string snmp2_getnext(string host, string community, string object_id [, int timeout [, int retries]])
1129    Fetch a SNMP object */
1130 PHP_FUNCTION(snmp2_getnext)
1131 {
1132 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU,SNMP_CMD_GETNEXT, SNMP_VERSION_2c);
1133 }
1134 /* }}} */
1135 
1136 /* {{{ proto array snmp2_walk(string host, string community, string object_id [, int timeout [, int retries]])
1137    Return all objects under the specified object id */
1138 PHP_FUNCTION(snmp2_walk)
1139 {
1140 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU,SNMP_CMD_WALK, SNMP_VERSION_2c);
1141 }
1142 /* }}} */
1143 
1144 /* {{{ proto array snmp2_real_walk(string host, string community, string object_id [, int timeout [, int retries]])
1145    Return all objects including their respective object id withing the specified one */
1146 PHP_FUNCTION(snmp2_real_walk)
1147 {
1148 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU,SNMP_CMD_REALWALK, SNMP_VERSION_2c);
1149 }
1150 /* }}} */
1151 
1152 /* {{{ proto int snmp2_set(string host, string community, string object_id, string type, mixed value [, int timeout [, int retries]])
1153    Set the value of a SNMP object */
1154 PHP_FUNCTION(snmp2_set)
1155 {
1156 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU,SNMP_CMD_SET, SNMP_VERSION_2c);
1157 }
1158 /* }}} */
1159 
1160 /* {{{ proto void php_snmpv3(INTERNAL_FUNCTION_PARAMETERS, int st)
1161 *
1162 * Generic SNMPv3 object fetcher
1163 * From here is passed on the common internal object fetcher.
1164 *
1165 * st=SNMP_CMD_GET   snmp3_get() - query an agent and return a single value.
1166 * st=SNMP_CMD_GETNEXT   snmp3_getnext() - query an agent and return the next single value.
1167 * st=SNMP_CMD_WALK   snmp3_walk() - walk the mib and return a single dimensional array
1168 *                       containing the values.
1169 * st=SNMP_CMD_REALWALK   snmp3_real_walk() - walk the mib and return an
1170 *                            array of oid,value pairs.
1171 * st=SNMP_CMD_SET  snmp3_set() - query an agent and set a single value
1172 *
1173 */
1174 static void php_snmpv3(INTERNAL_FUNCTION_PARAMETERS, int st)
1175 {
1176 	char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
1177 	int a1_len, a2_len, a3_len, a4_len, a5_len, a6_len, a7_len, a8_len;
1178 	struct snmp_session session;
1179 	long timeout = SNMP_DEFAULT_TIMEOUT;
1180 	long retries = SNMP_DEFAULT_RETRIES;
1181 	char type = (char) 0;
1182 	char *value = (char *) 0, *stype = "";
1183 	int stype_len, value_len;
1184 	char hostname[MAX_NAME_LEN];
1185 	int remote_port = 161;
1186 	char *pptr;
1187 	int argc = ZEND_NUM_ARGS();
1188 
1189 	if (st == SNMP_CMD_SET) {
1190 		if (zend_parse_parameters(argc TSRMLS_CC, "ssssssssss|ll", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len,
1191 			&a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len, &a8, &a8_len, &stype, &stype_len, &value, &value_len, &timeout, &retries) == FAILURE) {
1192 			return;
1193 		}
1194 	} else {
1195 		/* SNMP_CMD_GET
1196 		 * SNMP_CMD_GETNEXT
1197 		 * SNMP_CMD_WALK
1198 		 * SNMP_CMD_REALWALK
1199 		 */
1200 		if (zend_parse_parameters(argc TSRMLS_CC, "ssssssss|ll", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len,
1201 			&a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len, &a8, &a8_len, &timeout, &retries) == FAILURE) {
1202 			return;
1203 		}
1204 	}
1205 
1206 	snmp_sess_init(&session);
1207 	/* This is all SNMPv3 */
1208 	session.version = SNMP_VERSION_3;
1209 
1210 	/* Reading the hostname and its optional non-default port number */
1211 	strlcpy(hostname, a1, sizeof(hostname));
1212 	if ((pptr = strchr(hostname, ':'))) {
1213 		remote_port = strtol(pptr + 1, NULL, 0);
1214 	}
1215 	session.peername = hostname;
1216 	session.remote_port = remote_port;
1217 
1218 	/* Setting the security name. */
1219 	if (netsnmp_session_set_sec_name(&session, a2)) {
1220 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could net set security name: %s", a2);
1221 		RETURN_FALSE;
1222 	}
1223 
1224 	/* Setting the security level. */
1225 	if (netsnmp_session_set_sec_level(&session, a3 TSRMLS_CC)) {
1226 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid security level: %s", a3);
1227 		RETURN_FALSE;
1228 	}
1229 
1230 	/* Setting the authentication protocol. */
1231 	if (netsnmp_session_set_auth_protocol(&session, a4 TSRMLS_CC)) {
1232 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid authentication protocol: %s", a4);
1233 		RETURN_FALSE;
1234 	}
1235 
1236 	/* Setting the authentication passphrase. */
1237 	if (netsnmp_session_gen_auth_key(&session, a5 TSRMLS_CC)) {
1238 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not generate key for authentication pass phrase: %s", a5);
1239 		RETURN_FALSE;
1240 	}
1241 
1242 	/* Setting the security protocol. */
1243 	if (netsnmp_session_set_sec_protocol(&session, a6 TSRMLS_CC) && a6_len) {
1244 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid security protocol: %s", a6);
1245 		RETURN_FALSE;
1246 	}
1247 
1248 	/* Setting the security protocol passphrase. */
1249 	if (netsnmp_session_gen_sec_key(&session, a7 TSRMLS_CC) && a7_len) {
1250 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not generate key for security pass phrase: %s", a7);
1251 		RETURN_FALSE;
1252 	}
1253 
1254 	if (st == SNMP_CMD_SET) {
1255 		type = stype[0];
1256 	}
1257 
1258 	session.retries = retries;
1259 	session.timeout = timeout;
1260 
1261 	php_snmp_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, st, &session, a8, type, value);
1262 }
1263 /* }}} */
1264 
1265 /* {{{ proto int snmp3_get(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, string object_id [, int timeout [, int retries]])
1266    Fetch the value of a SNMP object */
1267 PHP_FUNCTION(snmp3_get)
1268 {
1269 	php_snmpv3(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET);
1270 }
1271 /* }}} */
1272 
1273 /* {{{ proto int snmp3_getnext(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, string object_id [, int timeout [, int retries]])
1274    Fetch the value of a SNMP object */
1275 PHP_FUNCTION(snmp3_getnext)
1276 {
1277 	php_snmpv3(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT);
1278 }
1279 /* }}} */
1280 
1281 /* {{{ proto int snmp3_walk(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, string object_id [, int timeout [, int retries]])
1282    Fetch the value of a SNMP object */
1283 PHP_FUNCTION(snmp3_walk)
1284 {
1285 	php_snmpv3(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK);
1286 }
1287 /* }}} */
1288 
1289 /* {{{ proto int snmp3_real_walk(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, string object_id [, int timeout [, int retries]])
1290    Fetch the value of a SNMP object */
1291 PHP_FUNCTION(snmp3_real_walk)
1292 {
1293 	php_snmpv3(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_REALWALK);
1294 }
1295 /* }}} */
1296 
1297 /* {{{ proto int snmp3_set(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, string object_id, string type, mixed value [, int timeout [, int retries]])
1298    Fetch the value of a SNMP object */
1299 PHP_FUNCTION(snmp3_set)
1300 {
1301 	php_snmpv3(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET);
1302 }
1303 /* }}} */
1304 
1305 /* {{{ proto void snmp_set_valueretrieval(int method)
1306    Specify the method how the SNMP values will be returned */
1307 PHP_FUNCTION(snmp_set_valueretrieval)
1308 {
1309 	long method;
1310 
1311 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method) == FAILURE) {
1312 		return;
1313 	}
1314 
1315 	if ((method == SNMP_VALUE_LIBRARY) || (method == SNMP_VALUE_PLAIN) || (method == SNMP_VALUE_OBJECT)) {
1316 		SNMP_G(valueretrieval) = method;
1317 	}
1318 }
1319 /* }}} */
1320 
1321 /* {{{ proto int snmp_get_valueretrieval()
1322    Return the method how the SNMP values will be returned */
1323 PHP_FUNCTION(snmp_get_valueretrieval)
1324 {
1325 	RETURN_LONG(SNMP_G(valueretrieval));
1326 }
1327 /* }}} */
1328 
1329 /* {{{ proto int snmp_read_mib(string filename)
1330    Reads and parses a MIB file into the active MIB tree. */
1331 PHP_FUNCTION(snmp_read_mib)
1332 {
1333 	char *filename;
1334 	int filename_len;
1335 
1336 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
1337 		return;
1338 	}
1339 
1340 	/* Prevent read_mib() from printing any errors. */
1341 	snmp_disable_stderrlog();
1342 
1343 	if (!read_mib(filename)) {
1344 		char *error = strerror(errno);
1345 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading MIB file '%s': %s", filename, error);
1346 		RETURN_FALSE;
1347 	}
1348 	RETURN_TRUE;
1349 }
1350 /* }}} */
1351 
1352 #endif
1353 
1354 /*
1355  * Local variables:
1356  * tab-width: 4
1357  * c-basic-offset: 4
1358  * End:
1359  * vim600: sw=4 ts=4 fdm=marker
1360  * vim<600: sw=4 ts=4
1361  */
1362