xref: /PHP-8.0/ext/snmp/snmp.c (revision f9fd3595)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | http://www.php.net/license/3_01.txt                                  |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
14    |          Mike Jackson <mhjack@tscnet.com>                            |
15    |          Steven Lawrance <slawrance@technologist.com>                |
16    |          Harrie Hazewinkel <harrie@lisanza.net>                      |
17    |          Johann Hanne <jonny@nurfuerspam.de>                         |
18    |          Boris Lytockin <lytboris@gmail.com>                         |
19    +----------------------------------------------------------------------+
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "php.h"
27 #include "main/php_network.h"
28 #include "ext/standard/info.h"
29 #include "php_snmp.h"
30 
31 #include "zend_exceptions.h"
32 #include "ext/spl/spl_exceptions.h"
33 #include "snmp_arginfo.h"
34 
35 #if HAVE_SNMP
36 
37 #include <sys/types.h>
38 #include <errno.h>
39 #ifdef PHP_WIN32
40 #include <winsock2.h>
41 #include <process.h>
42 #include "win32/time.h"
43 #else
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <netdb.h>
48 #endif
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #include <locale.h>
53 
54 #ifndef __P
55 #ifdef __GNUC__
56 #define __P(args) args
57 #else
58 #define __P(args) ()
59 #endif
60 #endif
61 
62 #include <net-snmp/net-snmp-config.h>
63 #include <net-snmp/net-snmp-includes.h>
64 
65 /* For net-snmp prior to 5.4 */
66 #ifndef HAVE_SHUTDOWN_SNMP_LOGGING
67 extern netsnmp_log_handler *logh_head;
68 #define shutdown_snmp_logging() \
69 	{ \
70 		snmp_disable_log(); \
71 		while(NULL != logh_head) \
72 			netsnmp_remove_loghandler( logh_head ); \
73 	}
74 #endif
75 
76 #define SNMP_VALUE_LIBRARY	(0 << 0)
77 #define SNMP_VALUE_PLAIN	(1 << 0)
78 #define SNMP_VALUE_OBJECT	(1 << 1)
79 
80 typedef struct snmp_session php_snmp_session;
81 
82 #define PHP_SNMP_ADD_PROPERTIES(a, b) \
83 { \
84 	int i = 0; \
85 	while (b[i].name != NULL) { \
86 		php_snmp_add_property((a), (b)[i].name, (b)[i].name_length, \
87 							(php_snmp_read_t)(b)[i].read_func, (php_snmp_write_t)(b)[i].write_func); \
88 		i++; \
89 	} \
90 }
91 
92 #define PHP_SNMP_ERRNO_NOERROR			0
93 #define PHP_SNMP_ERRNO_GENERIC			(1 << 1)
94 #define PHP_SNMP_ERRNO_TIMEOUT			(1 << 2)
95 #define PHP_SNMP_ERRNO_ERROR_IN_REPLY		(1 << 3)
96 #define PHP_SNMP_ERRNO_OID_NOT_INCREASING	(1 << 4)
97 #define PHP_SNMP_ERRNO_OID_PARSING_ERROR	(1 << 5)
98 #define PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES	(1 << 6)
99 #define PHP_SNMP_ERRNO_ANY	( \
100 		PHP_SNMP_ERRNO_GENERIC | \
101 		PHP_SNMP_ERRNO_TIMEOUT | \
102 		PHP_SNMP_ERRNO_ERROR_IN_REPLY | \
103 		PHP_SNMP_ERRNO_OID_NOT_INCREASING | \
104 		PHP_SNMP_ERRNO_OID_PARSING_ERROR | \
105 		PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES | \
106 		PHP_SNMP_ERRNO_NOERROR \
107 	)
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 /* Handlers */
116 static zend_object_handlers php_snmp_object_handlers;
117 
118 /* Class entries */
119 zend_class_entry *php_snmp_ce;
120 zend_class_entry *php_snmp_exception_ce;
121 
122 /* Class object properties */
123 static HashTable php_snmp_properties;
124 
125 struct objid_query {
126 	int count;
127 	int offset;
128 	int step;
129 	zend_long non_repeaters;
130 	zend_long max_repetitions;
131 	int valueretrieval;
132 	int array_output;
133 	int oid_increasing_check;
134 	snmpobjarg *vars;
135 };
136 
137 /* query an agent with GET method */
138 #define SNMP_CMD_GET		(1<<0)
139 /* query an agent with GETNEXT method */
140 #define SNMP_CMD_GETNEXT	(1<<1)
141 /* query an agent with SET method */
142 #define SNMP_CMD_SET		(1<<2)
143 /* walk the mib */
144 #define SNMP_CMD_WALK		(1<<3)
145 /* force values-only output */
146 #define SNMP_NUMERIC_KEYS	(1<<7)
147 /* use user-supplied OID names for keys in array output mode in GET method */
148 #define SNMP_ORIGINAL_NAMES_AS_KEYS	(1<<8)
149 /* use OID suffix (`index') for keys in array output mode in WALK  method */
150 #define SNMP_USE_SUFFIX_AS_KEYS	(1<<9)
151 
152 #ifdef COMPILE_DL_SNMP
153 ZEND_GET_MODULE(snmp)
154 #endif
155 
156 /* THREAD_LS snmp_module php_snmp_module; - may need one of these at some point */
157 
158 /* {{{ PHP_GINIT_FUNCTION */
PHP_GINIT_FUNCTION(snmp)159 static PHP_GINIT_FUNCTION(snmp)
160 {
161 	snmp_globals->valueretrieval = SNMP_VALUE_LIBRARY;
162 }
163 /* }}} */
164 
165 #define PHP_SNMP_SESSION_FREE(a) { \
166 	if ((*session)->a) { \
167 		efree((*session)->a); \
168 		(*session)->a = NULL; \
169 	} \
170 }
171 
netsnmp_session_free(php_snmp_session ** session)172 static void netsnmp_session_free(php_snmp_session **session) /* {{{ */
173 {
174 	if (*session) {
175 		PHP_SNMP_SESSION_FREE(peername);
176 		PHP_SNMP_SESSION_FREE(community);
177 		PHP_SNMP_SESSION_FREE(securityName);
178 		PHP_SNMP_SESSION_FREE(contextEngineID);
179 		efree(*session);
180 		*session = NULL;
181 	}
182 }
183 /* }}} */
184 
php_snmp_object_free_storage(zend_object * object)185 static void php_snmp_object_free_storage(zend_object *object) /* {{{ */
186 {
187 	php_snmp_object *intern = php_snmp_fetch_object(object);
188 
189 	if (!intern) {
190 		return;
191 	}
192 
193 	netsnmp_session_free(&(intern->session));
194 
195 	zend_object_std_dtor(&intern->zo);
196 }
197 /* }}} */
198 
php_snmp_object_new(zend_class_entry * class_type)199 static zend_object *php_snmp_object_new(zend_class_entry *class_type) /* {{{ */
200 {
201 	php_snmp_object *intern;
202 
203 	/* Allocate memory for it */
204 	intern = zend_object_alloc(sizeof(php_snmp_object), class_type);
205 
206 	zend_object_std_init(&intern->zo, class_type);
207 	object_properties_init(&intern->zo, class_type);
208 
209 	intern->zo.handlers = &php_snmp_object_handlers;
210 
211 	return &intern->zo;
212 
213 }
214 /* }}} */
215 
216 /* {{{ php_snmp_error
217  *
218  * Record last SNMP-related error in object
219  *
220  */
php_snmp_error(zval * object,int type,const char * format,...)221 static void php_snmp_error(zval *object, int type, const char *format, ...)
222 {
223 	va_list args;
224 	php_snmp_object *snmp_object = NULL;
225 
226 	if (object) {
227 		snmp_object = Z_SNMP_P(object);
228 		if (type == PHP_SNMP_ERRNO_NOERROR) {
229 			memset(snmp_object->snmp_errstr, 0, sizeof(snmp_object->snmp_errstr));
230 		} else {
231 			va_start(args, format);
232 			vsnprintf(snmp_object->snmp_errstr, sizeof(snmp_object->snmp_errstr) - 1, format, args);
233 			va_end(args);
234 		}
235 		snmp_object->snmp_errno = type;
236 	}
237 
238 	if (type == PHP_SNMP_ERRNO_NOERROR) {
239 		return;
240 	}
241 
242 	if (object && (snmp_object->exceptions_enabled & type)) {
243 		zend_throw_exception_ex(php_snmp_exception_ce, type, "%s", snmp_object->snmp_errstr);
244 	} else {
245 		va_start(args, format);
246 		php_verror(NULL, "", E_WARNING, format, args);
247 		va_end(args);
248 	}
249 }
250 
251 /* }}} */
252 
253 /* {{{ php_snmp_getvalue
254 *
255 * SNMP value to zval converter
256 *
257 */
php_snmp_getvalue(struct variable_list * vars,zval * snmpval,int valueretrieval)258 static void php_snmp_getvalue(struct variable_list *vars, zval *snmpval, int valueretrieval)
259 {
260 	zval val;
261 	char sbuf[512];
262 	char *buf = &(sbuf[0]);
263 	char *dbuf = (char *)NULL;
264 	int buflen = sizeof(sbuf) - 1;
265 	int val_len = vars->val_len;
266 
267 	/* use emalloc() for large values, use static array otherwise */
268 
269 	/* There is no way to know the size of buffer snprint_value() needs in order to print a value there.
270 	 * So we are forced to probe it
271 	 */
272 	while ((valueretrieval & SNMP_VALUE_PLAIN) == 0) {
273 		*buf = '\0';
274 		if (snprint_value(buf, buflen, vars->name, vars->name_length, vars) == -1) {
275 			if (val_len > 512*1024) {
276 				php_error_docref(NULL, E_WARNING, "snprint_value() asks for a buffer more than 512k, Net-SNMP bug?");
277 				break;
278 			}
279 			 /* buffer is not long enough to hold full output, double it */
280 			val_len *= 2;
281 		} else {
282 			break;
283 		}
284 
285 		if (buf == dbuf) {
286 			dbuf = (char *)erealloc(dbuf, val_len + 1);
287 		} else {
288 			dbuf = (char *)emalloc(val_len + 1);
289 		}
290 
291 		buf = dbuf;
292 		buflen = val_len;
293 	}
294 
295 	if((valueretrieval & SNMP_VALUE_PLAIN) && val_len > buflen){
296 		dbuf = (char *)emalloc(val_len + 1);
297 		buf = dbuf;
298 		buflen = val_len;
299 	}
300 
301 	if (valueretrieval & SNMP_VALUE_PLAIN) {
302 		*buf = 0;
303 		switch (vars->type) {
304 		case ASN_BIT_STR:		/* 0x03, asn1.h */
305 			ZVAL_STRINGL(&val, (char *)vars->val.bitstring, vars->val_len);
306 			break;
307 
308 		case ASN_OCTET_STR:		/* 0x04, asn1.h */
309 		case ASN_OPAQUE:		/* 0x44, snmp_impl.h */
310 			ZVAL_STRINGL(&val, (char *)vars->val.string, vars->val_len);
311 			break;
312 
313 		case ASN_NULL:			/* 0x05, asn1.h */
314 			ZVAL_NULL(&val);
315 			break;
316 
317 		case ASN_OBJECT_ID:		/* 0x06, asn1.h */
318 			snprint_objid(buf, buflen, vars->val.objid, vars->val_len / sizeof(oid));
319 			ZVAL_STRING(&val, buf);
320 			break;
321 
322 		case ASN_IPADDRESS:		/* 0x40, snmp_impl.h */
323 			snprintf(buf, buflen, "%d.%d.%d.%d",
324 				 (vars->val.string)[0], (vars->val.string)[1],
325 				 (vars->val.string)[2], (vars->val.string)[3]);
326 			buf[buflen]=0;
327 			ZVAL_STRING(&val, buf);
328 			break;
329 
330 		case ASN_COUNTER:		/* 0x41, snmp_impl.h */
331 		case ASN_GAUGE:			/* 0x42, snmp_impl.h */
332 		/* ASN_UNSIGNED is the same as ASN_GAUGE */
333 		case ASN_TIMETICKS:		/* 0x43, snmp_impl.h */
334 		case ASN_UINTEGER:		/* 0x47, snmp_impl.h */
335 			snprintf(buf, buflen, "%lu", *vars->val.integer);
336 			buf[buflen]=0;
337 			ZVAL_STRING(&val, buf);
338 			break;
339 
340 		case ASN_INTEGER:		/* 0x02, asn1.h */
341 			snprintf(buf, buflen, "%ld", *vars->val.integer);
342 			buf[buflen]=0;
343 			ZVAL_STRING(&val, buf);
344 			break;
345 
346 #if defined(NETSNMP_WITH_OPAQUE_SPECIAL_TYPES) || defined(OPAQUE_SPECIAL_TYPES)
347 		case ASN_OPAQUE_FLOAT:		/* 0x78, asn1.h */
348 			snprintf(buf, buflen, "%f", *vars->val.floatVal);
349 			ZVAL_STRING(&val, buf);
350 			break;
351 
352 		case ASN_OPAQUE_DOUBLE:		/* 0x79, asn1.h */
353 			snprintf(buf, buflen, "%f", *vars->val.doubleVal);
354 			ZVAL_STRING(&val, buf);
355 			break;
356 
357 		case ASN_OPAQUE_I64:		/* 0x80, asn1.h */
358 			printI64(buf, vars->val.counter64);
359 			ZVAL_STRING(&val, buf);
360 			break;
361 
362 		case ASN_OPAQUE_U64:		/* 0x81, asn1.h */
363 #endif
364 		case ASN_COUNTER64:		/* 0x46, snmp_impl.h */
365 			printU64(buf, vars->val.counter64);
366 			ZVAL_STRING(&val, buf);
367 			break;
368 
369 		default:
370 			ZVAL_STRING(&val, "Unknown value type");
371 			php_error_docref(NULL, E_WARNING, "Unknown value type: %u", vars->type);
372 			break;
373 		}
374 	} else /* use Net-SNMP value translation */ {
375 		/* we have desired string in buffer, just use it */
376 		ZVAL_STRING(&val, buf);
377 	}
378 
379 	if (valueretrieval & SNMP_VALUE_OBJECT) {
380 		object_init(snmpval);
381 		add_property_long(snmpval, "type", vars->type);
382 		add_property_zval(snmpval, "value", &val);
383 	} else  {
384 		ZVAL_COPY(snmpval, &val);
385 	}
386 	zval_ptr_dtor(&val);
387 
388 	if (dbuf){ /* malloc was used to store value */
389 		efree(dbuf);
390 	}
391 }
392 /* }}} */
393 
394 /* {{{ php_snmp_internal
395 *
396 * SNMP object fetcher/setter for all SNMP versions
397 *
398 */
php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS,int st,struct snmp_session * session,struct objid_query * objid_query)399 static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st,
400 							struct snmp_session *session,
401 							struct objid_query *objid_query)
402 {
403 	struct snmp_session *ss;
404 	struct snmp_pdu *pdu=NULL, *response;
405 	struct variable_list *vars;
406 	oid root[MAX_NAME_LEN];
407 	size_t rootlen = 0;
408 	int status, count, found;
409 	char buf[2048];
410 	char buf2[2048];
411 	int keepwalking=1;
412 	char *err;
413 	zval snmpval;
414 	int snmp_errno;
415 
416 	/* we start with retval=FALSE. If any actual data is acquired, retval will be set to appropriate type */
417 	RETVAL_FALSE;
418 
419 	/* reset errno and errstr */
420 	php_snmp_error(getThis(), PHP_SNMP_ERRNO_NOERROR, "");
421 
422 	if (st & SNMP_CMD_WALK) { /* remember root OID */
423 		memmove((char *)root, (char *)(objid_query->vars[0].name), (objid_query->vars[0].name_length) * sizeof(oid));
424 		rootlen = objid_query->vars[0].name_length;
425 		objid_query->offset = objid_query->count;
426 	}
427 
428 	if ((ss = snmp_open(session)) == NULL) {
429 		snmp_error(session, NULL, NULL, &err);
430 		php_error_docref(NULL, E_WARNING, "Could not open snmp connection: %s", err);
431 		free(err);
432 		RETVAL_FALSE;
433 		return;
434 	}
435 
436 	if ((st & SNMP_CMD_SET) && objid_query->count > objid_query->step) {
437 		php_snmp_error(getThis(), PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES, "Can not fit all OIDs for SET query into one packet, using multiple queries");
438 	}
439 
440 	while (keepwalking) {
441 		keepwalking = 0;
442 		if (st & SNMP_CMD_WALK) {
443 			if (session->version == SNMP_VERSION_1) {
444 				pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
445 			} else {
446 				pdu = snmp_pdu_create(SNMP_MSG_GETBULK);
447 				pdu->non_repeaters = objid_query->non_repeaters;
448 				pdu->max_repetitions = objid_query->max_repetitions;
449 			}
450 			snmp_add_null_var(pdu, objid_query->vars[0].name, objid_query->vars[0].name_length);
451 		} else {
452 			if (st & SNMP_CMD_GET) {
453 				pdu = snmp_pdu_create(SNMP_MSG_GET);
454 			} else if (st & SNMP_CMD_GETNEXT) {
455 				pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
456 			} else if (st & SNMP_CMD_SET) {
457 				pdu = snmp_pdu_create(SNMP_MSG_SET);
458 			} else {
459 				snmp_close(ss);
460 				php_error_docref(NULL, E_ERROR, "Unknown SNMP command (internals)");
461 				RETVAL_FALSE;
462 				return;
463 			}
464 			for (count = 0; objid_query->offset < objid_query->count && count < objid_query->step; objid_query->offset++, count++){
465 				if (st & SNMP_CMD_SET) {
466 					if ((snmp_errno = snmp_add_var(pdu, objid_query->vars[objid_query->offset].name, objid_query->vars[objid_query->offset].name_length, objid_query->vars[objid_query->offset].type, objid_query->vars[objid_query->offset].value))) {
467 						snprint_objid(buf, sizeof(buf), objid_query->vars[objid_query->offset].name, objid_query->vars[objid_query->offset].name_length);
468 						php_snmp_error(getThis(), PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Could not add variable: OID='%s' type='%c' value='%s': %s", buf, objid_query->vars[objid_query->offset].type, objid_query->vars[objid_query->offset].value, snmp_api_errstring(snmp_errno));
469 						snmp_free_pdu(pdu);
470 						snmp_close(ss);
471 						RETVAL_FALSE;
472 						return;
473 					}
474 				} else {
475 					snmp_add_null_var(pdu, objid_query->vars[objid_query->offset].name, objid_query->vars[objid_query->offset].name_length);
476 				}
477 			}
478 			if(pdu->variables == NULL){
479 				snmp_free_pdu(pdu);
480 				snmp_close(ss);
481 				RETVAL_FALSE;
482 				return;
483 			}
484 		}
485 
486 retry:
487 		status = snmp_synch_response(ss, pdu, &response);
488 		if (status == STAT_SUCCESS) {
489 			if (response->errstat == SNMP_ERR_NOERROR) {
490 				if (st & SNMP_CMD_SET) {
491 					if (objid_query->offset < objid_query->count) { /* we have unprocessed OIDs */
492 						keepwalking = 1;
493 						snmp_free_pdu(response);
494 						continue;
495 					}
496 					snmp_free_pdu(response);
497 					snmp_close(ss);
498 					RETVAL_TRUE;
499 					return;
500 				}
501 				for (vars = response->variables; vars; vars = vars->next_variable) {
502 					/* do not output errors as values */
503 					if ( 	vars->type == SNMP_ENDOFMIBVIEW ||
504 						vars->type == SNMP_NOSUCHOBJECT ||
505 						vars->type == SNMP_NOSUCHINSTANCE ) {
506 						if ((st & SNMP_CMD_WALK) && Z_TYPE_P(return_value) == IS_ARRAY) {
507 							break;
508 						}
509 						snprint_objid(buf, sizeof(buf), vars->name, vars->name_length);
510 						snprint_value(buf2, sizeof(buf2), vars->name, vars->name_length, vars);
511 						php_snmp_error(getThis(), PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at '%s': %s", buf, buf2);
512 						continue;
513 					}
514 
515 					if ((st & SNMP_CMD_WALK) &&
516 						(vars->name_length < rootlen || memcmp(root, vars->name, rootlen * sizeof(oid)))) { /* not part of this subtree */
517 						if (Z_TYPE_P(return_value) == IS_ARRAY) { /* some records are fetched already, shut down further lookup */
518 							keepwalking = 0;
519 						} else {
520 							/* first fetched OID is out of subtree, fallback to GET query */
521 							st |= SNMP_CMD_GET;
522 							st ^= SNMP_CMD_WALK;
523 							objid_query->offset = 0;
524 							keepwalking = 1;
525 						}
526 						break;
527 					}
528 
529 					ZVAL_NULL(&snmpval);
530 					php_snmp_getvalue(vars, &snmpval, objid_query->valueretrieval);
531 
532 					if (objid_query->array_output) {
533 						if (Z_TYPE_P(return_value) == IS_TRUE || Z_TYPE_P(return_value) == IS_FALSE) {
534 							array_init(return_value);
535 						}
536 						if (st & SNMP_NUMERIC_KEYS) {
537 							add_next_index_zval(return_value, &snmpval);
538 						} else if (st & SNMP_ORIGINAL_NAMES_AS_KEYS && st & SNMP_CMD_GET) {
539 							found = 0;
540 							for (count = 0; count < objid_query->count; count++) {
541 								if (objid_query->vars[count].name_length == vars->name_length && snmp_oid_compare(objid_query->vars[count].name, objid_query->vars[count].name_length, vars->name, vars->name_length) == 0) {
542 									found = 1;
543 									objid_query->vars[count].name_length = 0; /* mark this name as used */
544 									break;
545 								}
546 							}
547 							if (found) {
548 								add_assoc_zval(return_value, objid_query->vars[count].oid, &snmpval);
549 							} else {
550 								snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
551 								php_error_docref(NULL, E_WARNING, "Could not find original OID name for '%s'", buf2);
552 							}
553 						} else if (st & SNMP_USE_SUFFIX_AS_KEYS && st & SNMP_CMD_WALK) {
554 							snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
555 							if (rootlen <= vars->name_length && snmp_oid_compare(root, rootlen, vars->name, rootlen) == 0) {
556 								buf2[0] = '\0';
557 								count = rootlen;
558 								while(count < vars->name_length){
559 									sprintf(buf, "%lu.", vars->name[count]);
560 									strcat(buf2, buf);
561 									count++;
562 								}
563 								buf2[strlen(buf2) - 1] = '\0'; /* remove trailing '.' */
564 							}
565 							add_assoc_zval(return_value, buf2, &snmpval);
566 						} else {
567 							snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
568 							add_assoc_zval(return_value, buf2, &snmpval);
569 						}
570 					} else {
571 						ZVAL_COPY_VALUE(return_value, &snmpval);
572 						break;
573 					}
574 
575 					/* OID increase check */
576 					if (st & SNMP_CMD_WALK) {
577 						if (objid_query->oid_increasing_check == TRUE && snmp_oid_compare(objid_query->vars[0].name, objid_query->vars[0].name_length, vars->name, vars->name_length) >= 0) {
578 							snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
579 							php_snmp_error(getThis(), PHP_SNMP_ERRNO_OID_NOT_INCREASING, "Error: OID not increasing: %s", buf2);
580 							keepwalking = 0;
581 						} else {
582 							memmove((char *)(objid_query->vars[0].name), (char *)vars->name, vars->name_length * sizeof(oid));
583 							objid_query->vars[0].name_length = vars->name_length;
584 							keepwalking = 1;
585 						}
586 					}
587 				}
588 				if (objid_query->offset < objid_query->count) { /* we have unprocessed OIDs */
589 					keepwalking = 1;
590 				}
591 			} else {
592 				if (st & SNMP_CMD_WALK && response->errstat == SNMP_ERR_TOOBIG && objid_query->max_repetitions > 1) { /* Answer will not fit into single packet */
593 					objid_query->max_repetitions /= 2;
594 					snmp_free_pdu(response);
595 					keepwalking = 1;
596 					continue;
597 				}
598 				if (!(st & SNMP_CMD_WALK) || response->errstat != SNMP_ERR_NOSUCHNAME || Z_TYPE_P(return_value) == IS_TRUE || Z_TYPE_P(return_value) == IS_FALSE) {
599 					for (count=1, vars = response->variables;
600 						vars && count != response->errindex;
601 						vars = vars->next_variable, count++);
602 
603 					if (st & (SNMP_CMD_GET | SNMP_CMD_GETNEXT) && response->errstat == SNMP_ERR_TOOBIG && objid_query->step > 1) { /* Answer will not fit into single packet */
604 						objid_query->offset = ((objid_query->offset > objid_query->step) ? (objid_query->offset - objid_query->step) : 0 );
605 						objid_query->step /= 2;
606 						snmp_free_pdu(response);
607 						keepwalking = 1;
608 						continue;
609 					}
610 					if (vars) {
611 						snprint_objid(buf, sizeof(buf), vars->name, vars->name_length);
612 						php_snmp_error(getThis(), PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at '%s': %s", buf, snmp_errstring(response->errstat));
613 					} else {
614 						php_snmp_error(getThis(), PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at %u object_id: %s", response->errindex, snmp_errstring(response->errstat));
615 					}
616 					if (st & (SNMP_CMD_GET | SNMP_CMD_GETNEXT)) { /* cut out bogus OID and retry */
617 						if ((pdu = snmp_fix_pdu(response, ((st & SNMP_CMD_GET) ? SNMP_MSG_GET : SNMP_MSG_GETNEXT) )) != NULL) {
618 							snmp_free_pdu(response);
619 							goto retry;
620 						}
621 					}
622 					snmp_free_pdu(response);
623 					snmp_close(ss);
624 					if (objid_query->array_output) {
625 						zval_ptr_dtor(return_value);
626 					}
627 					RETVAL_FALSE;
628 					return;
629 				}
630 			}
631 		} else if (status == STAT_TIMEOUT) {
632 			php_snmp_error(getThis(), PHP_SNMP_ERRNO_TIMEOUT, "No response from %s", session->peername);
633 			if (objid_query->array_output) {
634 				zval_ptr_dtor(return_value);
635 			}
636 			snmp_close(ss);
637 			RETVAL_FALSE;
638 			return;
639 		} else {    /* status == STAT_ERROR */
640 			snmp_error(ss, NULL, NULL, &err);
641 			php_snmp_error(getThis(), PHP_SNMP_ERRNO_GENERIC, "Fatal error: %s", err);
642 			free(err);
643 			if (objid_query->array_output) {
644 				zval_ptr_dtor(return_value);
645 			}
646 			snmp_close(ss);
647 			RETVAL_FALSE;
648 			return;
649 		}
650 		if (response) {
651 			snmp_free_pdu(response);
652 		}
653 	} /* keepwalking */
654 	snmp_close(ss);
655 }
656 /* }}} */
657 
658 /* {{{ php_snmp_parse_oid
659 *
660 * OID parser (and type, value for SNMP_SET command)
661 */
php_snmp_parse_oid(zval * object,int st,struct objid_query * objid_query,zend_string * oid_str,HashTable * oid_ht,zend_string * type_str,HashTable * type_ht,zend_string * value_str,HashTable * value_ht)662 static int php_snmp_parse_oid(
663 	zval *object, int st, struct objid_query *objid_query, zend_string *oid_str, HashTable *oid_ht,
664 	zend_string *type_str, HashTable *type_ht, zend_string *value_str, HashTable *value_ht
665 ) {
666 	char *pptr;
667 	uint32_t idx_type = 0, idx_value = 0;
668 	zval *tmp_oid, *tmp_type, *tmp_value;
669 
670 	objid_query->count = 0;
671 	objid_query->array_output = ((st & SNMP_CMD_WALK) ? TRUE : FALSE);
672 	if (oid_str) {
673 		objid_query->vars = (snmpobjarg *)emalloc(sizeof(snmpobjarg));
674 		objid_query->vars[objid_query->count].oid = ZSTR_VAL(oid_str);
675 		if (st & SNMP_CMD_SET) {
676 			if (type_ht) {
677 				zend_type_error("Type must be of type string when object ID is a string");
678 				efree(objid_query->vars);
679 				return FALSE;
680 			}
681 			if (value_ht) {
682 				zend_type_error("Value must be of type string when object ID is a string");
683 				efree(objid_query->vars);
684 				return FALSE;
685 			}
686 
687 			/* Both type and value must be valid strings */
688 			ZEND_ASSERT(type_str && value_str);
689 
690 			if (ZSTR_LEN(type_str) != 1) {
691 				zend_value_error("Type must be a single character");
692 				efree(objid_query->vars);
693 				return FALSE;
694 			}
695 			pptr = ZSTR_VAL(type_str);
696 			objid_query->vars[objid_query->count].type = *pptr;
697 			objid_query->vars[objid_query->count].value = ZSTR_VAL(value_str);
698 		}
699 		objid_query->count++;
700 	} else if (oid_ht) { /* we got objid array */
701 		if (zend_hash_num_elements(oid_ht) == 0) {
702 			zend_value_error("Array of object IDs cannot be empty");
703 			return FALSE;
704 		}
705 		objid_query->vars = (snmpobjarg *)safe_emalloc(sizeof(snmpobjarg), zend_hash_num_elements(oid_ht), 0);
706 		objid_query->array_output = ( (st & SNMP_CMD_SET) ? FALSE : TRUE );
707 		ZEND_HASH_FOREACH_VAL(oid_ht, tmp_oid) {
708 			convert_to_string_ex(tmp_oid);
709 			objid_query->vars[objid_query->count].oid = Z_STRVAL_P(tmp_oid);
710 			if (st & SNMP_CMD_SET) {
711 				if (type_str) {
712 					pptr = ZSTR_VAL(type_str);
713 					objid_query->vars[objid_query->count].type = *pptr;
714 				} else if (type_ht) {
715 					while (idx_type < type_ht->nNumUsed) {
716 						tmp_type = &type_ht->arData[idx_type].val;
717 						if (Z_TYPE_P(tmp_type) != IS_UNDEF) {
718 							break;
719 						}
720 						idx_type++;
721 					}
722 					if (idx_type < type_ht->nNumUsed) {
723 						convert_to_string_ex(tmp_type);
724 						if (Z_STRLEN_P(tmp_type) != 1) {
725 							zend_value_error("Type must be a single character");
726 							efree(objid_query->vars);
727 							return FALSE;
728 						}
729 						pptr = Z_STRVAL_P(tmp_type);
730 						objid_query->vars[objid_query->count].type = *pptr;
731 						idx_type++;
732 					} else {
733 						php_error_docref(NULL, E_WARNING, "'%s': no type set", Z_STRVAL_P(tmp_oid));
734 						efree(objid_query->vars);
735 						return FALSE;
736 					}
737 				}
738 
739 				if (value_str) {
740 					objid_query->vars[objid_query->count].value = ZSTR_VAL(value_str);
741 				} else if (value_ht) {
742 					while (idx_value < value_ht->nNumUsed) {
743 						tmp_value = &value_ht->arData[idx_value].val;
744 						if (Z_TYPE_P(tmp_value) != IS_UNDEF) {
745 							break;
746 						}
747 						idx_value++;
748 					}
749 					if (idx_value < value_ht->nNumUsed) {
750 						convert_to_string_ex(tmp_value);
751 						objid_query->vars[objid_query->count].value = Z_STRVAL_P(tmp_value);
752 						idx_value++;
753 					} else {
754 						php_error_docref(NULL, E_WARNING, "'%s': no value set", Z_STRVAL_P(tmp_oid));
755 						efree(objid_query->vars);
756 						return FALSE;
757 					}
758 				}
759 			}
760 			objid_query->count++;
761 		} ZEND_HASH_FOREACH_END();
762 	}
763 
764 	/* now parse all OIDs */
765 	if (st & SNMP_CMD_WALK) {
766 		if (objid_query->count > 1) {
767 			php_snmp_error(object, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Multi OID walks are not supported!");
768 			efree(objid_query->vars);
769 			return FALSE;
770 		}
771 		objid_query->vars[0].name_length = MAX_NAME_LEN;
772 		if (strlen(objid_query->vars[0].oid)) { /* on a walk, an empty string means top of tree - no error */
773 			if (!snmp_parse_oid(objid_query->vars[0].oid, objid_query->vars[0].name, &(objid_query->vars[0].name_length))) {
774 				php_snmp_error(object, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Invalid object identifier: %s", objid_query->vars[0].oid);
775 				efree(objid_query->vars);
776 				return FALSE;
777 			}
778 		} else {
779 			memmove((char *)objid_query->vars[0].name, (char *)objid_mib, sizeof(objid_mib));
780 			objid_query->vars[0].name_length = sizeof(objid_mib) / sizeof(oid);
781 		}
782 	} else {
783 		for (objid_query->offset = 0; objid_query->offset < objid_query->count; objid_query->offset++) {
784 			objid_query->vars[objid_query->offset].name_length = MAX_OID_LEN;
785 			if (!snmp_parse_oid(objid_query->vars[objid_query->offset].oid, objid_query->vars[objid_query->offset].name, &(objid_query->vars[objid_query->offset].name_length))) {
786 				php_snmp_error(object, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Invalid object identifier: %s", objid_query->vars[objid_query->offset].oid);
787 				efree(objid_query->vars);
788 				return FALSE;
789 			}
790 		}
791 	}
792 	objid_query->offset = 0;
793 	objid_query->step = objid_query->count;
794 	return (objid_query->count > 0);
795 }
796 /* }}} */
797 
798 /* {{{ netsnmp_session_init
799 	allocates memory for session and session->peername, caller should free it manually using netsnmp_session_free() and efree()
800 */
netsnmp_session_init(php_snmp_session ** session_p,int version,char * hostname,char * community,int timeout,int retries)801 static int netsnmp_session_init(php_snmp_session **session_p, int version, char *hostname, char *community, int timeout, int retries)
802 {
803 	php_snmp_session *session;
804 	char *pptr, *host_ptr;
805 	int force_ipv6 = FALSE; (void) force_ipv6;
806 	int n;
807 	struct sockaddr **psal;
808 	struct sockaddr **res;
809 	// TODO: Do not strip and re-add the port in peername?
810 	unsigned remote_port = SNMP_PORT;
811 
812 	*session_p = (php_snmp_session *)emalloc(sizeof(php_snmp_session));
813 	session = *session_p;
814 	memset(session, 0, sizeof(php_snmp_session));
815 
816 	snmp_sess_init(session);
817 
818 	session->version = version;
819 
820 	session->peername = emalloc(MAX_NAME_LEN);
821 	/* we copy original hostname for further processing */
822 	strlcpy(session->peername, hostname, MAX_NAME_LEN);
823 	host_ptr = session->peername;
824 
825 	/* Reading the hostname and its optional non-default port number */
826 	if (*host_ptr == '[') { /* IPv6 address */
827 		force_ipv6 = TRUE;
828 		host_ptr++;
829 		if ((pptr = strchr(host_ptr, ']'))) {
830 			if (pptr[1] == ':') {
831 				remote_port = atoi(pptr + 2);
832 			}
833 			*pptr = '\0';
834 		} else {
835 			php_error_docref(NULL, E_WARNING, "Malformed IPv6 address, closing square bracket missing");
836 			return (-1);
837 		}
838 	} else { /* IPv4 address */
839 		if ((pptr = strchr(host_ptr, ':'))) {
840 			remote_port = atoi(pptr + 1);
841 			*pptr = '\0';
842 		}
843 	}
844 
845 	/* since Net-SNMP library requires 'udp6:' prefix for all IPv6 addresses (in FQDN form too) we need to
846 	   perform possible name resolution before running any SNMP queries */
847 	if ((n = php_network_getaddresses(host_ptr, SOCK_DGRAM, &psal, NULL)) == 0) { /* some resolver error */
848 		/* warnings sent, bailing out */
849 		return (-1);
850 	}
851 
852 	/* we have everything we need in psal, flush peername and fill it properly */
853 	*(session->peername) = '\0';
854 	res = psal;
855 	while (n-- > 0) {
856 		pptr = session->peername;
857 #if HAVE_GETADDRINFO && HAVE_IPV6 && HAVE_INET_NTOP
858 		if (force_ipv6 && (*res)->sa_family != AF_INET6) {
859 			res++;
860 			continue;
861 		}
862 		if ((*res)->sa_family == AF_INET6) {
863 			strcpy(session->peername, "udp6:[");
864 			pptr = session->peername + strlen(session->peername);
865 			inet_ntop((*res)->sa_family, &(((struct sockaddr_in6*)(*res))->sin6_addr), pptr, MAX_NAME_LEN);
866 			strcat(pptr, "]");
867 		} else if ((*res)->sa_family == AF_INET) {
868 			inet_ntop((*res)->sa_family, &(((struct sockaddr_in*)(*res))->sin_addr), pptr, MAX_NAME_LEN);
869 		} else {
870 			res++;
871 			continue;
872 		}
873 #else
874 		if ((*res)->sa_family != AF_INET) {
875 			res++;
876 			continue;
877 		}
878 		strcat(pptr, inet_ntoa(((struct sockaddr_in*)(*res))->sin_addr));
879 #endif
880 		break;
881 	}
882 
883 	if (strlen(session->peername) == 0) {
884 		php_error_docref(NULL, E_WARNING, "Unknown failure while resolving '%s'", hostname);
885 		return (-1);
886 	}
887 	/* XXX FIXME
888 		There should be check for non-empty session->peername!
889 	*/
890 
891 	/* put back non-standard SNMP port */
892 	if (remote_port != SNMP_PORT) {
893 		pptr = session->peername + strlen(session->peername);
894 		sprintf(pptr, ":%d", remote_port);
895 	}
896 
897 	php_network_freeaddresses(psal);
898 
899 	if (version == SNMP_VERSION_3) {
900 		/* Setting the security name. */
901 		session->securityName = estrdup(community);
902 		session->securityNameLen = strlen(session->securityName);
903 	} else {
904 		session->authenticator = NULL;
905 		session->community = (u_char *)estrdup(community);
906 		session->community_len = strlen(community);
907 	}
908 
909 	session->retries = retries;
910 	session->timeout = timeout;
911 	return (0);
912 }
913 /* }}} */
914 
915 /* {{{ int netsnmp_session_set_sec_level(struct snmp_session *s, char *level)
916    Set the security level in the snmpv3 session */
netsnmp_session_set_sec_level(struct snmp_session * s,char * level)917 static int netsnmp_session_set_sec_level(struct snmp_session *s, char *level)
918 {
919 	if (!strcasecmp(level, "noAuthNoPriv") || !strcasecmp(level, "nanp")) {
920 		s->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
921 	} else if (!strcasecmp(level, "authNoPriv") || !strcasecmp(level, "anp")) {
922 		s->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
923 	} else if (!strcasecmp(level, "authPriv") || !strcasecmp(level, "ap")) {
924 		s->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
925 	} else {
926 		zend_value_error("Security level must be one of \"noAuthNoPriv\", \"authNoPriv\", or \"authPriv\"");
927 		return (-1);
928 	}
929 	return (0);
930 }
931 /* }}} */
932 
933 /* {{{ int netsnmp_session_set_auth_protocol(struct snmp_session *s, char *prot)
934    Set the authentication protocol in the snmpv3 session */
netsnmp_session_set_auth_protocol(struct snmp_session * s,char * prot)935 static int netsnmp_session_set_auth_protocol(struct snmp_session *s, char *prot)
936 {
937 #ifndef DISABLE_MD5
938 	if (!strcasecmp(prot, "MD5")) {
939 		s->securityAuthProto = usmHMACMD5AuthProtocol;
940 		s->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
941 	} else
942 #endif
943 	if (!strcasecmp(prot, "SHA")) {
944 		s->securityAuthProto = usmHMACSHA1AuthProtocol;
945 		s->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
946 	} else {
947 		zend_value_error("Authentication protocol must be either \"MD5\" or \"SHA\"");
948 		return (-1);
949 	}
950 	return (0);
951 }
952 /* }}} */
953 
954 /* {{{ int netsnmp_session_set_sec_protocol(struct snmp_session *s, char *prot)
955    Set the security protocol in the snmpv3 session */
netsnmp_session_set_sec_protocol(struct snmp_session * s,char * prot)956 static int netsnmp_session_set_sec_protocol(struct snmp_session *s, char *prot)
957 {
958 #ifndef NETSNMP_DISABLE_DES
959 	if (!strcasecmp(prot, "DES")) {
960 		s->securityPrivProto = usmDESPrivProtocol;
961 		s->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
962 	} else
963 #endif
964 #ifdef HAVE_AES
965 	if (!strcasecmp(prot, "AES128") || !strcasecmp(prot, "AES")) {
966 		s->securityPrivProto = usmAESPrivProtocol;
967 		s->securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
968 	} else
969 #endif
970 	{
971 #ifdef HAVE_AES
972 #ifndef NETSNMP_DISABLE_DES
973 		zend_value_error("Security protocol must be one of \"DES\", \"AES128\", or \"AES\"");
974 #else
975 		zend_value_error("Security protocol must be one of \"AES128\", or \"AES\"");
976 #endif
977 #else
978 #ifndef NETSNMP_DISABLE_DES
979 		zend_value_error("Security protocol must be \"DES\"");
980 #else
981 		zend_value_error("No security protocol supported");
982 #endif
983 #endif
984 		return (-1);
985 	}
986 	return (0);
987 }
988 /* }}} */
989 
990 /* {{{ int netsnmp_session_gen_auth_key(struct snmp_session *s, char *pass)
991    Make key from pass phrase in the snmpv3 session */
netsnmp_session_gen_auth_key(struct snmp_session * s,char * pass)992 static int netsnmp_session_gen_auth_key(struct snmp_session *s, char *pass)
993 {
994 	int snmp_errno;
995 	s->securityAuthKeyLen = USM_AUTH_KU_LEN;
996 	if ((snmp_errno = generate_Ku(s->securityAuthProto, s->securityAuthProtoLen,
997 			(u_char *) pass, strlen(pass),
998 			s->securityAuthKey, &(s->securityAuthKeyLen)))) {
999 		php_error_docref(NULL, E_WARNING, "Error generating a key for authentication pass phrase '%s': %s", pass, snmp_api_errstring(snmp_errno));
1000 		return (-1);
1001 	}
1002 	return (0);
1003 }
1004 /* }}} */
1005 
1006 /* {{{ int netsnmp_session_gen_sec_key(struct snmp_session *s, u_char *pass)
1007    Make key from pass phrase in the snmpv3 session */
netsnmp_session_gen_sec_key(struct snmp_session * s,char * pass)1008 static int netsnmp_session_gen_sec_key(struct snmp_session *s, char *pass)
1009 {
1010 	int snmp_errno;
1011 
1012 	s->securityPrivKeyLen = USM_PRIV_KU_LEN;
1013 	if ((snmp_errno = generate_Ku(s->securityAuthProto, s->securityAuthProtoLen,
1014 			(u_char *)pass, strlen(pass),
1015 			s->securityPrivKey, &(s->securityPrivKeyLen)))) {
1016 		php_error_docref(NULL, E_WARNING, "Error generating a key for privacy pass phrase '%s': %s", pass, snmp_api_errstring(snmp_errno));
1017 		return (-1);
1018 	}
1019 	return (0);
1020 }
1021 /* }}} */
1022 
1023 /* {{{ in netsnmp_session_set_contextEngineID(struct snmp_session *s, u_char * contextEngineID)
1024    Set context Engine Id in the snmpv3 session */
netsnmp_session_set_contextEngineID(struct snmp_session * s,char * contextEngineID)1025 static int netsnmp_session_set_contextEngineID(struct snmp_session *s, char * contextEngineID)
1026 {
1027 	size_t	ebuf_len = 32, eout_len = 0;
1028 	u_char	*ebuf = (u_char *) emalloc(ebuf_len);
1029 
1030 	if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, contextEngineID)) {
1031 		// TODO Promote to Error?
1032 		php_error_docref(NULL, E_WARNING, "Bad engine ID value '%s'", contextEngineID);
1033 		efree(ebuf);
1034 		return (-1);
1035 	}
1036 
1037 	if (s->contextEngineID) {
1038 		efree(s->contextEngineID);
1039 	}
1040 
1041 	s->contextEngineID = ebuf;
1042 	s->contextEngineIDLen = eout_len;
1043 	return (0);
1044 }
1045 /* }}} */
1046 
1047 /* {{{ php_set_security(struct snmp_session *session, char *sec_level, char *auth_protocol, char *auth_passphrase, char *priv_protocol, char *priv_passphrase, char *contextName, char *contextEngineID)
1048    Set all snmpv3-related security options */
netsnmp_session_set_security(struct snmp_session * session,char * sec_level,char * auth_protocol,char * auth_passphrase,char * priv_protocol,char * priv_passphrase,char * contextName,char * contextEngineID)1049 static int netsnmp_session_set_security(struct snmp_session *session, char *sec_level, char *auth_protocol, char *auth_passphrase, char *priv_protocol, char *priv_passphrase, char *contextName, char *contextEngineID)
1050 {
1051 
1052 	/* Setting the security level. */
1053 	if (netsnmp_session_set_sec_level(session, sec_level)) {
1054 		/* ValueError already generated, just bail out */
1055 		return (-1);
1056 	}
1057 
1058 	if (session->securityLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1059 
1060 		/* Setting the authentication protocol. */
1061 		if (netsnmp_session_set_auth_protocol(session, auth_protocol)) {
1062 			/* ValueError already generated, just bail out */
1063 			return (-1);
1064 		}
1065 
1066 		/* Setting the authentication passphrase. */
1067 		if (netsnmp_session_gen_auth_key(session, auth_passphrase)) {
1068 			/* Warning message sent already, just bail out */
1069 			return (-1);
1070 		}
1071 
1072 		if (session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
1073 			/* Setting the security protocol. */
1074 			if (netsnmp_session_set_sec_protocol(session, priv_protocol)) {
1075 				/* ValueError already generated, just bail out */
1076 				return (-1);
1077 			}
1078 
1079 			/* Setting the security protocol passphrase. */
1080 			if (netsnmp_session_gen_sec_key(session, priv_passphrase)) {
1081 				/* Warning message sent already, just bail out */
1082 				return (-1);
1083 			}
1084 		}
1085 	}
1086 
1087 	/* Setting contextName if specified */
1088 	if (contextName) {
1089 		session->contextName = contextName;
1090 		session->contextNameLen = strlen(contextName);
1091 	}
1092 
1093 	/* Setting contextEngineIS if specified */
1094 	if (contextEngineID && strlen(contextEngineID) && netsnmp_session_set_contextEngineID(session, contextEngineID)) {
1095 		/* Warning message sent already, just bail out */
1096 		return (-1);
1097 	}
1098 
1099 	return (0);
1100 }
1101 /* }}} */
1102 
1103 /* {{{ php_snmp
1104 *
1105 * Generic SNMP handler for all versions.
1106 * This function makes use of the internal SNMP object fetcher.
1107 * Used both in old (non-OO) and OO API
1108 *
1109 */
php_snmp(INTERNAL_FUNCTION_PARAMETERS,int st,int version)1110 static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version)
1111 {
1112 	zend_string *oid_str, *type_str = NULL, *value_str = NULL;
1113 	HashTable *oid_ht, *type_ht = NULL, *value_ht = NULL;
1114 	char *a1 = NULL, *a2 = NULL, *a3 = NULL, *a4 = NULL, *a5 = NULL, *a6 = NULL, *a7 = NULL;
1115 	size_t a1_len, a2_len, a3_len, a4_len, a5_len, a6_len, a7_len;
1116 	zend_bool use_orignames = 0, suffix_keys = 0;
1117 	zend_long timeout = SNMP_DEFAULT_TIMEOUT;
1118 	zend_long retries = SNMP_DEFAULT_RETRIES;
1119 	struct objid_query objid_query;
1120 	php_snmp_session *session;
1121 	int session_less_mode = (getThis() == NULL);
1122 	php_snmp_object *snmp_object;
1123 	php_snmp_object glob_snmp_object;
1124 
1125 	objid_query.max_repetitions = -1;
1126 	objid_query.non_repeaters = 0;
1127 	objid_query.valueretrieval = SNMP_G(valueretrieval);
1128 	objid_query.oid_increasing_check = TRUE;
1129 
1130 	if (session_less_mode) {
1131 		if (version == SNMP_VERSION_3) {
1132 			if (st & SNMP_CMD_SET) {
1133 				ZEND_PARSE_PARAMETERS_START(10, 12)
1134 					Z_PARAM_STRING(a1, a1_len)
1135 					Z_PARAM_STRING(a2, a2_len)
1136 					Z_PARAM_STRING(a3, a3_len)
1137 					Z_PARAM_STRING(a4, a4_len)
1138 					Z_PARAM_STRING(a5, a5_len)
1139 					Z_PARAM_STRING(a6, a6_len)
1140 					Z_PARAM_STRING(a7, a7_len)
1141 					Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str)
1142 					Z_PARAM_ARRAY_HT_OR_STR(type_ht, type_str)
1143 					Z_PARAM_ARRAY_HT_OR_STR(value_ht, value_str)
1144 					Z_PARAM_OPTIONAL
1145 					Z_PARAM_LONG(timeout)
1146 					Z_PARAM_LONG(retries)
1147 				ZEND_PARSE_PARAMETERS_END();
1148 			} else {
1149 				/* SNMP_CMD_GET
1150 				 * SNMP_CMD_GETNEXT
1151 				 * SNMP_CMD_WALK
1152 				 */
1153 				ZEND_PARSE_PARAMETERS_START(8, 10)
1154 					Z_PARAM_STRING(a1, a1_len)
1155 					Z_PARAM_STRING(a2, a2_len)
1156 					Z_PARAM_STRING(a3, a3_len)
1157 					Z_PARAM_STRING(a4, a4_len)
1158 					Z_PARAM_STRING(a5, a5_len)
1159 					Z_PARAM_STRING(a6, a6_len)
1160 					Z_PARAM_STRING(a7, a7_len)
1161 					Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str)
1162 					Z_PARAM_OPTIONAL
1163 					Z_PARAM_LONG(timeout)
1164 					Z_PARAM_LONG(retries)
1165 				ZEND_PARSE_PARAMETERS_END();
1166 			}
1167 		} else {
1168 			if (st & SNMP_CMD_SET) {
1169 				ZEND_PARSE_PARAMETERS_START(5, 7)
1170 					Z_PARAM_STRING(a1, a1_len)
1171 					Z_PARAM_STRING(a2, a2_len)
1172 					Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str)
1173 					Z_PARAM_ARRAY_HT_OR_STR(type_ht, type_str)
1174 					Z_PARAM_ARRAY_HT_OR_STR(value_ht, value_str)
1175 					Z_PARAM_OPTIONAL
1176 					Z_PARAM_LONG(timeout)
1177 					Z_PARAM_LONG(retries)
1178 				ZEND_PARSE_PARAMETERS_END();
1179 			} else {
1180 				/* SNMP_CMD_GET
1181 				 * SNMP_CMD_GETNEXT
1182 				 * SNMP_CMD_WALK
1183 				 */
1184 				ZEND_PARSE_PARAMETERS_START(3, 5)
1185 					Z_PARAM_STRING(a1, a1_len)
1186 					Z_PARAM_STRING(a2, a2_len)
1187 					Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str)
1188 					Z_PARAM_OPTIONAL
1189 					Z_PARAM_LONG(timeout)
1190 					Z_PARAM_LONG(retries)
1191 				ZEND_PARSE_PARAMETERS_END();
1192 			}
1193 		}
1194 	} else {
1195 		if (st & SNMP_CMD_SET) {
1196 			ZEND_PARSE_PARAMETERS_START(3, 3)
1197 				Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str)
1198 				Z_PARAM_ARRAY_HT_OR_STR(type_ht, type_str)
1199 				Z_PARAM_ARRAY_HT_OR_STR(value_ht, value_str)
1200 			ZEND_PARSE_PARAMETERS_END();
1201 		} else if (st & SNMP_CMD_WALK) {
1202 			ZEND_PARSE_PARAMETERS_START(1, 4)
1203 				Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str)
1204 				Z_PARAM_OPTIONAL
1205 				Z_PARAM_BOOL(suffix_keys)
1206 				Z_PARAM_LONG(objid_query.max_repetitions)
1207 				Z_PARAM_LONG(objid_query.non_repeaters)
1208 			ZEND_PARSE_PARAMETERS_END();
1209 			if (suffix_keys) {
1210 				st |= SNMP_USE_SUFFIX_AS_KEYS;
1211 			}
1212 		} else if (st & SNMP_CMD_GET) {
1213 			ZEND_PARSE_PARAMETERS_START(1, 2)
1214 				Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str)
1215 				Z_PARAM_OPTIONAL
1216 				Z_PARAM_BOOL(use_orignames)
1217 			ZEND_PARSE_PARAMETERS_END();
1218 			if (use_orignames) {
1219 				st |= SNMP_ORIGINAL_NAMES_AS_KEYS;
1220 			}
1221 		} else {
1222 			/* SNMP_CMD_GETNEXT
1223 			 */
1224 			ZEND_PARSE_PARAMETERS_START(1, 1)
1225 				Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str)
1226 			ZEND_PARSE_PARAMETERS_END();
1227 		}
1228 	}
1229 
1230 	if (!php_snmp_parse_oid(getThis(), st, &objid_query, oid_str, oid_ht, type_str, type_ht, value_str, value_ht)) {
1231 		RETURN_FALSE;
1232 	}
1233 
1234 	if (session_less_mode) {
1235 		if (netsnmp_session_init(&session, version, a1, a2, timeout, retries)) {
1236 			efree(objid_query.vars);
1237 			netsnmp_session_free(&session);
1238 			RETURN_FALSE;
1239 		}
1240 		if (version == SNMP_VERSION_3 && netsnmp_session_set_security(session, a3, a4, a5, a6, a7, NULL, NULL)) {
1241 			efree(objid_query.vars);
1242 			netsnmp_session_free(&session);
1243 			/* Warning message sent already, just bail out */
1244 			RETURN_FALSE;
1245 		}
1246 	} else {
1247 		zval *object = getThis();
1248 		snmp_object = Z_SNMP_P(object);
1249 		session = snmp_object->session;
1250 		if (!session) {
1251 			zend_throw_error(NULL, "Invalid or uninitialized SNMP object");
1252 			efree(objid_query.vars);
1253 			RETURN_THROWS();
1254 		}
1255 
1256 		if (snmp_object->max_oids > 0) {
1257 			objid_query.step = snmp_object->max_oids;
1258 			if (objid_query.max_repetitions < 0) { /* unspecified in function call, use session-wise */
1259 				objid_query.max_repetitions = snmp_object->max_oids;
1260 			}
1261 		}
1262 		objid_query.oid_increasing_check = snmp_object->oid_increasing_check;
1263 		objid_query.valueretrieval = snmp_object->valueretrieval;
1264 		glob_snmp_object.enum_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM);
1265 		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, snmp_object->enum_print);
1266 		glob_snmp_object.quick_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT);
1267 		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, snmp_object->quick_print);
1268 		glob_snmp_object.oid_output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
1269 		netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, snmp_object->oid_output_format);
1270 	}
1271 
1272 	if (objid_query.max_repetitions < 0) {
1273 		objid_query.max_repetitions = 20; /* provide correct default value */
1274 	}
1275 
1276 	php_snmp_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, st, session, &objid_query);
1277 
1278 	efree(objid_query.vars);
1279 
1280 	if (session_less_mode) {
1281 		netsnmp_session_free(&session);
1282 	} else {
1283 		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, glob_snmp_object.enum_print);
1284 		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, glob_snmp_object.quick_print);
1285 		netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, glob_snmp_object.oid_output_format);
1286 	}
1287 }
1288 /* }}} */
1289 
1290 /* {{{ Fetch a SNMP object */
PHP_FUNCTION(snmpget)1291 PHP_FUNCTION(snmpget)
1292 {
1293 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_1);
1294 }
1295 /* }}} */
1296 
1297 /* {{{ Fetch a SNMP object */
PHP_FUNCTION(snmpgetnext)1298 PHP_FUNCTION(snmpgetnext)
1299 {
1300 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_1);
1301 }
1302 /* }}} */
1303 
1304 /* {{{ Return all objects under the specified object id */
PHP_FUNCTION(snmpwalk)1305 PHP_FUNCTION(snmpwalk)
1306 {
1307 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, (SNMP_CMD_WALK | SNMP_NUMERIC_KEYS), SNMP_VERSION_1);
1308 }
1309 /* }}} */
1310 
1311 /* {{{ Return all objects including their respective object id within the specified one */
PHP_FUNCTION(snmprealwalk)1312 PHP_FUNCTION(snmprealwalk)
1313 {
1314 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, SNMP_VERSION_1);
1315 }
1316 /* }}} */
1317 
1318 /* {{{ Set the value of a SNMP object */
PHP_FUNCTION(snmpset)1319 PHP_FUNCTION(snmpset)
1320 {
1321 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, SNMP_VERSION_1);
1322 }
1323 /* }}} */
1324 
1325 /* {{{ Return the current status of quick_print */
PHP_FUNCTION(snmp_get_quick_print)1326 PHP_FUNCTION(snmp_get_quick_print)
1327 {
1328 	if (zend_parse_parameters_none() == FAILURE) {
1329 		RETURN_THROWS();
1330 	}
1331 
1332 	RETURN_BOOL(netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT));
1333 }
1334 /* }}} */
1335 
1336 /* {{{ Return all objects including their respective object id within the specified one */
PHP_FUNCTION(snmp_set_quick_print)1337 PHP_FUNCTION(snmp_set_quick_print)
1338 {
1339 	zend_bool a1;
1340 
1341 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &a1) == FAILURE) {
1342 		RETURN_THROWS();
1343 	}
1344 
1345 	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, (int)a1);
1346 	RETURN_TRUE;
1347 }
1348 /* }}} */
1349 
1350 /* {{{ Return all values that are enums with their enum value instead of the raw integer */
PHP_FUNCTION(snmp_set_enum_print)1351 PHP_FUNCTION(snmp_set_enum_print)
1352 {
1353 	zend_bool a1;
1354 
1355 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &a1) == FAILURE) {
1356 		RETURN_THROWS();
1357 	}
1358 
1359 	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, (int) a1);
1360 	RETURN_TRUE;
1361 }
1362 /* }}} */
1363 
1364 /* {{{ Set the OID output format. */
PHP_FUNCTION(snmp_set_oid_output_format)1365 PHP_FUNCTION(snmp_set_oid_output_format)
1366 {
1367 	zend_long a1;
1368 
1369 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &a1) == FAILURE) {
1370 		RETURN_THROWS();
1371 	}
1372 
1373 	switch (a1) {
1374 		case NETSNMP_OID_OUTPUT_SUFFIX:
1375 		case NETSNMP_OID_OUTPUT_MODULE:
1376 		case NETSNMP_OID_OUTPUT_FULL:
1377 		case NETSNMP_OID_OUTPUT_NUMERIC:
1378 		case NETSNMP_OID_OUTPUT_UCD:
1379 		case NETSNMP_OID_OUTPUT_NONE:
1380 			netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, a1);
1381 			RETURN_TRUE;
1382 		default:
1383 			zend_argument_value_error(1, "must be an SNMP_OID_OUTPUT_* constant");
1384 			RETURN_THROWS();
1385 	}
1386 }
1387 /* }}} */
1388 
1389 /* {{{ Fetch a SNMP object */
PHP_FUNCTION(snmp2_get)1390 PHP_FUNCTION(snmp2_get)
1391 {
1392 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_2c);
1393 }
1394 /* }}} */
1395 
1396 /* {{{ Fetch a SNMP object */
PHP_FUNCTION(snmp2_getnext)1397 PHP_FUNCTION(snmp2_getnext)
1398 {
1399 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_2c);
1400 }
1401 /* }}} */
1402 
1403 /* {{{ Return all objects under the specified object id */
PHP_FUNCTION(snmp2_walk)1404 PHP_FUNCTION(snmp2_walk)
1405 {
1406 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, (SNMP_CMD_WALK | SNMP_NUMERIC_KEYS), SNMP_VERSION_2c);
1407 }
1408 /* }}} */
1409 
1410 /* {{{ Return all objects including their respective object id within the specified one */
PHP_FUNCTION(snmp2_real_walk)1411 PHP_FUNCTION(snmp2_real_walk)
1412 {
1413 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, SNMP_VERSION_2c);
1414 }
1415 /* }}} */
1416 
1417 /* {{{ Set the value of a SNMP object */
PHP_FUNCTION(snmp2_set)1418 PHP_FUNCTION(snmp2_set)
1419 {
1420 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, SNMP_VERSION_2c);
1421 }
1422 /* }}} */
1423 
1424 /* {{{ Fetch the value of a SNMP object */
PHP_FUNCTION(snmp3_get)1425 PHP_FUNCTION(snmp3_get)
1426 {
1427 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_3);
1428 }
1429 /* }}} */
1430 
1431 /* {{{ Fetch the value of a SNMP object */
PHP_FUNCTION(snmp3_getnext)1432 PHP_FUNCTION(snmp3_getnext)
1433 {
1434 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_3);
1435 }
1436 /* }}} */
1437 
1438 /* {{{ Fetch the value of a SNMP object */
PHP_FUNCTION(snmp3_walk)1439 PHP_FUNCTION(snmp3_walk)
1440 {
1441 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, (SNMP_CMD_WALK | SNMP_NUMERIC_KEYS), SNMP_VERSION_3);
1442 }
1443 /* }}} */
1444 
1445 /* {{{ Fetch the value of a SNMP object */
PHP_FUNCTION(snmp3_real_walk)1446 PHP_FUNCTION(snmp3_real_walk)
1447 {
1448 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, SNMP_VERSION_3);
1449 }
1450 /* }}} */
1451 
1452 /* {{{ Fetch the value of a SNMP object */
PHP_FUNCTION(snmp3_set)1453 PHP_FUNCTION(snmp3_set)
1454 {
1455 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, SNMP_VERSION_3);
1456 }
1457 /* }}} */
1458 
1459 /* {{{ Specify the method how the SNMP values will be returned */
PHP_FUNCTION(snmp_set_valueretrieval)1460 PHP_FUNCTION(snmp_set_valueretrieval)
1461 {
1462 	zend_long method;
1463 
1464 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &method) == FAILURE) {
1465 		RETURN_THROWS();
1466 	}
1467 
1468 	if (method >= 0 && method <= (SNMP_VALUE_LIBRARY|SNMP_VALUE_PLAIN|SNMP_VALUE_OBJECT)) {
1469 			SNMP_G(valueretrieval) = method;
1470 			RETURN_TRUE;
1471 	} else {
1472 		zend_argument_value_error(1, "must be a bitmask of SNMP_VALUE_LIBRARY, SNMP_VALUE_PLAIN, and SNMP_VALUE_OBJECT");
1473 		RETURN_THROWS();
1474 	}
1475 }
1476 /* }}} */
1477 
1478 /* {{{ Return the method how the SNMP values will be returned */
PHP_FUNCTION(snmp_get_valueretrieval)1479 PHP_FUNCTION(snmp_get_valueretrieval)
1480 {
1481 	if (zend_parse_parameters_none() == FAILURE) {
1482 		RETURN_THROWS();
1483 	}
1484 
1485 	RETURN_LONG(SNMP_G(valueretrieval));
1486 }
1487 /* }}} */
1488 
1489 /* {{{ Reads and parses a MIB file into the active MIB tree. */
PHP_FUNCTION(snmp_read_mib)1490 PHP_FUNCTION(snmp_read_mib)
1491 {
1492 	char *filename;
1493 	size_t filename_len;
1494 
1495 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &filename, &filename_len) == FAILURE) {
1496 		RETURN_THROWS();
1497 	}
1498 
1499 	if (!read_mib(filename)) {
1500 		char *error = strerror(errno);
1501 		php_error_docref(NULL, E_WARNING, "Error while reading MIB file '%s': %s", filename, error);
1502 		RETURN_FALSE;
1503 	}
1504 	RETURN_TRUE;
1505 }
1506 /* }}} */
1507 
1508 /* {{{ Creates a new SNMP session to specified host. */
PHP_METHOD(SNMP,__construct)1509 PHP_METHOD(SNMP, __construct)
1510 {
1511 	php_snmp_object *snmp_object;
1512 	zval *object = ZEND_THIS;
1513 	char *a1, *a2;
1514 	size_t a1_len, a2_len;
1515 	zend_long timeout = SNMP_DEFAULT_TIMEOUT;
1516 	zend_long retries = SNMP_DEFAULT_RETRIES;
1517 	zend_long version = SNMP_DEFAULT_VERSION;
1518 	int argc = ZEND_NUM_ARGS();
1519 
1520 	snmp_object = Z_SNMP_P(object);
1521 
1522 	if (zend_parse_parameters(argc, "lss|ll", &version, &a1, &a1_len, &a2, &a2_len, &timeout, &retries) == FAILURE) {
1523 		RETURN_THROWS();
1524 	}
1525 
1526 	switch (version) {
1527 		case SNMP_VERSION_1:
1528 		case SNMP_VERSION_2c:
1529 		case SNMP_VERSION_3:
1530 			break;
1531 		default:
1532 			zend_argument_value_error(1, "must be a valid SNMP protocol version");
1533 			RETURN_THROWS();
1534 	}
1535 
1536 	/* handle re-open of snmp session */
1537 	if (snmp_object->session) {
1538 		netsnmp_session_free(&(snmp_object->session));
1539 	}
1540 
1541 	if (netsnmp_session_init(&(snmp_object->session), version, a1, a2, timeout, retries)) {
1542 		return;
1543 	}
1544 	snmp_object->max_oids = 0;
1545 	snmp_object->valueretrieval = SNMP_G(valueretrieval);
1546 	snmp_object->enum_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM);
1547 	snmp_object->oid_output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
1548 	snmp_object->quick_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT);
1549 	snmp_object->oid_increasing_check = TRUE;
1550 	snmp_object->exceptions_enabled = 0;
1551 }
1552 /* }}} */
1553 
1554 /* {{{ Close SNMP session */
PHP_METHOD(SNMP,close)1555 PHP_METHOD(SNMP, close)
1556 {
1557 	php_snmp_object *snmp_object;
1558 	zval *object = ZEND_THIS;
1559 
1560 	snmp_object = Z_SNMP_P(object);
1561 
1562 	if (zend_parse_parameters_none() == FAILURE) {
1563 		RETURN_THROWS();
1564 	}
1565 
1566 	netsnmp_session_free(&(snmp_object->session));
1567 
1568 	RETURN_TRUE;
1569 }
1570 /* }}} */
1571 
1572 /* {{{ Fetch a SNMP object returning scalar for single OID and array of oid->value pairs for multi OID request */
PHP_METHOD(SNMP,get)1573 PHP_METHOD(SNMP, get)
1574 {
1575 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, (-1));
1576 }
1577 /* }}} */
1578 
1579 /* {{{ Fetch a SNMP object returning scalar for single OID and array of oid->value pairs for multi OID request */
PHP_METHOD(SNMP,getnext)1580 PHP_METHOD(SNMP, getnext)
1581 {
1582 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, (-1));
1583 }
1584 /* }}} */
1585 
1586 /* {{{ Return all objects including their respective object id within the specified one as array of oid->value pairs */
PHP_METHOD(SNMP,walk)1587 PHP_METHOD(SNMP, walk)
1588 {
1589 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, (-1));
1590 }
1591 /* }}} */
1592 
1593 /* {{{ Set the value of a SNMP object */
PHP_METHOD(SNMP,set)1594 PHP_METHOD(SNMP, set)
1595 {
1596 	php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, (-1));
1597 }
1598 /* }}} */
1599 
1600 /* {{{ Set SNMPv3 security-related session parameters */
PHP_METHOD(SNMP,setSecurity)1601 PHP_METHOD(SNMP, setSecurity)
1602 {
1603 	php_snmp_object *snmp_object;
1604 	zval *object = ZEND_THIS;
1605 	char *a1 = "", *a2 = "", *a3 = "", *a4 = "", *a5 = "", *a6 = "", *a7 = "";
1606 	size_t a1_len = 0, a2_len = 0, a3_len = 0, a4_len = 0, a5_len = 0, a6_len = 0, a7_len = 0;
1607 	int argc = ZEND_NUM_ARGS();
1608 
1609 	snmp_object = Z_SNMP_P(object);
1610 
1611 	if (zend_parse_parameters(argc, "s|ssssss", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len,
1612 		&a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len) == FAILURE) {
1613 		RETURN_THROWS();
1614 	}
1615 
1616 	if (netsnmp_session_set_security(snmp_object->session, a1, a2, a3, a4, a5, a6, a7)) {
1617 		/* Warning message sent already, just bail out */
1618 		RETURN_FALSE;
1619 	}
1620 	RETURN_TRUE;
1621 }
1622 /* }}} */
1623 
1624 /* {{{ Get last error code number */
PHP_METHOD(SNMP,getErrno)1625 PHP_METHOD(SNMP, getErrno)
1626 {
1627 	php_snmp_object *snmp_object;
1628 	zval *object = ZEND_THIS;
1629 
1630 	snmp_object = Z_SNMP_P(object);
1631 
1632 	if (zend_parse_parameters_none() == FAILURE) {
1633 		RETURN_THROWS();
1634 	}
1635 
1636 	RETVAL_LONG(snmp_object->snmp_errno);
1637 	return;
1638 }
1639 /* }}} */
1640 
1641 /* {{{ Get last error message */
PHP_METHOD(SNMP,getError)1642 PHP_METHOD(SNMP, getError)
1643 {
1644 	php_snmp_object *snmp_object;
1645 	zval *object = ZEND_THIS;
1646 
1647 	snmp_object = Z_SNMP_P(object);
1648 
1649 	if (zend_parse_parameters_none() == FAILURE) {
1650 		RETURN_THROWS();
1651 	}
1652 
1653 	RETURN_STRING(snmp_object->snmp_errstr);
1654 }
1655 /* }}} */
1656 
1657 /* {{{ */
php_snmp_add_property(HashTable * h,const char * name,size_t name_length,php_snmp_read_t read_func,php_snmp_write_t write_func)1658 void php_snmp_add_property(HashTable *h, const char *name, size_t name_length, php_snmp_read_t read_func, php_snmp_write_t write_func)
1659 {
1660 	php_snmp_prop_handler p;
1661 	zend_string *str;
1662 
1663 	p.name = (char*) name;
1664 	p.name_length = name_length;
1665 	p.read_func = (read_func) ? read_func : NULL;
1666 	p.write_func = (write_func) ? write_func : NULL;
1667 	str = zend_string_init_interned(name, name_length, 1);
1668 	zend_hash_add_mem(h, str, &p, sizeof(php_snmp_prop_handler));
1669 	zend_string_release_ex(str, 1);
1670 }
1671 /* }}} */
1672 
1673 /* {{{ php_snmp_read_property(zval *object, zval *member, int type[, const zend_literal *key])
1674    Generic object property reader */
php_snmp_read_property(zend_object * object,zend_string * name,int type,void ** cache_slot,zval * rv)1675 zval *php_snmp_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
1676 {
1677 	zval *retval;
1678 	php_snmp_object *obj;
1679 	php_snmp_prop_handler *hnd;
1680 	int ret;
1681 
1682 	obj = php_snmp_fetch_object(object);
1683 	hnd = zend_hash_find_ptr(&php_snmp_properties, name);
1684 
1685 	if (hnd && hnd->read_func) {
1686 		ret = hnd->read_func(obj, rv);
1687 		if (ret == SUCCESS) {
1688 			retval = rv;
1689 		} else {
1690 			retval = &EG(uninitialized_zval);
1691 		}
1692 	} else {
1693 		retval = zend_std_read_property(object, name, type, cache_slot, rv);
1694 	}
1695 
1696 	return retval;
1697 }
1698 /* }}} */
1699 
1700 /* {{{ php_snmp_write_property(zval *object, zval *member, zval *value[, const zend_literal *key])
1701    Generic object property writer */
php_snmp_write_property(zend_object * object,zend_string * name,zval * value,void ** cache_slot)1702 zval *php_snmp_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
1703 {
1704 	php_snmp_object *obj;
1705 	php_snmp_prop_handler *hnd;
1706 
1707 	obj = php_snmp_fetch_object(object);
1708 	hnd = zend_hash_find_ptr(&php_snmp_properties, name);
1709 
1710 	if (hnd && hnd->write_func) {
1711 		hnd->write_func(obj, value);
1712 		/*
1713 		if (!PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) == 0) {
1714 			Z_ADDREF_P(value);
1715 			zval_ptr_dtor(&value);
1716 		}
1717 		*/
1718 	} else {
1719 		value = zend_std_write_property(object, name, value, cache_slot);
1720 	}
1721 
1722 	return value;
1723 }
1724 /* }}} */
1725 
1726 /* {{{ php_snmp_has_property(zval *object, zval *member, int has_set_exists[, const zend_literal *key])
1727    Generic object property checker */
php_snmp_has_property(zend_object * object,zend_string * name,int has_set_exists,void ** cache_slot)1728 static int php_snmp_has_property(zend_object *object, zend_string *name, int has_set_exists, void **cache_slot)
1729 {
1730 	zval rv;
1731 	php_snmp_prop_handler *hnd;
1732 	int ret = 0;
1733 
1734 	if ((hnd = zend_hash_find_ptr(&php_snmp_properties, name)) != NULL) {
1735 		switch (has_set_exists) {
1736 			case ZEND_PROPERTY_EXISTS:
1737 				ret = 1;
1738 				break;
1739 			case ZEND_PROPERTY_ISSET: {
1740 				zval *value = php_snmp_read_property(object, name, BP_VAR_IS, cache_slot, &rv);
1741 				if (value != &EG(uninitialized_zval)) {
1742 					ret = Z_TYPE_P(value) != IS_NULL? 1 : 0;
1743 					zval_ptr_dtor(value);
1744 				}
1745 				break;
1746 			}
1747 			default: {
1748 				zval *value = php_snmp_read_property(object, name, BP_VAR_IS, cache_slot, &rv);
1749 				if (value != &EG(uninitialized_zval)) {
1750 					convert_to_boolean(value);
1751 					ret = Z_TYPE_P(value) == IS_TRUE? 1:0;
1752 				}
1753 				break;
1754 			}
1755 		}
1756 	} else {
1757 		ret = zend_std_has_property(object, name, has_set_exists, cache_slot);
1758 	}
1759 	return ret;
1760 }
1761 /* }}} */
1762 
php_snmp_get_gc(zend_object * object,zval ** gc_data,int * gc_data_count)1763 static HashTable *php_snmp_get_gc(zend_object *object, zval **gc_data, int *gc_data_count) /* {{{ */
1764 {
1765 	*gc_data = NULL;
1766 	*gc_data_count = 0;
1767 	return zend_std_get_properties(object);
1768 }
1769 /* }}} */
1770 
1771 /* {{{ php_snmp_get_properties(zval *object)
1772    Returns all object properties. Injects SNMP properties into object on first call */
php_snmp_get_properties(zend_object * object)1773 static HashTable *php_snmp_get_properties(zend_object *object)
1774 {
1775 	php_snmp_object *obj;
1776 	php_snmp_prop_handler *hnd;
1777 	HashTable *props;
1778 	zval rv;
1779 	zend_string *key;
1780 
1781 	obj = php_snmp_fetch_object(object);
1782 	props = zend_std_get_properties(object);
1783 
1784 	ZEND_HASH_FOREACH_STR_KEY_PTR(&php_snmp_properties, key, hnd) {
1785 		if (!hnd->read_func || hnd->read_func(obj, &rv) != SUCCESS) {
1786 			ZVAL_NULL(&rv);
1787 		}
1788 		zend_hash_update(props, key, &rv);
1789 	} ZEND_HASH_FOREACH_END();
1790 
1791 	return obj->zo.properties;
1792 }
1793 /* }}} */
1794 
1795 /* {{{ */
php_snmp_read_info(php_snmp_object * snmp_object,zval * retval)1796 static int php_snmp_read_info(php_snmp_object *snmp_object, zval *retval)
1797 {
1798 	zval val;
1799 
1800 	array_init(retval);
1801 
1802 	if (snmp_object->session == NULL) {
1803 		return SUCCESS;
1804 	}
1805 
1806 	ZVAL_STRINGL(&val, snmp_object->session->peername, strlen(snmp_object->session->peername));
1807 	add_assoc_zval(retval, "hostname", &val);
1808 
1809 	ZVAL_LONG(&val, snmp_object->session->timeout);
1810 	add_assoc_zval(retval, "timeout", &val);
1811 
1812 	ZVAL_LONG(&val, snmp_object->session->retries);
1813 	add_assoc_zval(retval, "retries", &val);
1814 
1815 	return SUCCESS;
1816 }
1817 /* }}} */
1818 
1819 /* {{{ */
php_snmp_read_max_oids(php_snmp_object * snmp_object,zval * retval)1820 static int php_snmp_read_max_oids(php_snmp_object *snmp_object, zval *retval)
1821 {
1822 	if (snmp_object->max_oids > 0) {
1823 		ZVAL_LONG(retval, snmp_object->max_oids);
1824 	} else {
1825 		ZVAL_NULL(retval);
1826 	}
1827 	return SUCCESS;
1828 }
1829 /* }}} */
1830 
1831 #define PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(name) \
1832 	static int php_snmp_read_##name(php_snmp_object *snmp_object, zval *retval) \
1833 	{ \
1834 		ZVAL_BOOL(retval, snmp_object->name); \
1835 		return SUCCESS; \
1836 	}
1837 
1838 PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(oid_increasing_check)
PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(quick_print)1839 PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(quick_print)
1840 PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(enum_print)
1841 
1842 #define PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(name) \
1843 	static int php_snmp_read_##name(php_snmp_object *snmp_object, zval *retval) \
1844 	{ \
1845 		ZVAL_LONG(retval, snmp_object->name); \
1846 		return SUCCESS; \
1847 	}
1848 
1849 PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(valueretrieval)
1850 PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(oid_output_format)
1851 PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(exceptions_enabled)
1852 
1853 /* {{{ */
1854 static int php_snmp_write_info(php_snmp_object *snmp_object, zval *newval)
1855 {
1856 	zend_throw_error(NULL, "SNMP::$info property is read-only");
1857 	return FAILURE;
1858 }
1859 /* }}} */
1860 
1861 /* {{{ */
php_snmp_write_max_oids(php_snmp_object * snmp_object,zval * newval)1862 static int php_snmp_write_max_oids(php_snmp_object *snmp_object, zval *newval)
1863 {
1864 	zend_long lval;
1865 
1866 	if (Z_TYPE_P(newval) == IS_NULL) {
1867 		snmp_object->max_oids = 0;
1868 		return SUCCESS;
1869 	}
1870 
1871 	lval = zval_get_long(newval);
1872 
1873 	if (lval <= 0) {
1874 		zend_value_error("max_oids must be greater than 0 or null");
1875 		return FAILURE;
1876 	}
1877 	snmp_object->max_oids = lval;
1878 
1879 	return SUCCESS;
1880 }
1881 /* }}} */
1882 
1883 /* {{{ */
php_snmp_write_valueretrieval(php_snmp_object * snmp_object,zval * newval)1884 static int php_snmp_write_valueretrieval(php_snmp_object *snmp_object, zval *newval)
1885 {
1886 	zend_long lval = zval_get_long(newval);
1887 
1888 	if (lval >= 0 && lval <= (SNMP_VALUE_LIBRARY|SNMP_VALUE_PLAIN|SNMP_VALUE_OBJECT)) {
1889 		snmp_object->valueretrieval = lval;
1890 	} else {
1891 		zend_value_error("SNMP retrieval method must be a bitmask of SNMP_VALUE_LIBRARY, SNMP_VALUE_PLAIN, and SNMP_VALUE_OBJECT");
1892 		return FAILURE;
1893 	}
1894 
1895 	return SUCCESS;
1896 }
1897 /* }}} */
1898 
1899 #define PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(name) \
1900 static int php_snmp_write_##name(php_snmp_object *snmp_object, zval *newval) \
1901 { \
1902 	zval ztmp; \
1903 	ZVAL_COPY(&ztmp, newval); \
1904 	convert_to_boolean(&ztmp); \
1905 	newval = &ztmp; \
1906 \
1907 	snmp_object->name = Z_TYPE_P(newval) == IS_TRUE? 1 : 0; \
1908 \
1909 	return SUCCESS; \
1910 }
1911 
1912 PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(quick_print)
PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(enum_print)1913 PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(enum_print)
1914 PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(oid_increasing_check)
1915 
1916 /* {{{ */
1917 static int php_snmp_write_oid_output_format(php_snmp_object *snmp_object, zval *newval)
1918 {
1919 	zend_long lval = zval_get_long(newval);
1920 
1921 	switch(lval) {
1922 		case NETSNMP_OID_OUTPUT_SUFFIX:
1923 		case NETSNMP_OID_OUTPUT_MODULE:
1924 		case NETSNMP_OID_OUTPUT_FULL:
1925 		case NETSNMP_OID_OUTPUT_NUMERIC:
1926 		case NETSNMP_OID_OUTPUT_UCD:
1927 		case NETSNMP_OID_OUTPUT_NONE:
1928 			snmp_object->oid_output_format = lval;
1929 			return SUCCESS;
1930 		default:
1931 			zend_value_error("SNMP output print format must be an SNMP_OID_OUTPUT_* constant");
1932 			return FAILURE;
1933 	}
1934 }
1935 /* }}} */
1936 
1937 /* {{{ */
php_snmp_write_exceptions_enabled(php_snmp_object * snmp_object,zval * newval)1938 static int php_snmp_write_exceptions_enabled(php_snmp_object *snmp_object, zval *newval)
1939 {
1940 	int ret = SUCCESS;
1941 
1942 	snmp_object->exceptions_enabled = zval_get_long(newval);
1943 
1944 	return ret;
1945 }
1946 /* }}} */
1947 
free_php_snmp_properties(zval * el)1948 static void free_php_snmp_properties(zval *el)  /* {{{ */
1949 {
1950 	pefree(Z_PTR_P(el), 1);
1951 }
1952 /* }}} */
1953 
1954 #define PHP_SNMP_PROPERTY_ENTRY_RECORD(name) \
1955 	{ "" #name "",		sizeof("" #name "") - 1,	php_snmp_read_##name,	php_snmp_write_##name }
1956 
1957 const php_snmp_prop_handler php_snmp_property_entries[] = {
1958 	PHP_SNMP_PROPERTY_ENTRY_RECORD(info),
1959 	PHP_SNMP_PROPERTY_ENTRY_RECORD(max_oids),
1960 	PHP_SNMP_PROPERTY_ENTRY_RECORD(valueretrieval),
1961 	PHP_SNMP_PROPERTY_ENTRY_RECORD(quick_print),
1962 	PHP_SNMP_PROPERTY_ENTRY_RECORD(enum_print),
1963 	PHP_SNMP_PROPERTY_ENTRY_RECORD(oid_output_format),
1964 	PHP_SNMP_PROPERTY_ENTRY_RECORD(oid_increasing_check),
1965 	PHP_SNMP_PROPERTY_ENTRY_RECORD(exceptions_enabled),
1966 	{ NULL, 0, NULL, NULL}
1967 };
1968 /* }}} */
1969 
1970 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(snmp)1971 PHP_MINIT_FUNCTION(snmp)
1972 {
1973 	netsnmp_log_handler *logh;
1974 	zend_class_entry ce, cex;
1975 
1976 	init_snmp("snmpapp");
1977 	/* net-snmp corrupts the CTYPE locale during initialization. */
1978 	setlocale(LC_CTYPE, "C");
1979 
1980 #ifdef NETSNMP_DS_LIB_DONT_PERSIST_STATE
1981 	/* Prevent update of the snmpapp.conf file */
1982 	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
1983 #endif
1984 
1985 	/* Disable logging, use exit status'es and related variabled to detect errors */
1986 	shutdown_snmp_logging();
1987 	logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_NONE, LOG_ERR);
1988 	if (logh) {
1989 		logh->pri_max = LOG_ERR;
1990 	}
1991 
1992 	memcpy(&php_snmp_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
1993 	php_snmp_object_handlers.read_property = php_snmp_read_property;
1994 	php_snmp_object_handlers.write_property = php_snmp_write_property;
1995 	php_snmp_object_handlers.has_property = php_snmp_has_property;
1996 	php_snmp_object_handlers.get_properties = php_snmp_get_properties;
1997 	php_snmp_object_handlers.get_gc = php_snmp_get_gc;
1998 
1999 	/* Register SNMP Class */
2000 	INIT_CLASS_ENTRY(ce, "SNMP", class_SNMP_methods);
2001 	ce.create_object = php_snmp_object_new;
2002 	php_snmp_object_handlers.offset = XtOffsetOf(php_snmp_object, zo);
2003 	php_snmp_object_handlers.clone_obj = NULL;
2004 	php_snmp_object_handlers.free_obj = php_snmp_object_free_storage;
2005 	php_snmp_ce = zend_register_internal_class(&ce);
2006 
2007 	/* Register SNMP Class properties */
2008 	zend_hash_init(&php_snmp_properties, 0, NULL, free_php_snmp_properties, 1);
2009 	PHP_SNMP_ADD_PROPERTIES(&php_snmp_properties, php_snmp_property_entries);
2010 
2011 	REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_SUFFIX",	NETSNMP_OID_OUTPUT_SUFFIX,	CONST_CS | CONST_PERSISTENT);
2012 	REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_MODULE",	NETSNMP_OID_OUTPUT_MODULE,	CONST_CS | CONST_PERSISTENT);
2013 	REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_FULL",		NETSNMP_OID_OUTPUT_FULL,	CONST_CS | CONST_PERSISTENT);
2014 	REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_NUMERIC",	NETSNMP_OID_OUTPUT_NUMERIC,	CONST_CS | CONST_PERSISTENT);
2015 	REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_UCD",		NETSNMP_OID_OUTPUT_UCD,		CONST_CS | CONST_PERSISTENT);
2016 	REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_NONE",		NETSNMP_OID_OUTPUT_NONE,	CONST_CS | CONST_PERSISTENT);
2017 
2018 	REGISTER_LONG_CONSTANT("SNMP_VALUE_LIBRARY",	SNMP_VALUE_LIBRARY,	CONST_CS | CONST_PERSISTENT);
2019 	REGISTER_LONG_CONSTANT("SNMP_VALUE_PLAIN",	SNMP_VALUE_PLAIN,	CONST_CS | CONST_PERSISTENT);
2020 	REGISTER_LONG_CONSTANT("SNMP_VALUE_OBJECT",	SNMP_VALUE_OBJECT,	CONST_CS | CONST_PERSISTENT);
2021 
2022 	REGISTER_LONG_CONSTANT("SNMP_BIT_STR",		ASN_BIT_STR,	CONST_CS | CONST_PERSISTENT);
2023 	REGISTER_LONG_CONSTANT("SNMP_OCTET_STR",	ASN_OCTET_STR,	CONST_CS | CONST_PERSISTENT);
2024 	REGISTER_LONG_CONSTANT("SNMP_OPAQUE",		ASN_OPAQUE,	CONST_CS | CONST_PERSISTENT);
2025 	REGISTER_LONG_CONSTANT("SNMP_NULL",		ASN_NULL,	CONST_CS | CONST_PERSISTENT);
2026 	REGISTER_LONG_CONSTANT("SNMP_OBJECT_ID",	ASN_OBJECT_ID,	CONST_CS | CONST_PERSISTENT);
2027 	REGISTER_LONG_CONSTANT("SNMP_IPADDRESS",	ASN_IPADDRESS,	CONST_CS | CONST_PERSISTENT);
2028 	REGISTER_LONG_CONSTANT("SNMP_COUNTER",		ASN_GAUGE,	CONST_CS | CONST_PERSISTENT);
2029 	REGISTER_LONG_CONSTANT("SNMP_UNSIGNED",		ASN_UNSIGNED,	CONST_CS | CONST_PERSISTENT);
2030 	REGISTER_LONG_CONSTANT("SNMP_TIMETICKS",	ASN_TIMETICKS,	CONST_CS | CONST_PERSISTENT);
2031 	REGISTER_LONG_CONSTANT("SNMP_UINTEGER",		ASN_UINTEGER,	CONST_CS | CONST_PERSISTENT);
2032 	REGISTER_LONG_CONSTANT("SNMP_INTEGER",		ASN_INTEGER,	CONST_CS | CONST_PERSISTENT);
2033 	REGISTER_LONG_CONSTANT("SNMP_COUNTER64",	ASN_COUNTER64,	CONST_CS | CONST_PERSISTENT);
2034 
2035 	REGISTER_SNMP_CLASS_CONST_LONG("VERSION_1",			SNMP_VERSION_1);
2036 	REGISTER_SNMP_CLASS_CONST_LONG("VERSION_2c",			SNMP_VERSION_2c);
2037 	REGISTER_SNMP_CLASS_CONST_LONG("VERSION_2C",			SNMP_VERSION_2c);
2038 	REGISTER_SNMP_CLASS_CONST_LONG("VERSION_3",			SNMP_VERSION_3);
2039 
2040 	REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_NOERROR",			PHP_SNMP_ERRNO_NOERROR);
2041 	REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_ANY",			PHP_SNMP_ERRNO_ANY);
2042 	REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_GENERIC",			PHP_SNMP_ERRNO_GENERIC);
2043 	REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_TIMEOUT",			PHP_SNMP_ERRNO_TIMEOUT);
2044 	REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_ERROR_IN_REPLY",		PHP_SNMP_ERRNO_ERROR_IN_REPLY);
2045 	REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_OID_NOT_INCREASING",	PHP_SNMP_ERRNO_OID_NOT_INCREASING);
2046 	REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_OID_PARSING_ERROR",	PHP_SNMP_ERRNO_OID_PARSING_ERROR);
2047 	REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_MULTIPLE_SET_QUERIES",	PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES);
2048 
2049 	/* Register SNMPException class */
2050 	INIT_CLASS_ENTRY(cex, "SNMPException", NULL);
2051 	php_snmp_exception_ce = zend_register_internal_class_ex(&cex, spl_ce_RuntimeException);
2052 
2053 	return SUCCESS;
2054 }
2055 /* }}} */
2056 
2057 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(snmp)2058 PHP_MSHUTDOWN_FUNCTION(snmp)
2059 {
2060 	snmp_shutdown("snmpapp");
2061 
2062 	zend_hash_destroy(&php_snmp_properties);
2063 
2064 	return SUCCESS;
2065 }
2066 /* }}} */
2067 
2068 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(snmp)2069 PHP_MINFO_FUNCTION(snmp)
2070 {
2071 	php_info_print_table_start();
2072 	php_info_print_table_row(2, "NET-SNMP Support", "enabled");
2073 	php_info_print_table_row(2, "NET-SNMP Version", netsnmp_get_version());
2074 	php_info_print_table_end();
2075 }
2076 /* }}} */
2077 
2078 /* {{{ snmp_module_deps[] */
2079 static const zend_module_dep snmp_module_deps[] = {
2080 	ZEND_MOD_REQUIRED("spl")
2081 	ZEND_MOD_END
2082 };
2083 /* }}} */
2084 
2085 /* {{{ snmp_module_entry */
2086 zend_module_entry snmp_module_entry = {
2087 	STANDARD_MODULE_HEADER_EX,
2088 	NULL,
2089 	snmp_module_deps,
2090 	"snmp",
2091 	ext_functions,
2092 	PHP_MINIT(snmp),
2093 	PHP_MSHUTDOWN(snmp),
2094 	NULL,
2095 	NULL,
2096 	PHP_MINFO(snmp),
2097 	PHP_SNMP_VERSION,
2098 	PHP_MODULE_GLOBALS(snmp),
2099 	PHP_GINIT(snmp),
2100 	NULL,
2101 	NULL,
2102 	STANDARD_MODULE_PROPERTIES_EX
2103 };
2104 /* }}} */
2105 
2106 #endif
2107