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