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