Annotation of embedaddon/php/ext/snmp/snmp.c, revision 1.1.1.5

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.5 ! misho       5:    | Copyright (c) 1997-2014 The PHP Group                                |
1.1       misho       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>                         |
1.1.1.2   misho      20:    |          Boris Lytockin <lytboris@gmail.com>                         |
1.1       misho      21:    +----------------------------------------------------------------------+
                     22:  */
                     23: 
1.1.1.2   misho      24: /* $Id$ */
1.1       misho      25: 
                     26: #ifdef HAVE_CONFIG_H
                     27: #include "config.h"
                     28: #endif
                     29: 
                     30: #include "php.h"
1.1.1.2   misho      31: #include "main/php_network.h"
1.1       misho      32: #include "ext/standard/info.h"
                     33: #include "php_snmp.h"
                     34: 
1.1.1.2   misho      35: #include "zend_exceptions.h"
                     36: 
                     37: #if HAVE_SPL
                     38: #include "ext/spl/spl_exceptions.h"
                     39: #endif
                     40: 
1.1       misho      41: #if HAVE_SNMP
                     42: 
                     43: #include <sys/types.h>
                     44: #ifdef PHP_WIN32
                     45: #include <winsock2.h>
                     46: #include <errno.h>
                     47: #include <process.h>
                     48: #include "win32/time.h"
                     49: #elif defined(NETWARE)
                     50: #ifdef USE_WINSOCK
                     51: #include <novsock2.h>
                     52: #else
                     53: #include <sys/socket.h>
                     54: #endif
                     55: #include <errno.h>
                     56: #include <sys/timeval.h>
                     57: #else
                     58: #include <sys/socket.h>
                     59: #include <netinet/in.h>
                     60: #include <arpa/inet.h>
                     61: #ifndef _OSD_POSIX
                     62: #include <sys/errno.h>
                     63: #else
                     64: #include <errno.h>  /* BS2000/OSD uses <errno.h>, not <sys/errno.h> */
                     65: #endif
                     66: #include <netdb.h>
                     67: #endif
                     68: #ifdef HAVE_UNISTD_H
                     69: #include <unistd.h>
                     70: #endif
                     71: 
                     72: #ifndef __P
                     73: #ifdef __GNUC__
                     74: #define __P(args) args
                     75: #else
                     76: #define __P(args) ()
                     77: #endif
                     78: #endif
                     79: 
                     80: #include <net-snmp/net-snmp-config.h>
                     81: #include <net-snmp/net-snmp-includes.h>
                     82: 
1.1.1.2   misho      83: /* For net-snmp prior to 5.4 */
                     84: #ifndef HAVE_SHUTDOWN_SNMP_LOGGING
                     85: extern netsnmp_log_handler *logh_head;
                     86: #define shutdown_snmp_logging() \
                     87:        { \
                     88:                snmp_disable_log(); \
                     89:                while(NULL != logh_head) \
                     90:                        netsnmp_remove_loghandler( logh_head ); \
                     91:        }
1.1       misho      92: #endif
                     93: 
1.1.1.2   misho      94: #define SNMP_VALUE_LIBRARY     (0 << 0)
                     95: #define SNMP_VALUE_PLAIN       (1 << 0)
                     96: #define SNMP_VALUE_OBJECT      (1 << 1)
                     97: 
                     98: typedef struct snmp_session php_snmp_session;
                     99: #define PHP_SNMP_SESSION_RES_NAME "SNMP session"
                    100: 
                    101: #define PHP_SNMP_ADD_PROPERTIES(a, b) \
                    102: { \
                    103:        int i = 0; \
                    104:        while (b[i].name != NULL) { \
                    105:                php_snmp_add_property((a), (b)[i].name, (b)[i].name_length, \
                    106:                                                        (php_snmp_read_t)(b)[i].read_func, (php_snmp_write_t)(b)[i].write_func TSRMLS_CC); \
                    107:                i++; \
                    108:        } \
                    109: }
                    110: 
                    111: #define PHP_SNMP_ERRNO_NOERROR                 0
                    112: #define PHP_SNMP_ERRNO_GENERIC                 (1 << 1)
                    113: #define PHP_SNMP_ERRNO_TIMEOUT                 (1 << 2)
                    114: #define PHP_SNMP_ERRNO_ERROR_IN_REPLY          (1 << 3)
                    115: #define PHP_SNMP_ERRNO_OID_NOT_INCREASING      (1 << 4)
                    116: #define PHP_SNMP_ERRNO_OID_PARSING_ERROR       (1 << 5)
                    117: #define PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES    (1 << 6)
                    118: #define PHP_SNMP_ERRNO_ANY     ( \
                    119:                PHP_SNMP_ERRNO_GENERIC | \
                    120:                PHP_SNMP_ERRNO_TIMEOUT | \
                    121:                PHP_SNMP_ERRNO_ERROR_IN_REPLY | \
                    122:                PHP_SNMP_ERRNO_OID_NOT_INCREASING | \
                    123:                PHP_SNMP_ERRNO_OID_PARSING_ERROR | \
                    124:                PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES | \
                    125:                PHP_SNMP_ERRNO_NOERROR \
                    126:        )
1.1       misho     127: 
                    128: ZEND_DECLARE_MODULE_GLOBALS(snmp)
                    129: static PHP_GINIT_FUNCTION(snmp);
                    130: 
                    131: /* constant - can be shared among threads */
                    132: static oid objid_mib[] = {1, 3, 6, 1, 2, 1};
                    133: 
1.1.1.2   misho     134: static int le_snmp_session;
                    135: 
                    136: /* Handlers */
                    137: static zend_object_handlers php_snmp_object_handlers;
                    138: 
                    139: /* Class entries */
                    140: zend_class_entry *php_snmp_ce;
                    141: zend_class_entry *php_snmp_exception_ce;
                    142: 
                    143: /* Class object properties */
                    144: static HashTable php_snmp_properties;
                    145: 
1.1       misho     146: /* {{{ arginfo */
1.1.1.2   misho     147: 
1.1       misho     148: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpget, 0, 0, 3)
                    149:        ZEND_ARG_INFO(0, host)
                    150:        ZEND_ARG_INFO(0, community)
                    151:        ZEND_ARG_INFO(0, object_id)
                    152:        ZEND_ARG_INFO(0, timeout)
                    153:        ZEND_ARG_INFO(0, retries)
                    154: ZEND_END_ARG_INFO()
                    155: 
                    156: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpgetnext, 0, 0, 3)
                    157:        ZEND_ARG_INFO(0, host)
                    158:        ZEND_ARG_INFO(0, community)
                    159:        ZEND_ARG_INFO(0, object_id)
                    160:        ZEND_ARG_INFO(0, timeout)
                    161:        ZEND_ARG_INFO(0, retries)
                    162: ZEND_END_ARG_INFO()
                    163: 
                    164: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpwalk, 0, 0, 3)
                    165:        ZEND_ARG_INFO(0, host)
                    166:        ZEND_ARG_INFO(0, community)
                    167:        ZEND_ARG_INFO(0, object_id)
                    168:        ZEND_ARG_INFO(0, timeout)
                    169:        ZEND_ARG_INFO(0, retries)
                    170: ZEND_END_ARG_INFO()
                    171: 
                    172: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmprealwalk, 0, 0, 3)
                    173:        ZEND_ARG_INFO(0, host)
                    174:        ZEND_ARG_INFO(0, community)
                    175:        ZEND_ARG_INFO(0, object_id)
                    176:        ZEND_ARG_INFO(0, timeout)
                    177:        ZEND_ARG_INFO(0, retries)
                    178: ZEND_END_ARG_INFO()
                    179: 
1.1.1.2   misho     180: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmpset, 0, 0, 5)
                    181:        ZEND_ARG_INFO(0, host)
                    182:        ZEND_ARG_INFO(0, community)
                    183:        ZEND_ARG_INFO(0, object_id)
                    184:        ZEND_ARG_INFO(0, type)
                    185:        ZEND_ARG_INFO(0, value)
                    186:        ZEND_ARG_INFO(0, timeout)
                    187:        ZEND_ARG_INFO(0, retries)
                    188: ZEND_END_ARG_INFO()
                    189: 
                    190: 
1.1       misho     191: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_get_quick_print, 0, 0, 1)
                    192:        ZEND_ARG_INFO(0, d)
                    193: ZEND_END_ARG_INFO()
                    194: 
                    195: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_quick_print, 0, 0, 1)
                    196:        ZEND_ARG_INFO(0, quick_print)
                    197: ZEND_END_ARG_INFO()
                    198: 
                    199: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_enum_print, 0, 0, 1)
                    200:        ZEND_ARG_INFO(0, enum_print)
                    201: ZEND_END_ARG_INFO()
                    202: 
                    203: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_oid_output_format, 0, 0, 1)
                    204:        ZEND_ARG_INFO(0, oid_format)
                    205: ZEND_END_ARG_INFO()
                    206: 
                    207: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_get, 0, 0, 3)
                    208:        ZEND_ARG_INFO(0, host)
                    209:        ZEND_ARG_INFO(0, community)
                    210:        ZEND_ARG_INFO(0, object_id)
                    211:        ZEND_ARG_INFO(0, timeout)
                    212:        ZEND_ARG_INFO(0, retries)
                    213: ZEND_END_ARG_INFO()
                    214: 
                    215: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_getnext, 0, 0, 3)
                    216:        ZEND_ARG_INFO(0, host)
                    217:        ZEND_ARG_INFO(0, community)
                    218:        ZEND_ARG_INFO(0, object_id)
                    219:        ZEND_ARG_INFO(0, timeout)
                    220:        ZEND_ARG_INFO(0, retries)
                    221: ZEND_END_ARG_INFO()
                    222: 
                    223: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_walk, 0, 0, 3)
                    224:        ZEND_ARG_INFO(0, host)
                    225:        ZEND_ARG_INFO(0, community)
                    226:        ZEND_ARG_INFO(0, object_id)
                    227:        ZEND_ARG_INFO(0, timeout)
                    228:        ZEND_ARG_INFO(0, retries)
                    229: ZEND_END_ARG_INFO()
                    230: 
                    231: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_real_walk, 0, 0, 3)
                    232:        ZEND_ARG_INFO(0, host)
                    233:        ZEND_ARG_INFO(0, community)
                    234:        ZEND_ARG_INFO(0, object_id)
                    235:        ZEND_ARG_INFO(0, timeout)
                    236:        ZEND_ARG_INFO(0, retries)
                    237: ZEND_END_ARG_INFO()
                    238: 
                    239: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp2_set, 0, 0, 5)
                    240:        ZEND_ARG_INFO(0, host)
                    241:        ZEND_ARG_INFO(0, community)
                    242:        ZEND_ARG_INFO(0, object_id)
                    243:        ZEND_ARG_INFO(0, type)
                    244:        ZEND_ARG_INFO(0, value)
                    245:        ZEND_ARG_INFO(0, timeout)
                    246:        ZEND_ARG_INFO(0, retries)
                    247: ZEND_END_ARG_INFO()
                    248: 
                    249: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_get, 0, 0, 8)
                    250:        ZEND_ARG_INFO(0, host)
                    251:        ZEND_ARG_INFO(0, sec_name)
                    252:        ZEND_ARG_INFO(0, sec_level)
                    253:        ZEND_ARG_INFO(0, auth_protocol)
                    254:        ZEND_ARG_INFO(0, auth_passphrase)
                    255:        ZEND_ARG_INFO(0, priv_protocol)
                    256:        ZEND_ARG_INFO(0, priv_passphrase)
                    257:        ZEND_ARG_INFO(0, object_id)
                    258:        ZEND_ARG_INFO(0, timeout)
                    259:        ZEND_ARG_INFO(0, retries)
                    260: ZEND_END_ARG_INFO()
                    261: 
                    262: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_getnext, 0, 0, 8)
                    263:        ZEND_ARG_INFO(0, host)
                    264:        ZEND_ARG_INFO(0, sec_name)
                    265:        ZEND_ARG_INFO(0, sec_level)
                    266:        ZEND_ARG_INFO(0, auth_protocol)
                    267:        ZEND_ARG_INFO(0, auth_passphrase)
                    268:        ZEND_ARG_INFO(0, priv_protocol)
                    269:        ZEND_ARG_INFO(0, priv_passphrase)
                    270:        ZEND_ARG_INFO(0, object_id)
                    271:        ZEND_ARG_INFO(0, timeout)
                    272:        ZEND_ARG_INFO(0, retries)
                    273: ZEND_END_ARG_INFO()
                    274: 
                    275: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_walk, 0, 0, 8)
                    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, timeout)
                    285:        ZEND_ARG_INFO(0, retries)
                    286: ZEND_END_ARG_INFO()
                    287: 
                    288: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_real_walk, 0, 0, 8)
                    289:        ZEND_ARG_INFO(0, host)
                    290:        ZEND_ARG_INFO(0, sec_name)
                    291:        ZEND_ARG_INFO(0, sec_level)
                    292:        ZEND_ARG_INFO(0, auth_protocol)
                    293:        ZEND_ARG_INFO(0, auth_passphrase)
                    294:        ZEND_ARG_INFO(0, priv_protocol)
                    295:        ZEND_ARG_INFO(0, priv_passphrase)
                    296:        ZEND_ARG_INFO(0, object_id)
                    297:        ZEND_ARG_INFO(0, timeout)
                    298:        ZEND_ARG_INFO(0, retries)
                    299: ZEND_END_ARG_INFO()
                    300: 
                    301: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp3_set, 0, 0, 10)
                    302:        ZEND_ARG_INFO(0, host)
                    303:        ZEND_ARG_INFO(0, sec_name)
                    304:        ZEND_ARG_INFO(0, sec_level)
                    305:        ZEND_ARG_INFO(0, auth_protocol)
                    306:        ZEND_ARG_INFO(0, auth_passphrase)
                    307:        ZEND_ARG_INFO(0, priv_protocol)
                    308:        ZEND_ARG_INFO(0, priv_passphrase)
                    309:        ZEND_ARG_INFO(0, object_id)
                    310:        ZEND_ARG_INFO(0, type)
                    311:        ZEND_ARG_INFO(0, value)
                    312:        ZEND_ARG_INFO(0, timeout)
                    313:        ZEND_ARG_INFO(0, retries)
                    314: ZEND_END_ARG_INFO()
                    315: 
                    316: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set_valueretrieval, 0, 0, 1)
                    317:        ZEND_ARG_INFO(0, method)
                    318: ZEND_END_ARG_INFO()
                    319: 
                    320: ZEND_BEGIN_ARG_INFO(arginfo_snmp_get_valueretrieval, 0)
                    321: ZEND_END_ARG_INFO()
                    322: 
                    323: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_read_mib, 0, 0, 1)
                    324:        ZEND_ARG_INFO(0, filename)
                    325: ZEND_END_ARG_INFO()
1.1.1.2   misho     326: 
                    327: /* OO arginfo */
                    328: 
                    329: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_create, 0, 0, 3)
                    330:        ZEND_ARG_INFO(0, version)
                    331:        ZEND_ARG_INFO(0, host)
                    332:        ZEND_ARG_INFO(0, community)
                    333:        ZEND_ARG_INFO(0, timeout)
                    334:        ZEND_ARG_INFO(0, retries)
                    335: ZEND_END_ARG_INFO()
                    336: 
                    337: ZEND_BEGIN_ARG_INFO(arginfo_snmp_void, 0)
                    338: ZEND_END_ARG_INFO()
                    339: 
                    340: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_setSecurity, 0, 0, 8)
                    341:        ZEND_ARG_INFO(0, session)
                    342:        ZEND_ARG_INFO(0, sec_level)
                    343:        ZEND_ARG_INFO(0, auth_protocol)
                    344:        ZEND_ARG_INFO(0, auth_passphrase)
                    345:        ZEND_ARG_INFO(0, priv_protocol)
                    346:        ZEND_ARG_INFO(0, priv_passphrase)
                    347:        ZEND_ARG_INFO(0, contextName)
                    348:        ZEND_ARG_INFO(0, contextEngineID)
                    349:        ZEND_ARG_INFO(0, )
                    350: ZEND_END_ARG_INFO()
                    351: 
                    352: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_get, 0, 0, 1)
                    353:        ZEND_ARG_INFO(0, object_id)
                    354:        ZEND_ARG_INFO(0, use_orignames)
                    355: ZEND_END_ARG_INFO()
                    356: 
                    357: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_walk, 0, 0, 4)
                    358:        ZEND_ARG_INFO(0, object_id)
                    359:        ZEND_ARG_INFO(0, suffix_keys)
                    360:        ZEND_ARG_INFO(0, max_repetitions)
                    361:        ZEND_ARG_INFO(0, non_repeaters)
                    362: ZEND_END_ARG_INFO()
                    363: 
                    364: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_set, 0, 0, 3)
                    365:        ZEND_ARG_INFO(0, object_id)
                    366:        ZEND_ARG_INFO(0, type)
                    367:        ZEND_ARG_INFO(0, value)
                    368: ZEND_END_ARG_INFO()
                    369: 
                    370: ZEND_BEGIN_ARG_INFO_EX(arginfo_snmp_class_set_quick_print, 0, 0, 1)
                    371:        ZEND_ARG_INFO(0, quick_print)
                    372: ZEND_END_ARG_INFO()
1.1       misho     373: /* }}} */
                    374: 
1.1.1.2   misho     375: struct objid_query {
                    376:        int count;
                    377:        int offset;
                    378:        int step;
                    379:        long non_repeaters;
                    380:        long max_repetitions;
                    381:        int valueretrieval;
                    382:        int array_output;
                    383:        int oid_increasing_check;
                    384:        snmpobjarg *vars;
                    385: };
                    386: 
1.1       misho     387: /* {{{ snmp_functions[]
                    388:  */
                    389: const zend_function_entry snmp_functions[] = {
1.1.1.2   misho     390:        PHP_FE(snmpget,                                 arginfo_snmpget)
                    391:        PHP_FE(snmpgetnext,                             arginfo_snmpgetnext)
                    392:        PHP_FE(snmpwalk,                                arginfo_snmpwalk)
                    393:        PHP_FE(snmprealwalk,                            arginfo_snmprealwalk)
                    394:        PHP_FALIAS(snmpwalkoid, snmprealwalk,           arginfo_snmprealwalk)
                    395:        PHP_FE(snmpset,                                 arginfo_snmpset)
1.1       misho     396:        PHP_FE(snmp_get_quick_print,                    arginfo_snmp_get_quick_print)
                    397:        PHP_FE(snmp_set_quick_print,                    arginfo_snmp_set_quick_print)
                    398:        PHP_FE(snmp_set_enum_print,                     arginfo_snmp_set_enum_print)
                    399:        PHP_FE(snmp_set_oid_output_format,              arginfo_snmp_set_oid_output_format)
                    400:        PHP_FALIAS(snmp_set_oid_numeric_print, snmp_set_oid_output_format, arginfo_snmp_set_oid_output_format)
                    401: 
                    402:        PHP_FE(snmp2_get,                               arginfo_snmp2_get)
1.1.1.2   misho     403:        PHP_FE(snmp2_getnext,                           arginfo_snmp2_getnext)
1.1       misho     404:        PHP_FE(snmp2_walk,                              arginfo_snmp2_walk)
1.1.1.2   misho     405:        PHP_FE(snmp2_real_walk,                         arginfo_snmp2_real_walk)
1.1       misho     406:        PHP_FE(snmp2_set,                               arginfo_snmp2_set)
                    407: 
                    408:        PHP_FE(snmp3_get,                               arginfo_snmp3_get)
1.1.1.2   misho     409:        PHP_FE(snmp3_getnext,                           arginfo_snmp3_getnext)
1.1       misho     410:        PHP_FE(snmp3_walk,                              arginfo_snmp3_walk)
1.1.1.2   misho     411:        PHP_FE(snmp3_real_walk,                         arginfo_snmp3_real_walk)
1.1       misho     412:        PHP_FE(snmp3_set,                               arginfo_snmp3_set)
1.1.1.2   misho     413:        PHP_FE(snmp_set_valueretrieval,                 arginfo_snmp_set_valueretrieval)
                    414:        PHP_FE(snmp_get_valueretrieval,                 arginfo_snmp_get_valueretrieval)
1.1       misho     415: 
1.1.1.2   misho     416:        PHP_FE(snmp_read_mib,                           arginfo_snmp_read_mib)
1.1       misho     417:        PHP_FE_END
                    418: };
                    419: /* }}} */
                    420: 
1.1.1.2   misho     421: /* query an agent with GET method */
                    422: #define SNMP_CMD_GET           (1<<0)
                    423: /* query an agent with GETNEXT method */
                    424: #define SNMP_CMD_GETNEXT       (1<<1)
                    425: /* query an agent with SET method */
                    426: #define SNMP_CMD_SET           (1<<2)
                    427: /* walk the mib */
                    428: #define SNMP_CMD_WALK          (1<<3)
                    429: /* force values-only output */
                    430: #define SNMP_NUMERIC_KEYS      (1<<7)
                    431: /* use user-supplied OID names for keys in array output mode in GET method */
                    432: #define SNMP_ORIGINAL_NAMES_AS_KEYS    (1<<8)
                    433: /* use OID suffix (`index') for keys in array output mode in WALK  method */
                    434: #define SNMP_USE_SUFFIX_AS_KEYS        (1<<9)
1.1       misho     435: 
                    436: #ifdef COMPILE_DL_SNMP
                    437: ZEND_GET_MODULE(snmp)
                    438: #endif
                    439: 
                    440: /* THREAD_LS snmp_module php_snmp_module; - may need one of these at some point */
                    441: 
                    442: /* {{{ PHP_GINIT_FUNCTION
                    443:  */
                    444: static PHP_GINIT_FUNCTION(snmp)
                    445: {
                    446:        snmp_globals->valueretrieval = SNMP_VALUE_LIBRARY;
                    447: }
                    448: /* }}} */
                    449: 
1.1.1.2   misho     450: #define PHP_SNMP_SESSION_FREE(a) { \
                    451:        if ((*session)->a) { \
                    452:                efree((*session)->a); \
                    453:                (*session)->a = NULL; \
                    454:        } \
                    455: }
                    456: 
                    457: static void netsnmp_session_free(php_snmp_session **session)
1.1       misho     458: {
1.1.1.2   misho     459:        if (*session) {
                    460:                PHP_SNMP_SESSION_FREE(peername);
                    461:                PHP_SNMP_SESSION_FREE(community);
                    462:                PHP_SNMP_SESSION_FREE(securityName);
                    463:                PHP_SNMP_SESSION_FREE(contextEngineID);
                    464:                efree(*session);
                    465:                *session = NULL;
                    466:        }
                    467: }
1.1       misho     468: 
1.1.1.2   misho     469: static void php_snmp_session_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
                    470: {
                    471:        php_snmp_session *session = (php_snmp_session *)rsrc->ptr;
                    472:        netsnmp_session_free(&session);
                    473: }
1.1       misho     474: 
1.1.1.2   misho     475: static void php_snmp_object_free_storage(void *object TSRMLS_DC)
                    476: {
                    477:        php_snmp_object *intern = (php_snmp_object *)object;
                    478:        
                    479:        if (!intern) {
                    480:                return;
                    481:        }
1.1       misho     482: 
1.1.1.2   misho     483:        netsnmp_session_free(&(intern->session));
1.1       misho     484: 
1.1.1.2   misho     485:        zend_object_std_dtor(&intern->zo TSRMLS_CC);
                    486:        
                    487:        efree(intern);
1.1       misho     488: }
                    489: 
1.1.1.2   misho     490: static zend_object_value php_snmp_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
1.1       misho     491: {
1.1.1.2   misho     492:        zend_object_value retval;
                    493:        php_snmp_object *intern;
1.1       misho     494: 
1.1.1.2   misho     495:        /* Allocate memory for it */
                    496:        intern = emalloc(sizeof(php_snmp_object));
                    497:        memset(&intern->zo, 0, sizeof(php_snmp_object));
                    498: 
                    499:        zend_object_std_init(&intern->zo, class_type TSRMLS_CC);
                    500:        object_properties_init(&intern->zo, class_type);
                    501: 
                    502:        retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) php_snmp_object_free_storage, NULL TSRMLS_CC);
                    503:        retval.handlers = (zend_object_handlers *) &php_snmp_object_handlers;
                    504: 
                    505:        return retval;
                    506:        
1.1       misho     507: }
                    508: 
1.1.1.2   misho     509: /* {{{ php_snmp_error
                    510:  *
                    511:  * Record last SNMP-related error in object
                    512:  *
1.1       misho     513:  */
1.1.1.2   misho     514: static void php_snmp_error(zval *object, const char *docref TSRMLS_DC, int type, const char *format, ...)
1.1       misho     515: {
1.1.1.2   misho     516:        va_list args;
1.1.1.4   misho     517:        php_snmp_object *snmp_object = NULL;
1.1.1.2   misho     518: 
                    519:        if (object) {
                    520:                snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC);
                    521:                if (type == PHP_SNMP_ERRNO_NOERROR) {
                    522:                        memset(snmp_object->snmp_errstr, 0, sizeof(snmp_object->snmp_errstr));
                    523:                } else {
                    524:                        va_start(args, format);
                    525:                        vsnprintf(snmp_object->snmp_errstr, sizeof(snmp_object->snmp_errstr) - 1, format, args);
                    526:                        va_end(args);
                    527:                }
                    528:                snmp_object->snmp_errno = type;
                    529:        }
                    530: 
                    531:        if (type == PHP_SNMP_ERRNO_NOERROR) {
                    532:                return;
                    533:        }
                    534: 
                    535:        if (object && (snmp_object->exceptions_enabled & type)) {
1.1.1.5 ! misho     536:                zend_throw_exception_ex(php_snmp_exception_ce, type TSRMLS_CC, snmp_object->snmp_errstr);
1.1.1.2   misho     537:        } else {
                    538:                va_start(args, format);
                    539:                php_verror(docref, "", E_WARNING, format, args TSRMLS_CC);
                    540:                va_end(args);
                    541:        }
1.1       misho     542: }
1.1.1.2   misho     543: 
1.1       misho     544: /* }}} */
                    545: 
1.1.1.2   misho     546: /* {{{ php_snmp_getvalue
                    547: *
                    548: * SNMP value to zval converter
                    549: *
                    550: */
                    551: static void php_snmp_getvalue(struct variable_list *vars, zval *snmpval TSRMLS_DC, int valueretrieval)
1.1       misho     552: {
                    553:        zval *val;
1.1.1.3   misho     554:        char sbuf[512];
1.1.1.2   misho     555:        char *buf = &(sbuf[0]);
                    556:        char *dbuf = (char *)NULL;
                    557:        int buflen = sizeof(sbuf) - 1;
                    558:        int val_len = vars->val_len;
                    559:        
1.1.1.3   misho     560:        /* use emalloc() for large values, use static array otherwize */
                    561: 
                    562:        /* There is no way to know the size of buffer snprint_value() needs in order to print a value there.
                    563:         * So we are forced to probe it
                    564:         */
                    565:        while ((valueretrieval & SNMP_VALUE_PLAIN) == 0) {
                    566:                *buf = '\0';
                    567:                if (snprint_value(buf, buflen, vars->name, vars->name_length, vars) == -1) {
                    568:                        if (val_len > 512*1024) {
                    569:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "snprint_value() asks for a buffer more than 512k, Net-SNMP bug?");
                    570:                                break;
                    571:                        }
                    572:                         /* buffer is not long enough to hold full output, double it */
                    573:                        val_len *= 2;
                    574:                } else {
                    575:                        break;
                    576:                }
                    577: 
                    578:                if (buf == dbuf) {
                    579:                        dbuf = (char *)erealloc(dbuf, val_len + 1);
                    580:                } else {
                    581:                        dbuf = (char *)emalloc(val_len + 1);
                    582:                }
                    583: 
                    584:                if (!dbuf) {
                    585:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "emalloc() failed: %s, fallback to static buffer", strerror(errno));
                    586:                        buf = &(sbuf[0]);
                    587:                        buflen = sizeof(sbuf) - 1;
                    588:                        break;
                    589:                }
                    590: 
                    591:                buf = dbuf;
                    592:                buflen = val_len;
1.1.1.2   misho     593:        }
1.1       misho     594: 
1.1.1.3   misho     595:        if((valueretrieval & SNMP_VALUE_PLAIN) && val_len > buflen){
1.1.1.2   misho     596:                if ((dbuf = (char *)emalloc(val_len + 1))) {
                    597:                        buf = dbuf;
                    598:                        buflen = val_len;
                    599:                } else {
1.1.1.3   misho     600:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "emalloc() failed: %s, fallback to static buffer", strerror(errno));
1.1.1.2   misho     601:                }
1.1       misho     602:        }
                    603: 
                    604:        MAKE_STD_ZVAL(val);
                    605: 
1.1.1.2   misho     606:        if (valueretrieval & SNMP_VALUE_PLAIN) {
1.1.1.3   misho     607:                *buf = 0;
1.1.1.2   misho     608:                switch (vars->type) {
                    609:                case ASN_BIT_STR:               /* 0x03, asn1.h */
                    610:                        ZVAL_STRINGL(val, (char *)vars->val.bitstring, vars->val_len, 1);
                    611:                        break;
1.1       misho     612: 
1.1.1.2   misho     613:                case ASN_OCTET_STR:             /* 0x04, asn1.h */
                    614:                case ASN_OPAQUE:                /* 0x44, snmp_impl.h */
                    615:                        ZVAL_STRINGL(val, (char *)vars->val.string, vars->val_len, 1);
                    616:                        break;
1.1       misho     617: 
1.1.1.2   misho     618:                case ASN_NULL:                  /* 0x05, asn1.h */
                    619:                        ZVAL_NULL(val);
                    620:                        break;
1.1       misho     621: 
1.1.1.2   misho     622:                case ASN_OBJECT_ID:             /* 0x06, asn1.h */
                    623:                        snprint_objid(buf, buflen, vars->val.objid, vars->val_len / sizeof(oid));
                    624:                        ZVAL_STRING(val, buf, 1);
                    625:                        break;
1.1       misho     626: 
1.1.1.2   misho     627:                case ASN_IPADDRESS:             /* 0x40, snmp_impl.h */
                    628:                        snprintf(buf, buflen, "%d.%d.%d.%d",
                    629:                                 (vars->val.string)[0], (vars->val.string)[1],
                    630:                                 (vars->val.string)[2], (vars->val.string)[3]);
                    631:                        buf[buflen]=0;
                    632:                        ZVAL_STRING(val, buf, 1);
                    633:                        break;
1.1       misho     634: 
1.1.1.2   misho     635:                case ASN_COUNTER:               /* 0x41, snmp_impl.h */
                    636:                case ASN_GAUGE:                 /* 0x42, snmp_impl.h */
                    637:                /* ASN_UNSIGNED is the same as ASN_GAUGE */
                    638:                case ASN_TIMETICKS:             /* 0x43, snmp_impl.h */
                    639:                case ASN_UINTEGER:              /* 0x47, snmp_impl.h */
                    640:                        snprintf(buf, buflen, "%lu", *vars->val.integer);
                    641:                        buf[buflen]=0;
                    642:                        ZVAL_STRING(val, buf, 1);
                    643:                        break;
1.1       misho     644: 
1.1.1.2   misho     645:                case ASN_INTEGER:               /* 0x02, asn1.h */
                    646:                        snprintf(buf, buflen, "%ld", *vars->val.integer);
                    647:                        buf[buflen]=0;
                    648:                        ZVAL_STRING(val, buf, 1);
                    649:                        break;
1.1       misho     650: 
1.1.1.2   misho     651: #if defined(NETSNMP_WITH_OPAQUE_SPECIAL_TYPES) || defined(OPAQUE_SPECIAL_TYPES)
                    652:                case ASN_OPAQUE_FLOAT:          /* 0x78, asn1.h */
                    653:                        snprintf(buf, buflen, "%f", *vars->val.floatVal);
                    654:                        ZVAL_STRING(val, buf, 1);
                    655:                        break;
1.1       misho     656: 
1.1.1.2   misho     657:                case ASN_OPAQUE_DOUBLE:         /* 0x79, asn1.h */
                    658:                        snprintf(buf, buflen, "%Lf", *vars->val.doubleVal);
                    659:                        ZVAL_STRING(val, buf, 1);
                    660:                        break;
1.1       misho     661: 
1.1.1.2   misho     662:                case ASN_OPAQUE_I64:            /* 0x80, asn1.h */
                    663:                        printI64(buf, vars->val.counter64);
                    664:                        ZVAL_STRING(val, buf, 1);
                    665:                        break;
                    666: 
                    667:                case ASN_OPAQUE_U64:            /* 0x81, asn1.h */
                    668: #endif
                    669:                case ASN_COUNTER64:             /* 0x46, snmp_impl.h */
                    670:                        printU64(buf, vars->val.counter64);
                    671:                        ZVAL_STRING(val, buf, 1);
                    672:                        break;
                    673: 
                    674:                default:
                    675:                        ZVAL_STRING(val, "Unknown value type", 1);
                    676:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown value type: %u", vars->type);
                    677:                        break;
                    678:                }
                    679:        } else /* use Net-SNMP value translation */ {
1.1.1.3   misho     680:                /* we have desired string in buffer, just use it */
1.1.1.2   misho     681:                ZVAL_STRING(val, buf, 1);
1.1       misho     682:        }
                    683: 
1.1.1.2   misho     684:        if (valueretrieval & SNMP_VALUE_OBJECT) {
1.1       misho     685:                object_init(snmpval);
                    686:                add_property_long(snmpval, "type", vars->type);
                    687:                add_property_zval(snmpval, "value", val);
1.1.1.2   misho     688:        } else  {
                    689:                *snmpval = *val;
                    690:                zval_copy_ctor(snmpval);
                    691:        }
                    692:        zval_ptr_dtor(&val);
                    693: 
                    694:        if(dbuf){ /* malloc was used to store value */
                    695:                efree(dbuf);
1.1       misho     696:        }
                    697: }
1.1.1.2   misho     698: /* }}} */
1.1       misho     699: 
                    700: /* {{{ php_snmp_internal
                    701: *
1.1.1.2   misho     702: * SNMP object fetcher/setter for all SNMP versions
1.1       misho     703: *
                    704: */
                    705: static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st, 
                    706:                                                        struct snmp_session *session,
1.1.1.2   misho     707:                                                        struct objid_query *objid_query)
1.1       misho     708: {
                    709:        struct snmp_session *ss;
                    710:        struct snmp_pdu *pdu=NULL, *response;
                    711:        struct variable_list *vars;
                    712:        oid root[MAX_NAME_LEN];
                    713:        size_t rootlen = 0;
1.1.1.2   misho     714:        int status, count, found;
1.1       misho     715:        char buf[2048];
                    716:        char buf2[2048];
                    717:        int keepwalking=1;
                    718:        char *err;
                    719:        zval *snmpval = NULL;
1.1.1.2   misho     720:        int snmp_errno;
1.1       misho     721: 
1.1.1.3   misho     722:        /* we start with retval=FALSE. If any actual data is acquired, retval will be set to appropriate type */
1.1.1.2   misho     723:        RETVAL_FALSE;
                    724:        
                    725:        /* reset errno and errstr */
                    726:        php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_NOERROR, "");
1.1       misho     727: 
1.1.1.2   misho     728:        if (st & SNMP_CMD_WALK) { /* remember root OID */
                    729:                memmove((char *)root, (char *)(objid_query->vars[0].name), (objid_query->vars[0].name_length) * sizeof(oid));
                    730:                rootlen = objid_query->vars[0].name_length;
                    731:                objid_query->offset = objid_query->count;
1.1       misho     732:        }
                    733: 
                    734:        if ((ss = snmp_open(session)) == NULL) {
                    735:                snmp_error(session, NULL, NULL, &err);
                    736:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not open snmp connection: %s", err);
                    737:                free(err);
1.1.1.2   misho     738:                RETVAL_FALSE;
                    739:                return;
1.1       misho     740:        }
                    741: 
1.1.1.2   misho     742:        if ((st & SNMP_CMD_SET) && objid_query->count > objid_query->step) {
                    743:                php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES, "Can not fit all OIDs for SET query into one packet, using multiple queries");
1.1       misho     744:        }
                    745: 
                    746:        while (keepwalking) {
                    747:                keepwalking = 0;
1.1.1.2   misho     748:                if (st & SNMP_CMD_WALK) {
1.1       misho     749:                        if (session->version == SNMP_VERSION_1) {
                    750:                                pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
                    751:                        } else {
                    752:                                pdu = snmp_pdu_create(SNMP_MSG_GETBULK);
1.1.1.2   misho     753:                                pdu->non_repeaters = objid_query->non_repeaters;
                    754:                                pdu->max_repetitions = objid_query->max_repetitions;
                    755:                        }
                    756:                        snmp_add_null_var(pdu, objid_query->vars[0].name, objid_query->vars[0].name_length);
                    757:                } else {
                    758:                        if (st & SNMP_CMD_GET) {
                    759:                                pdu = snmp_pdu_create(SNMP_MSG_GET);
                    760:                        } else if (st & SNMP_CMD_GETNEXT) {
                    761:                                pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
                    762:                        } else if (st & SNMP_CMD_SET) {
                    763:                                pdu = snmp_pdu_create(SNMP_MSG_SET);
                    764:                        } else {
                    765:                                snmp_close(ss);
                    766:                                php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unknown SNMP command (internals)");
                    767:                                RETVAL_FALSE;
                    768:                                return;
                    769:                        }
                    770:                        for (count = 0; objid_query->offset < objid_query->count && count < objid_query->step; objid_query->offset++, count++){
                    771:                                if (st & SNMP_CMD_SET) {
                    772:                                        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))) {
                    773:                                                snprint_objid(buf, sizeof(buf), objid_query->vars[objid_query->offset].name, objid_query->vars[objid_query->offset].name_length);
                    774:                                                php_snmp_error(getThis(), NULL TSRMLS_CC, 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));
                    775:                                                snmp_free_pdu(pdu);
                    776:                                                snmp_close(ss);
                    777:                                                RETVAL_FALSE;
                    778:                                                return;
                    779:                                        }
                    780:                                } else {
                    781:                                        snmp_add_null_var(pdu, objid_query->vars[objid_query->offset].name, objid_query->vars[objid_query->offset].name_length);
                    782:                                }
                    783:                        }
                    784:                        if(pdu->variables == NULL){
                    785:                                snmp_free_pdu(pdu);
                    786:                                snmp_close(ss);
                    787:                                RETVAL_FALSE;
                    788:                                return;
1.1       misho     789:                        }
                    790:                }
                    791: 
                    792: retry:
                    793:                status = snmp_synch_response(ss, pdu, &response);
                    794:                if (status == STAT_SUCCESS) {
                    795:                        if (response->errstat == SNMP_ERR_NOERROR) {
1.1.1.2   misho     796:                                if (st & SNMP_CMD_SET) {
                    797:                                        if (objid_query->offset < objid_query->count) { /* we have unprocessed OIDs */
                    798:                                                keepwalking = 1;
                    799:                                                continue;
                    800:                                        }
                    801:                                        snmp_free_pdu(response);
                    802:                                        snmp_close(ss);
                    803:                                        RETVAL_TRUE;
                    804:                                        return;
                    805:                                }
1.1       misho     806:                                for (vars = response->variables; vars; vars = vars->next_variable) {
1.1.1.2   misho     807:                                        /* do not output errors as values */
                    808:                                        if (    vars->type == SNMP_ENDOFMIBVIEW || 
                    809:                                                vars->type == SNMP_NOSUCHOBJECT || 
                    810:                                                vars->type == SNMP_NOSUCHINSTANCE ) {
                    811:                                                if ((st & SNMP_CMD_WALK) && Z_TYPE_P(return_value) == IS_ARRAY) {
                    812:                                                        break;
                    813:                                                }
                    814:                                                snprint_objid(buf, sizeof(buf), vars->name, vars->name_length);
                    815:                                                snprint_value(buf2, sizeof(buf2), vars->name, vars->name_length, vars);
                    816:                                                php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at '%s': %s", buf, buf2);
                    817:                                                continue;
1.1       misho     818:                                        }
1.1.1.2   misho     819:                                        
                    820:                                        if ((st & SNMP_CMD_WALK) && 
                    821:                                                (vars->name_length < rootlen || memcmp(root, vars->name, rootlen * sizeof(oid)))) { /* not part of this subtree */
                    822:                                                if (Z_TYPE_P(return_value) == IS_ARRAY) { /* some records are fetched already, shut down further lookup */
                    823:                                                        keepwalking = 0;
                    824:                                                } else {
                    825:                                                        /* first fetched OID is out of subtree, fallback to GET query */
                    826:                                                        st |= SNMP_CMD_GET;
                    827:                                                        st ^= SNMP_CMD_WALK;
                    828:                                                        objid_query->offset = 0;
                    829:                                                        keepwalking = 1;
                    830:                                                }
                    831:                                                break;
1.1       misho     832:                                        }
                    833: 
1.1.1.2   misho     834:                                        MAKE_STD_ZVAL(snmpval);
                    835:                                        php_snmp_getvalue(vars, snmpval TSRMLS_CC, objid_query->valueretrieval);
                    836: 
                    837:                                        if (objid_query->array_output) {
                    838:                                                if (Z_TYPE_P(return_value) == IS_BOOL) {
                    839:                                                        array_init(return_value);
                    840:                                                }
                    841:                                                if (st & SNMP_NUMERIC_KEYS) {
                    842:                                                        add_next_index_zval(return_value, snmpval);
                    843:                                                } else if (st & SNMP_ORIGINAL_NAMES_AS_KEYS && st & SNMP_CMD_GET) {
                    844:                                                        found = 0;
                    845:                                                        for (count = 0; count < objid_query->count; count++) {
                    846:                                                                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) {
                    847:                                                                        found = 1;
                    848:                                                                        objid_query->vars[count].name_length = 0; /* mark this name as used */
                    849:                                                                        break;
                    850:                                                                }
                    851:                                                        }
                    852:                                                        if (found) {
                    853:                                                                add_assoc_zval(return_value, objid_query->vars[count].oid, snmpval);
                    854:                                                        } else {
                    855:                                                                snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
                    856:                                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not find original OID name for '%s'", buf2);
                    857:                                                        }
                    858:                                                } else if (st & SNMP_USE_SUFFIX_AS_KEYS && st & SNMP_CMD_WALK) {
                    859:                                                        snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
1.1.1.3   misho     860:                                                        if (rootlen <= vars->name_length && snmp_oid_compare(root, rootlen, vars->name, rootlen) == 0) {
1.1.1.2   misho     861:                                                                buf2[0] = '\0';
1.1.1.3   misho     862:                                                                count = rootlen;
1.1.1.2   misho     863:                                                                while(count < vars->name_length){
                    864:                                                                        sprintf(buf, "%lu.", vars->name[count]);
                    865:                                                                        strcat(buf2, buf);
                    866:                                                                        count++;
                    867:                                                                }
                    868:                                                                buf2[strlen(buf2) - 1] = '\0'; /* remove trailing '.' */
                    869:                                                        }
                    870:                                                        add_assoc_zval(return_value, buf2, snmpval);
                    871:                                                } else {
                    872:                                                        snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
                    873:                                                        add_assoc_zval(return_value, buf2, snmpval);
                    874:                                                }
                    875:                                        } else {
1.1       misho     876:                                                *return_value = *snmpval;
                    877:                                                zval_copy_ctor(return_value);
                    878:                                                zval_ptr_dtor(&snmpval);
1.1.1.2   misho     879:                                                break;
1.1       misho     880:                                        }
1.1.1.2   misho     881: 
                    882:                                        /* OID increase check */
                    883:                                        if (st & SNMP_CMD_WALK) {
                    884:                                                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) {
                    885:                                                        snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
                    886:                                                        php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_OID_NOT_INCREASING, "Error: OID not increasing: %s", buf2);
                    887:                                                        keepwalking = 0;
                    888:                                                } else {
                    889:                                                        memmove((char *)(objid_query->vars[0].name), (char *)vars->name, vars->name_length * sizeof(oid));
                    890:                                                        objid_query->vars[0].name_length = vars->name_length;
                    891:                                                        keepwalking = 1;
1.1       misho     892:                                                }
                    893:                                        }
1.1.1.2   misho     894:                                }
                    895:                                if (objid_query->offset < objid_query->count) { /* we have unprocessed OIDs */
                    896:                                        keepwalking = 1;
                    897:                                }
1.1       misho     898:                        } else {
1.1.1.5 ! misho     899:                                if (st & SNMP_CMD_WALK && response->errstat == SNMP_ERR_TOOBIG && objid_query->max_repetitions > 1) { /* Answer will not fit into single packet */
        !           900:                                        objid_query->max_repetitions /= 2;
        !           901:                                        snmp_free_pdu(response);
        !           902:                                        keepwalking = 1;
        !           903:                                        continue;
        !           904:                                }
1.1.1.2   misho     905:                                if (!(st & SNMP_CMD_WALK) || response->errstat != SNMP_ERR_NOSUCHNAME || Z_TYPE_P(return_value) == IS_BOOL) {
                    906:                                        for (   count=1, vars = response->variables;
                    907:                                                vars && count != response->errindex;
1.1       misho     908:                                                vars = vars->next_variable, count++);
1.1.1.2   misho     909: 
                    910:                                        if (st & (SNMP_CMD_GET | SNMP_CMD_GETNEXT) && response->errstat == SNMP_ERR_TOOBIG && objid_query->step > 1) { /* Answer will not fit into single packet */
                    911:                                                objid_query->offset = ((objid_query->offset > objid_query->step) ? (objid_query->offset - objid_query->step) : 0 );
                    912:                                                objid_query->step /= 2;
                    913:                                                snmp_free_pdu(response);
                    914:                                                keepwalking = 1;
                    915:                                                continue;
1.1       misho     916:                                        }
1.1.1.2   misho     917:                                        if (vars) {
                    918:                                                snprint_objid(buf, sizeof(buf), vars->name, vars->name_length);
                    919:                                                php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at '%s': %s", buf, snmp_errstring(response->errstat));
                    920:                                        } else {
                    921:                                                php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at %u object_id: %s", response->errindex, snmp_errstring(response->errstat));
                    922:                                        }
                    923:                                        if (st & (SNMP_CMD_GET | SNMP_CMD_GETNEXT)) { /* cut out bogus OID and retry */
                    924:                                                if ((pdu = snmp_fix_pdu(response, ((st & SNMP_CMD_GET) ? SNMP_MSG_GET : SNMP_MSG_GETNEXT) )) != NULL) {
1.1       misho     925:                                                        snmp_free_pdu(response);
                    926:                                                        goto retry;
                    927:                                                }
                    928:                                        }
                    929:                                        snmp_free_pdu(response);
                    930:                                        snmp_close(ss);
1.1.1.2   misho     931:                                        if (objid_query->array_output) {
1.1       misho     932:                                                zval_dtor(return_value);
                    933:                                        }
1.1.1.2   misho     934:                                        RETVAL_FALSE;
                    935:                                        return;
1.1       misho     936:                                }
                    937:                        }
                    938:                } else if (status == STAT_TIMEOUT) {
1.1.1.2   misho     939:                        php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_TIMEOUT, "No response from %s", session->peername);
                    940:                        if (objid_query->array_output) {
1.1       misho     941:                                zval_dtor(return_value);
                    942:                        }
                    943:                        snmp_close(ss);
1.1.1.2   misho     944:                        RETVAL_FALSE;
                    945:                        return;
1.1       misho     946:                } else {    /* status == STAT_ERROR */
1.1.1.2   misho     947:                        snmp_error(ss, NULL, NULL, &err);
                    948:                        php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_GENERIC, "Fatal error: %s", err);
                    949:                        free(err);
                    950:                        if (objid_query->array_output) {
1.1       misho     951:                                zval_dtor(return_value);
                    952:                        }
                    953:                        snmp_close(ss);
1.1.1.2   misho     954:                        RETVAL_FALSE;
                    955:                        return;
1.1       misho     956:                }
                    957:                if (response) {
                    958:                        snmp_free_pdu(response);
                    959:                }
                    960:        } /* keepwalking */
                    961:        snmp_close(ss);
                    962: }
                    963: /* }}} */
                    964: 
1.1.1.2   misho     965: /* {{{ php_snmp_parse_oid
1.1       misho     966: *
1.1.1.2   misho     967: * OID parser (and type, value for SNMP_SET command)
1.1       misho     968: */
1.1.1.2   misho     969: 
                    970: static int php_snmp_parse_oid(zval *object, int st, struct objid_query *objid_query, zval **oid, zval **type, zval **value TSRMLS_DC)
1.1       misho     971: {
                    972:        char *pptr;
1.1.1.2   misho     973:        HashPosition pos_oid, pos_type, pos_value;
                    974:        zval **tmp_oid, **tmp_type, **tmp_value;
1.1       misho     975: 
1.1.1.2   misho     976:        if (Z_TYPE_PP(oid) != IS_ARRAY) {
                    977:                if (Z_ISREF_PP(oid)) {
                    978:                        SEPARATE_ZVAL(oid);
1.1       misho     979:                }
1.1.1.2   misho     980:                convert_to_string_ex(oid);
                    981:        } else if (Z_TYPE_PP(oid) == IS_ARRAY) {
                    982:                zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(oid), &pos_oid);
1.1       misho     983:        }
                    984: 
1.1.1.2   misho     985:        if (st & SNMP_CMD_SET) {
                    986:                if (Z_TYPE_PP(type) != IS_ARRAY) {
                    987:                        if (Z_ISREF_PP(type)) {
                    988:                                SEPARATE_ZVAL(type);
                    989:                        }
                    990:                        convert_to_string_ex(type);
                    991:                } else if (Z_TYPE_PP(type) == IS_ARRAY) {
                    992:                        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(type), &pos_type);
                    993:                }
1.1       misho     994: 
1.1.1.2   misho     995:                if (Z_TYPE_PP(value) != IS_ARRAY) {
                    996:                        if (Z_ISREF_PP(value)) {
                    997:                                SEPARATE_ZVAL(value);
                    998:                        }
                    999:                        convert_to_string_ex(value);
                   1000:                } else if (Z_TYPE_PP(value) == IS_ARRAY) {
                   1001:                        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(value), &pos_value);
                   1002:                }
1.1       misho    1003:        }
                   1004: 
1.1.1.2   misho    1005:        objid_query->count = 0;
                   1006:        objid_query->array_output = ((st & SNMP_CMD_WALK) ? TRUE : FALSE);
                   1007:        if (Z_TYPE_PP(oid) == IS_STRING) {
                   1008:                objid_query->vars = (snmpobjarg *)emalloc(sizeof(snmpobjarg));
                   1009:                if (objid_query->vars == NULL) {
                   1010:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "emalloc() failed while parsing oid: %s", strerror(errno));
                   1011:                        efree(objid_query->vars);
                   1012:                        return FALSE;
                   1013:                }
                   1014:                objid_query->vars[objid_query->count].oid = Z_STRVAL_PP(oid);
                   1015:                if (st & SNMP_CMD_SET) {
                   1016:                        if (Z_TYPE_PP(type) == IS_STRING && Z_TYPE_PP(value) == IS_STRING) {
                   1017:                                if (Z_STRLEN_PP(type) != 1) {
                   1018:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bogus type '%s', should be single char, got %u", Z_STRVAL_PP(type), Z_STRLEN_PP(type));
                   1019:                                        efree(objid_query->vars);
                   1020:                                        return FALSE;
                   1021:                                }
                   1022:                                pptr = Z_STRVAL_PP(type);
                   1023:                                objid_query->vars[objid_query->count].type = *pptr;
                   1024:                                objid_query->vars[objid_query->count].value = Z_STRVAL_PP(value);
                   1025:                        } else {
                   1026:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Single objid and multiple type or values are not supported");
                   1027:                                efree(objid_query->vars);
                   1028:                                return FALSE;
                   1029:                        }
                   1030:                }
                   1031:                objid_query->count++;
                   1032:        } else if (Z_TYPE_PP(oid) == IS_ARRAY) { /* we got objid array */
                   1033:                if (zend_hash_num_elements(Z_ARRVAL_PP(oid)) == 0) {
                   1034:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Got empty OID array");
                   1035:                        return FALSE;
                   1036:                }
                   1037:                objid_query->vars = (snmpobjarg *)emalloc(sizeof(snmpobjarg) * zend_hash_num_elements(Z_ARRVAL_PP(oid)));
                   1038:                if (objid_query->vars == NULL) {
                   1039:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "emalloc() failed while parsing oid array: %s", strerror(errno));
                   1040:                        efree(objid_query->vars);
                   1041:                        return FALSE;
                   1042:                }
                   1043:                objid_query->array_output = ( (st & SNMP_CMD_SET) ? FALSE : TRUE );
                   1044:                for (   zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(oid), &pos_oid);
                   1045:                        zend_hash_get_current_data_ex(Z_ARRVAL_PP(oid), (void **) &tmp_oid, &pos_oid) == SUCCESS;
                   1046:                        zend_hash_move_forward_ex(Z_ARRVAL_PP(oid), &pos_oid) ) {
                   1047: 
                   1048:                        convert_to_string_ex(tmp_oid);
                   1049:                        objid_query->vars[objid_query->count].oid = Z_STRVAL_PP(tmp_oid);
                   1050:                        if (st & SNMP_CMD_SET) {
                   1051:                                if (Z_TYPE_PP(type) == IS_STRING) {
                   1052:                                        pptr = Z_STRVAL_PP(type);
                   1053:                                        objid_query->vars[objid_query->count].type = *pptr;
                   1054:                                } else if (Z_TYPE_PP(type) == IS_ARRAY) {
                   1055:                                        if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(type), (void **) &tmp_type, &pos_type)) {
                   1056:                                                convert_to_string_ex(tmp_type);
                   1057:                                                if (Z_STRLEN_PP(tmp_type) != 1) {
                   1058:                                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s': bogus type '%s', should be single char, got %u", Z_STRVAL_PP(tmp_oid), Z_STRVAL_PP(tmp_type), Z_STRLEN_PP(tmp_type));
                   1059:                                                        efree(objid_query->vars);
                   1060:                                                        return FALSE;
                   1061:                                                }
                   1062:                                                pptr = Z_STRVAL_PP(tmp_type);
                   1063:                                                objid_query->vars[objid_query->count].type = *pptr;
                   1064:                                                zend_hash_move_forward_ex(Z_ARRVAL_PP(type), &pos_type);
                   1065:                                        } else {
                   1066:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s': no type set", Z_STRVAL_PP(tmp_oid));
                   1067:                                                efree(objid_query->vars);
                   1068:                                                return FALSE;
                   1069:                                        }
                   1070:                                }
1.1       misho    1071: 
1.1.1.2   misho    1072:                                if (Z_TYPE_PP(value) == IS_STRING) {
                   1073:                                        objid_query->vars[objid_query->count].value = Z_STRVAL_PP(value);
                   1074:                                } else if (Z_TYPE_PP(value) == IS_ARRAY) {
                   1075:                                        if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(value), (void **) &tmp_value, &pos_value)) {
                   1076:                                                convert_to_string_ex(tmp_value);
                   1077:                                                objid_query->vars[objid_query->count].value = Z_STRVAL_PP(tmp_value);
                   1078:                                                zend_hash_move_forward_ex(Z_ARRVAL_PP(value), &pos_value);
                   1079:                                        } else {
                   1080:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s': no value set", Z_STRVAL_PP(tmp_oid));
                   1081:                                                efree(objid_query->vars);
                   1082:                                                return FALSE;
                   1083:                                        }
                   1084:                                }
                   1085:                        }
                   1086:                        objid_query->count++;
                   1087:                }
1.1       misho    1088:        }
                   1089: 
1.1.1.2   misho    1090:        /* now parse all OIDs */
                   1091:        if (st & SNMP_CMD_WALK) {
                   1092:                if (objid_query->count > 1) {
                   1093:                        php_snmp_error(object, NULL TSRMLS_CC, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Multi OID walks are not supported!");
                   1094:                        efree(objid_query->vars);
                   1095:                        return FALSE;
                   1096:                }
                   1097:                objid_query->vars[0].name_length = MAX_NAME_LEN;
                   1098:                if (strlen(objid_query->vars[0].oid)) { /* on a walk, an empty string means top of tree - no error */
                   1099:                        if (!snmp_parse_oid(objid_query->vars[0].oid, objid_query->vars[0].name, &(objid_query->vars[0].name_length))) {
                   1100:                                php_snmp_error(object, NULL TSRMLS_CC, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Invalid object identifier: %s", objid_query->vars[0].oid);
                   1101:                                efree(objid_query->vars);
                   1102:                                return FALSE;
                   1103:                        }
                   1104:                } else { 
                   1105:                        memmove((char *)objid_query->vars[0].name, (char *)objid_mib, sizeof(objid_mib));
                   1106:                        objid_query->vars[0].name_length = sizeof(objid_mib) / sizeof(oid);
                   1107:                }
                   1108:        } else {
                   1109:                for (objid_query->offset = 0; objid_query->offset < objid_query->count; objid_query->offset++) {
                   1110:                        objid_query->vars[objid_query->offset].name_length = MAX_OID_LEN;
                   1111:                        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))) {
                   1112:                                php_snmp_error(object, NULL TSRMLS_CC, PHP_SNMP_ERRNO_OID_PARSING_ERROR, "Invalid object identifier: %s", objid_query->vars[objid_query->offset].oid);
                   1113:                                efree(objid_query->vars);
                   1114:                                return FALSE;
                   1115:                        }
                   1116:                }
                   1117:        }
                   1118:        objid_query->offset = 0;
                   1119:        objid_query->step = objid_query->count;
                   1120:        return (objid_query->count > 0);
1.1       misho    1121: }
                   1122: /* }}} */
                   1123: 
1.1.1.2   misho    1124: /* {{{ netsnmp_session_init
                   1125:        allocates memory for session and session->peername, caller should free it manually using netsnmp_session_free() and efree()
                   1126: */
                   1127: static int netsnmp_session_init(php_snmp_session **session_p, int version, char *hostname, char *community, int timeout, int retries TSRMLS_DC)
1.1       misho    1128: {
1.1.1.2   misho    1129:        php_snmp_session *session;
1.1.1.3   misho    1130:        char *pptr, *host_ptr;
1.1.1.2   misho    1131:        int force_ipv6 = FALSE;
                   1132:        int n;
                   1133:        struct sockaddr **psal;
                   1134:        struct sockaddr **res;
1.1       misho    1135: 
1.1.1.2   misho    1136:        *session_p = (php_snmp_session *)emalloc(sizeof(php_snmp_session));
                   1137:        session = *session_p;
                   1138:        if (session == NULL) {
                   1139:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "emalloc() failed allocating session");
                   1140:                return (-1);
1.1       misho    1141:        }
1.1.1.2   misho    1142:        memset(session, 0, sizeof(php_snmp_session));
1.1       misho    1143: 
1.1.1.2   misho    1144:        snmp_sess_init(session);
1.1       misho    1145: 
1.1.1.2   misho    1146:        session->version = version;
                   1147:        session->remote_port = SNMP_PORT;
                   1148: 
                   1149:        session->peername = emalloc(MAX_NAME_LEN);
                   1150:        if (session->peername == NULL) {
                   1151:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "emalloc() failed while copying hostname");
                   1152:                return (-1);
1.1       misho    1153:        }
1.1.1.3   misho    1154:        /* we copy original hostname for further processing */
                   1155:        strlcpy(session->peername, hostname, MAX_NAME_LEN);
                   1156:        host_ptr = session->peername;
1.1       misho    1157: 
1.1.1.2   misho    1158:        /* Reading the hostname and its optional non-default port number */
1.1.1.3   misho    1159:        if (*host_ptr == '[') { /* IPv6 address */
1.1.1.2   misho    1160:                force_ipv6 = TRUE;
1.1.1.3   misho    1161:                host_ptr++;
                   1162:                if ((pptr = strchr(host_ptr, ']'))) {
1.1.1.2   misho    1163:                        if (pptr[1] == ':') {
                   1164:                                session->remote_port = atoi(pptr + 2);
                   1165:                        }
                   1166:                        *pptr = '\0';
                   1167:                } else {
1.1.1.3   misho    1168:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "malformed IPv6 address, closing square bracket missing");
1.1.1.2   misho    1169:                        return (-1);
                   1170:                }
                   1171:        } else { /* IPv4 address */
1.1.1.3   misho    1172:                if ((pptr = strchr(host_ptr, ':'))) {
1.1.1.2   misho    1173:                        session->remote_port = atoi(pptr + 1);
                   1174:                        *pptr = '\0';
                   1175:                }
                   1176:        }
1.1       misho    1177: 
1.1.1.2   misho    1178:        /* since Net-SNMP library requires 'udp6:' prefix for all IPv6 addresses (in FQDN form too) we need to
                   1179:           perform possible name resolution before running any SNMP queries */
1.1.1.3   misho    1180:        if ((n = php_network_getaddresses(host_ptr, SOCK_DGRAM, &psal, NULL TSRMLS_CC)) == 0) { /* some resolver error */
1.1.1.2   misho    1181:                /* warnings sent, bailing out */
                   1182:                return (-1);
1.1       misho    1183:        }
                   1184: 
1.1.1.3   misho    1185:        /* we have everything we need in psal, flush peername and fill it properly */
                   1186:        *(session->peername) = '\0';
1.1.1.2   misho    1187:        res = psal;
                   1188:        while (n-- > 0) {
                   1189:                pptr = session->peername;
                   1190: #if HAVE_GETADDRINFO && HAVE_IPV6 && HAVE_INET_NTOP
                   1191:                if (force_ipv6 && (*res)->sa_family != AF_INET6) {
                   1192:                        res++;
                   1193:                        continue;
                   1194:                }
                   1195:                if ((*res)->sa_family == AF_INET6) {
1.1.1.3   misho    1196:                        strcpy(session->peername, "udp6:[");
1.1.1.2   misho    1197:                        pptr = session->peername + strlen(session->peername);
                   1198:                        inet_ntop((*res)->sa_family, &(((struct sockaddr_in6*)(*res))->sin6_addr), pptr, MAX_NAME_LEN);
1.1.1.3   misho    1199:                        strcat(pptr, "]");
1.1.1.2   misho    1200:                } else if ((*res)->sa_family == AF_INET) {
                   1201:                        inet_ntop((*res)->sa_family, &(((struct sockaddr_in*)(*res))->sin_addr), pptr, MAX_NAME_LEN);
                   1202:                } else {
                   1203:                        res++;
                   1204:                        continue;
                   1205:                }
                   1206: #else
                   1207:                if ((*res)->sa_family != AF_INET) {
                   1208:                        res++;
                   1209:                        continue;
                   1210:                }
                   1211:                strcat(pptr, inet_ntoa(((struct sockaddr_in*)(*res))->sin_addr));
1.1       misho    1212: #endif
1.1.1.2   misho    1213:                break;
                   1214:        }
1.1       misho    1215: 
1.1.1.2   misho    1216:        if (strlen(session->peername) == 0) {
1.1.1.3   misho    1217:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown failure while resolving '%s'", hostname);
1.1.1.2   misho    1218:                return (-1);
                   1219:        }
                   1220:        /* XXX FIXME
                   1221:                There should be check for non-empty session->peername!
                   1222:        */
1.1       misho    1223: 
1.1.1.2   misho    1224:        /* put back non-standard SNMP port */
                   1225:        if (session->remote_port != SNMP_PORT) {
                   1226:                pptr = session->peername + strlen(session->peername);
                   1227:                sprintf(pptr, ":%d", session->remote_port);
                   1228:        }
                   1229: 
                   1230:        php_network_freeaddresses(psal);
                   1231: 
                   1232:        if (version == SNMP_VERSION_3) {
                   1233:                /* Setting the security name. */
                   1234:                session->securityName = estrdup(community);
                   1235:                session->securityNameLen = strlen(session->securityName);
                   1236:        } else {
                   1237:                session->authenticator = NULL;
                   1238:                session->community = (u_char *)estrdup(community);
                   1239:                session->community_len = strlen(community);
1.1       misho    1240:        }
1.1.1.2   misho    1241: 
                   1242:        session->retries = retries;
                   1243:        session->timeout = timeout;
                   1244:        return (0);
1.1       misho    1245: }
                   1246: /* }}} */
                   1247: 
                   1248: /* {{{ int netsnmp_session_set_sec_level(struct snmp_session *s, char *level)
                   1249:    Set the security level in the snmpv3 session */
1.1.1.2   misho    1250: static int netsnmp_session_set_sec_level(struct snmp_session *s, char *level)
1.1       misho    1251: {
1.1.1.2   misho    1252:        if (!strcasecmp(level, "noAuthNoPriv") || !strcasecmp(level, "nanp")) {
                   1253:                s->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
                   1254:        } else if (!strcasecmp(level, "authNoPriv") || !strcasecmp(level, "anp")) {
                   1255:                s->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
                   1256:        } else if (!strcasecmp(level, "authPriv") || !strcasecmp(level, "ap")) {
                   1257:                s->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
                   1258:        } else {
                   1259:                return (-1);
1.1       misho    1260:        }
1.1.1.2   misho    1261:        return (0);
1.1       misho    1262: }
                   1263: /* }}} */
                   1264: 
                   1265: /* {{{ int netsnmp_session_set_auth_protocol(struct snmp_session *s, char *prot)
                   1266:    Set the authentication protocol in the snmpv3 session */
                   1267: static int netsnmp_session_set_auth_protocol(struct snmp_session *s, char *prot TSRMLS_DC)
                   1268: {
1.1.1.2   misho    1269:        if (!strcasecmp(prot, "MD5")) {
                   1270:                s->securityAuthProto = usmHMACMD5AuthProtocol;
                   1271:                s->securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
                   1272:        } else if (!strcasecmp(prot, "SHA")) {
                   1273:                s->securityAuthProto = usmHMACSHA1AuthProtocol;
                   1274:                s->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
                   1275:        } else {
                   1276:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown authentication protocol '%s'", prot);
                   1277:                return (-1);
1.1       misho    1278:        }
1.1.1.2   misho    1279:        return (0);
1.1       misho    1280: }
                   1281: /* }}} */
                   1282: 
                   1283: /* {{{ int netsnmp_session_set_sec_protocol(struct snmp_session *s, char *prot)
                   1284:    Set the security protocol in the snmpv3 session */
                   1285: static int netsnmp_session_set_sec_protocol(struct snmp_session *s, char *prot TSRMLS_DC)
                   1286: {
1.1.1.2   misho    1287:        if (!strcasecmp(prot, "DES")) {
                   1288:                s->securityPrivProto = usmDESPrivProtocol;
                   1289:                s->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
1.1       misho    1290: #ifdef HAVE_AES
1.1.1.2   misho    1291:        } else if (!strcasecmp(prot, "AES128") || !strcasecmp(prot, "AES")) {
                   1292:                s->securityPrivProto = usmAESPrivProtocol;
                   1293:                s->securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
1.1       misho    1294: #endif
1.1.1.2   misho    1295:        } else {
                   1296:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown security protocol '%s'", prot);
                   1297:                return (-1);
1.1       misho    1298:        }
1.1.1.2   misho    1299:        return (0);
1.1       misho    1300: }
                   1301: /* }}} */
                   1302: 
                   1303: /* {{{ int netsnmp_session_gen_auth_key(struct snmp_session *s, char *pass)
                   1304:    Make key from pass phrase in the snmpv3 session */
                   1305: static int netsnmp_session_gen_auth_key(struct snmp_session *s, char *pass TSRMLS_DC)
                   1306: {
1.1.1.2   misho    1307:        int snmp_errno;
                   1308:        s->securityAuthKeyLen = USM_AUTH_KU_LEN;
                   1309:        if ((snmp_errno = generate_Ku(s->securityAuthProto, s->securityAuthProtoLen,
                   1310:                        (u_char *) pass, strlen(pass),
                   1311:                        s->securityAuthKey, &(s->securityAuthKeyLen)))) {
                   1312:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error generating a key for authentication pass phrase '%s': %s", pass, snmp_api_errstring(snmp_errno));
                   1313:                return (-1);
1.1       misho    1314:        }
1.1.1.2   misho    1315:        return (0);
1.1       misho    1316: }
                   1317: /* }}} */
                   1318: 
                   1319: /* {{{ int netsnmp_session_gen_sec_key(struct snmp_session *s, u_char *pass)
                   1320:    Make key from pass phrase in the snmpv3 session */
1.1.1.2   misho    1321: static int netsnmp_session_gen_sec_key(struct snmp_session *s, char *pass TSRMLS_DC)
1.1       misho    1322: {
1.1.1.2   misho    1323:        int snmp_errno;
                   1324: 
                   1325:        s->securityPrivKeyLen = USM_PRIV_KU_LEN;
                   1326:        if ((snmp_errno = generate_Ku(s->securityAuthProto, s->securityAuthProtoLen,
                   1327:                        (u_char *)pass, strlen(pass),
                   1328:                        s->securityPrivKey, &(s->securityPrivKeyLen)))) {
                   1329:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error generating a key for privacy pass phrase '%s': %s", pass, snmp_api_errstring(snmp_errno));
                   1330:                return (-2);
1.1       misho    1331:        }
1.1.1.2   misho    1332:        return (0);
1.1       misho    1333: }
                   1334: /* }}} */
                   1335: 
1.1.1.2   misho    1336: /* {{{ in netsnmp_session_set_contextEngineID(struct snmp_session *s, u_char * contextEngineID)
                   1337:    Set context Engine Id in the snmpv3 session */
                   1338: static int netsnmp_session_set_contextEngineID(struct snmp_session *s, char * contextEngineID TSRMLS_DC)
1.1       misho    1339: {
1.1.1.2   misho    1340:        size_t  ebuf_len = 32, eout_len = 0;
                   1341:        u_char  *ebuf = (u_char *) emalloc(ebuf_len);
1.1       misho    1342: 
1.1.1.2   misho    1343:        if (ebuf == NULL) {
                   1344:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "malloc failure setting contextEngineID");
                   1345:                return (-1);
                   1346:        }
                   1347:        if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, contextEngineID)) {
                   1348:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad engine ID value '%s'", contextEngineID);
                   1349:                efree(ebuf);
                   1350:                return (-1);
                   1351:        }
1.1       misho    1352: 
1.1.1.2   misho    1353:        if (s->contextEngineID) {
                   1354:                efree(s->contextEngineID);
                   1355:        }
1.1       misho    1356: 
1.1.1.2   misho    1357:        s->contextEngineID = ebuf;
                   1358:        s->contextEngineIDLen = eout_len;
                   1359:        return (0);
1.1       misho    1360: }
                   1361: /* }}} */
                   1362: 
1.1.1.2   misho    1363: /* {{{ 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)
                   1364:    Set all snmpv3-related security options */
                   1365: 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 TSRMLS_DC)
1.1       misho    1366: {
1.1.1.2   misho    1367: 
                   1368:        /* Setting the security level. */
                   1369:        if (netsnmp_session_set_sec_level(session, sec_level)) {
                   1370:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid security level '%s'", sec_level);
                   1371:                return (-1);
                   1372:        }
                   1373: 
                   1374:        if (session->securityLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
                   1375: 
                   1376:                /* Setting the authentication protocol. */
                   1377:                if (netsnmp_session_set_auth_protocol(session, auth_protocol TSRMLS_CC)) {
                   1378:                        /* Warning message sent already, just bail out */
                   1379:                        return (-1);
                   1380:                }
                   1381: 
                   1382:                /* Setting the authentication passphrase. */
                   1383:                if (netsnmp_session_gen_auth_key(session, auth_passphrase TSRMLS_CC)) {
                   1384:                        /* Warning message sent already, just bail out */
                   1385:                        return (-1);
                   1386:                }
                   1387: 
                   1388:                if (session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
                   1389:                        /* Setting the security protocol. */
                   1390:                        if (netsnmp_session_set_sec_protocol(session, priv_protocol TSRMLS_CC)) {
                   1391:                                /* Warning message sent already, just bail out */
                   1392:                                return (-1);
                   1393:                        }
                   1394: 
                   1395:                        /* Setting the security protocol passphrase. */
                   1396:                        if (netsnmp_session_gen_sec_key(session, priv_passphrase TSRMLS_CC)) {
                   1397:                                /* Warning message sent already, just bail out */
                   1398:                                return (-1);
                   1399:                        }
                   1400:                }
                   1401:        }
                   1402: 
                   1403:        /* Setting contextName if specified */
                   1404:        if (contextName) {
                   1405:                session->contextName = contextName;
                   1406:                session->contextNameLen = strlen(contextName);
                   1407:        }
                   1408: 
                   1409:        /* Setting contextEngineIS if specified */
                   1410:        if (contextEngineID && strlen(contextEngineID) && netsnmp_session_set_contextEngineID(session, contextEngineID TSRMLS_CC)) {
                   1411:                /* Warning message sent already, just bail out */
                   1412:                return (-1);
                   1413:        }
                   1414: 
                   1415:        return (0);
1.1       misho    1416: }
                   1417: /* }}} */
                   1418: 
1.1.1.2   misho    1419: /* {{{ php_snmp
1.1       misho    1420: *
1.1.1.2   misho    1421: * Generic SNMP handler for all versions.
                   1422: * This function makes use of the internal SNMP object fetcher.
                   1423: * Used both in old (non-OO) and OO API
1.1       misho    1424: *
                   1425: */
1.1.1.2   misho    1426: static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version)
1.1       misho    1427: {
1.1.1.2   misho    1428:        zval **oid, **value, **type;
                   1429:        char *a1, *a2, *a3, *a4, *a5, *a6, *a7;
                   1430:        int a1_len, a2_len, a3_len, a4_len, a5_len, a6_len, a7_len;
                   1431:        zend_bool use_orignames = 0, suffix_keys = 0;
1.1       misho    1432:        long timeout = SNMP_DEFAULT_TIMEOUT;
                   1433:        long retries = SNMP_DEFAULT_RETRIES;
                   1434:        int argc = ZEND_NUM_ARGS();
1.1.1.2   misho    1435:        struct objid_query objid_query;
                   1436:        php_snmp_session *session;
                   1437:        int session_less_mode = (getThis() == NULL);
                   1438:        php_snmp_object *snmp_object;
                   1439:        php_snmp_object glob_snmp_object;
1.1       misho    1440:        
1.1.1.2   misho    1441:        objid_query.max_repetitions = -1;
                   1442:        objid_query.non_repeaters = 0;
                   1443:        objid_query.valueretrieval = SNMP_G(valueretrieval);
                   1444:        objid_query.oid_increasing_check = TRUE;
                   1445: 
                   1446:        if (session_less_mode) {
                   1447:                if (version == SNMP_VERSION_3) {
                   1448:                        if (st & SNMP_CMD_SET) {
                   1449:                                if (zend_parse_parameters(argc TSRMLS_CC, "sssssssZZZ|ll", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len,
                   1450:                                        &a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len, &oid, &type, &value, &timeout, &retries) == FAILURE) {
                   1451:                                        RETURN_FALSE;
                   1452:                                }
                   1453:                        } else {
                   1454:                                /* SNMP_CMD_GET
                   1455:                                 * SNMP_CMD_GETNEXT
                   1456:                                 * SNMP_CMD_WALK
                   1457:                                 */
                   1458:                                if (zend_parse_parameters(argc TSRMLS_CC, "sssssssZ|ll", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len,
                   1459:                                        &a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len, &oid, &timeout, &retries) == FAILURE) {
                   1460:                                        RETURN_FALSE;
                   1461:                                }
                   1462:                        }
                   1463:                } else {
                   1464:                        if (st & SNMP_CMD_SET) {
                   1465:                                if (zend_parse_parameters(argc TSRMLS_CC, "ssZZZ|ll", &a1, &a1_len, &a2, &a2_len, &oid, &type, &value, &timeout, &retries) == FAILURE) {
                   1466:                                        RETURN_FALSE;
                   1467:                                }
                   1468:                        } else {
                   1469:                                /* SNMP_CMD_GET
                   1470:                                 * SNMP_CMD_GETNEXT
                   1471:                                 * SNMP_CMD_WALK
                   1472:                                 */
                   1473:                                if (zend_parse_parameters(argc TSRMLS_CC, "ssZ|ll", &a1, &a1_len, &a2, &a2_len, &oid, &timeout, &retries) == FAILURE) {
                   1474:                                        RETURN_FALSE;
                   1475:                                }
                   1476:                        }
1.1       misho    1477:                }
                   1478:        } else {
1.1.1.2   misho    1479:                if (st & SNMP_CMD_SET) {
                   1480:                        if (zend_parse_parameters(argc TSRMLS_CC, "ZZZ", &oid, &type, &value) == FAILURE) {
                   1481:                                RETURN_FALSE;
                   1482:                        }
                   1483:                } else if (st & SNMP_CMD_WALK) {
                   1484:                        if (zend_parse_parameters(argc TSRMLS_CC, "Z|bll", &oid, &suffix_keys, &(objid_query.max_repetitions), &(objid_query.non_repeaters)) == FAILURE) {
                   1485:                                RETURN_FALSE;
                   1486:                        }
                   1487:                        if (suffix_keys) {
                   1488:                                st |= SNMP_USE_SUFFIX_AS_KEYS;
                   1489:                        }
                   1490:                } else if (st & SNMP_CMD_GET) {
                   1491:                        if (zend_parse_parameters(argc TSRMLS_CC, "Z|b", &oid, &use_orignames) == FAILURE) {
                   1492:                                RETURN_FALSE;
                   1493:                        }
                   1494:                        if (use_orignames) {
                   1495:                                st |= SNMP_ORIGINAL_NAMES_AS_KEYS;
                   1496:                        }
                   1497:                } else {
                   1498:                        /* SNMP_CMD_GETNEXT
                   1499:                         */
                   1500:                        if (zend_parse_parameters(argc TSRMLS_CC, "Z", &oid) == FAILURE) {
                   1501:                                RETURN_FALSE;
                   1502:                        }
1.1       misho    1503:                }
                   1504:        }
                   1505: 
1.1.1.2   misho    1506:        if (!php_snmp_parse_oid(getThis(), st, &objid_query, oid, type, value TSRMLS_CC)) {
1.1       misho    1507:                RETURN_FALSE;
                   1508:        }
                   1509: 
1.1.1.2   misho    1510:        if (session_less_mode) {
                   1511:                if (netsnmp_session_init(&session, version, a1, a2, timeout, retries TSRMLS_CC)) {
                   1512:                        efree(objid_query.vars);
                   1513:                        netsnmp_session_free(&session);
                   1514:                        RETURN_FALSE;
                   1515:                }
                   1516:                if (version == SNMP_VERSION_3 && netsnmp_session_set_security(session, a3, a4, a5, a6, a7, NULL, NULL TSRMLS_CC)) {
                   1517:                        efree(objid_query.vars);
                   1518:                        netsnmp_session_free(&session);
                   1519:                        /* Warning message sent already, just bail out */
                   1520:                        RETURN_FALSE;
                   1521:                }
                   1522:        } else {
                   1523:                zval *object = getThis();
                   1524:                snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC);
                   1525:                session = snmp_object->session;
                   1526:                if (!session) {
                   1527:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid or uninitialized SNMP object");
                   1528:                        efree(objid_query.vars);
                   1529:                        RETURN_FALSE;
                   1530:                }
1.1       misho    1531: 
1.1.1.2   misho    1532:                if (snmp_object->max_oids > 0) {
                   1533:                        objid_query.step = snmp_object->max_oids;
                   1534:                        if (objid_query.max_repetitions < 0) { /* unspecified in function call, use session-wise */
                   1535:                                objid_query.max_repetitions = snmp_object->max_oids;
                   1536:                        }
                   1537:                }
                   1538:                objid_query.oid_increasing_check = snmp_object->oid_increasing_check;
                   1539:                objid_query.valueretrieval = snmp_object->valueretrieval;
                   1540:                glob_snmp_object.enum_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM);
                   1541:                netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, snmp_object->enum_print);
                   1542:                glob_snmp_object.quick_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT);
                   1543:                netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, snmp_object->quick_print);
                   1544:                glob_snmp_object.oid_output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
                   1545:                netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, snmp_object->oid_output_format);
1.1       misho    1546:        }
                   1547: 
1.1.1.2   misho    1548:        if (objid_query.max_repetitions < 0) {
                   1549:                objid_query.max_repetitions = 20; /* provide correct default value */
1.1       misho    1550:        }
                   1551: 
1.1.1.2   misho    1552:        php_snmp_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, st, session, &objid_query);
                   1553:        
                   1554:        efree(objid_query.vars);
                   1555: 
                   1556:        if (session_less_mode) {
                   1557:                netsnmp_session_free(&session);
                   1558:        } else {
                   1559:                netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, glob_snmp_object.enum_print);
                   1560:                netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, glob_snmp_object.quick_print);
                   1561:                netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, glob_snmp_object.oid_output_format);
                   1562:        }
                   1563: }
                   1564: /* }}} */
                   1565: 
                   1566: /* {{{ proto mixed snmpget(string host, string community, mixed object_id [, int timeout [, int retries]]) 
                   1567:    Fetch a SNMP object */
                   1568: PHP_FUNCTION(snmpget)
                   1569: {
                   1570:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_1);
                   1571: }
                   1572: /* }}} */
                   1573: 
                   1574: /* {{{ proto mixed snmpgetnext(string host, string community, mixed object_id [, int timeout [, int retries]]) 
                   1575:    Fetch a SNMP object */
                   1576: PHP_FUNCTION(snmpgetnext)
                   1577: {
                   1578:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_1);
                   1579: }
                   1580: /* }}} */
                   1581: 
                   1582: /* {{{ proto mixed snmpwalk(string host, string community, mixed object_id [, int timeout [, int retries]]) 
                   1583:    Return all objects under the specified object id */
                   1584: PHP_FUNCTION(snmpwalk)
                   1585: {
                   1586:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, (SNMP_CMD_WALK | SNMP_NUMERIC_KEYS), SNMP_VERSION_1);
                   1587: }
                   1588: /* }}} */
                   1589: 
                   1590: /* {{{ proto mixed snmprealwalk(string host, string community, mixed object_id [, int timeout [, int retries]])
                   1591:    Return all objects including their respective object id withing the specified one */
                   1592: PHP_FUNCTION(snmprealwalk)
                   1593: {
                   1594:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, SNMP_VERSION_1);
                   1595: }
                   1596: /* }}} */
                   1597: 
                   1598: /* {{{ proto bool snmpset(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]]) 
                   1599:    Set the value of a SNMP object */
                   1600: PHP_FUNCTION(snmpset)
                   1601: {
                   1602:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, SNMP_VERSION_1);
                   1603: }
                   1604: /* }}} */
                   1605: 
                   1606: /* {{{ proto bool snmp_get_quick_print(void)
                   1607:    Return the current status of quick_print */
                   1608: PHP_FUNCTION(snmp_get_quick_print)
                   1609: {
                   1610:        if (zend_parse_parameters_none() == FAILURE) {
                   1611:                return;
1.1       misho    1612:        }
                   1613: 
1.1.1.2   misho    1614:        RETURN_BOOL(netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT));
                   1615: }
                   1616: /* }}} */
                   1617: 
                   1618: /* {{{ proto bool snmp_set_quick_print(int quick_print)
                   1619:    Return all objects including their respective object id withing the specified one */
                   1620: PHP_FUNCTION(snmp_set_quick_print)
                   1621: {
                   1622:        long a1;
                   1623: 
                   1624:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &a1) == FAILURE) {
1.1       misho    1625:                RETURN_FALSE;
                   1626:        }
                   1627: 
1.1.1.2   misho    1628:        netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, (int)a1);
                   1629:        RETURN_TRUE;
                   1630: }
                   1631: /* }}} */
                   1632: 
                   1633: /* {{{ proto bool snmp_set_enum_print(int enum_print)
                   1634:    Return all values that are enums with their enum value instead of the raw integer */
                   1635: PHP_FUNCTION(snmp_set_enum_print)
                   1636: {
                   1637:        long a1;
                   1638: 
                   1639:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &a1) == FAILURE) {
                   1640:                RETURN_FALSE;
1.1       misho    1641:        }
                   1642: 
1.1.1.2   misho    1643:        netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, (int) a1);
                   1644:        RETURN_TRUE;
                   1645: } 
                   1646: /* }}} */
                   1647: 
                   1648: /* {{{ proto bool snmp_set_oid_output_format(int oid_format)
                   1649:    Set the OID output format. */
                   1650: PHP_FUNCTION(snmp_set_oid_output_format)
                   1651: {
                   1652:        long a1;
                   1653: 
                   1654:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &a1) == FAILURE) {
                   1655:                RETURN_FALSE;
                   1656:        }
1.1       misho    1657: 
1.1.1.2   misho    1658:        switch((int) a1) {
                   1659:                case NETSNMP_OID_OUTPUT_SUFFIX:
                   1660:                case NETSNMP_OID_OUTPUT_MODULE:
                   1661:                case NETSNMP_OID_OUTPUT_FULL:
                   1662:                case NETSNMP_OID_OUTPUT_NUMERIC:
                   1663:                case NETSNMP_OID_OUTPUT_UCD:
                   1664:                case NETSNMP_OID_OUTPUT_NONE:
                   1665:                        netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, a1);
                   1666:                        RETURN_TRUE;
                   1667:                        break;
                   1668:                default:
                   1669:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown SNMP output print format '%d'", (int) a1);
                   1670:                        RETURN_FALSE;
                   1671:                        break;
                   1672:        }
                   1673: } 
                   1674: /* }}} */
                   1675: 
                   1676: /* {{{ proto mixed snmp2_get(string host, string community, mixed object_id [, int timeout [, int retries]]) 
                   1677:    Fetch a SNMP object */
                   1678: PHP_FUNCTION(snmp2_get)
                   1679: {
                   1680:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_2c);
1.1       misho    1681: }
                   1682: /* }}} */
                   1683: 
1.1.1.2   misho    1684: /* {{{ proto mixed snmp2_getnext(string host, string community, mixed object_id [, int timeout [, int retries]]) 
                   1685:    Fetch a SNMP object */
                   1686: PHP_FUNCTION(snmp2_getnext)
                   1687: {
                   1688:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_2c);
                   1689: }
                   1690: /* }}} */
                   1691: 
                   1692: /* {{{ proto mixed snmp2_walk(string host, string community, mixed object_id [, int timeout [, int retries]]) 
                   1693:    Return all objects under the specified object id */
                   1694: PHP_FUNCTION(snmp2_walk)
                   1695: {
                   1696:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, (SNMP_CMD_WALK | SNMP_NUMERIC_KEYS), SNMP_VERSION_2c);
                   1697: }
                   1698: /* }}} */
                   1699: 
                   1700: /* {{{ proto mixed snmp2_real_walk(string host, string community, mixed object_id [, int timeout [, int retries]])
                   1701:    Return all objects including their respective object id withing the specified one */
                   1702: PHP_FUNCTION(snmp2_real_walk)
                   1703: {
                   1704:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, SNMP_VERSION_2c);
                   1705: }
                   1706: /* }}} */
                   1707: 
                   1708: /* {{{ proto bool snmp2_set(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]]) 
                   1709:    Set the value of a SNMP object */
                   1710: PHP_FUNCTION(snmp2_set)
                   1711: {
                   1712:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, SNMP_VERSION_2c);
                   1713: }
                   1714: /* }}} */
                   1715: 
                   1716: /* {{{ proto mixed snmp3_get(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, mixed object_id [, int timeout [, int retries]])
1.1       misho    1717:    Fetch the value of a SNMP object */
                   1718: PHP_FUNCTION(snmp3_get)
                   1719: {
1.1.1.2   misho    1720:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_3);
1.1       misho    1721: }
                   1722: /* }}} */
                   1723: 
1.1.1.2   misho    1724: /* {{{ proto mixed snmp3_getnext(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, mixed object_id [, int timeout [, int retries]])
1.1       misho    1725:    Fetch the value of a SNMP object */
                   1726: PHP_FUNCTION(snmp3_getnext)
                   1727: {
1.1.1.2   misho    1728:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_3);
1.1       misho    1729: }
                   1730: /* }}} */
                   1731: 
1.1.1.2   misho    1732: /* {{{ proto mixed snmp3_walk(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, mixed object_id [, int timeout [, int retries]])
1.1       misho    1733:    Fetch the value of a SNMP object */
                   1734: PHP_FUNCTION(snmp3_walk)
                   1735: {
1.1.1.2   misho    1736:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, (SNMP_CMD_WALK | SNMP_NUMERIC_KEYS), SNMP_VERSION_3);
1.1       misho    1737: }
                   1738: /* }}} */
                   1739: 
1.1.1.2   misho    1740: /* {{{ proto mixed snmp3_real_walk(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, mixed object_id [, int timeout [, int retries]])
1.1       misho    1741:    Fetch the value of a SNMP object */
                   1742: PHP_FUNCTION(snmp3_real_walk)
                   1743: {
1.1.1.2   misho    1744:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, SNMP_VERSION_3);
1.1       misho    1745: }
                   1746: /* }}} */
                   1747: 
1.1.1.2   misho    1748: /* {{{ proto bool snmp3_set(string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_protocol, string priv_passphrase, mixed object_id, mixed type, mixed value [, int timeout [, int retries]])
1.1       misho    1749:    Fetch the value of a SNMP object */
                   1750: PHP_FUNCTION(snmp3_set)
                   1751: {
1.1.1.2   misho    1752:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, SNMP_VERSION_3);
1.1       misho    1753: }
                   1754: /* }}} */
                   1755: 
1.1.1.2   misho    1756: /* {{{ proto bool snmp_set_valueretrieval(int method)
1.1       misho    1757:    Specify the method how the SNMP values will be returned */
                   1758: PHP_FUNCTION(snmp_set_valueretrieval)
                   1759: {
                   1760:        long method;
                   1761: 
                   1762:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &method) == FAILURE) {
1.1.1.2   misho    1763:                RETURN_FALSE;
1.1       misho    1764:        }
                   1765: 
1.1.1.2   misho    1766:        if (method >= 0 && method <= (SNMP_VALUE_LIBRARY|SNMP_VALUE_PLAIN|SNMP_VALUE_OBJECT)) {
                   1767:                        SNMP_G(valueretrieval) = method;
                   1768:                        RETURN_TRUE;
                   1769:        } else {
                   1770:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown SNMP value retrieval method '%ld'", method);
                   1771:                RETURN_FALSE;
1.1       misho    1772:        }
                   1773: }
                   1774: /* }}} */
                   1775: 
                   1776: /* {{{ proto int snmp_get_valueretrieval()
                   1777:    Return the method how the SNMP values will be returned */
                   1778: PHP_FUNCTION(snmp_get_valueretrieval)
                   1779: {
1.1.1.2   misho    1780:        if (zend_parse_parameters_none() == FAILURE) {
                   1781:                RETURN_FALSE;
                   1782:        }
                   1783: 
1.1       misho    1784:        RETURN_LONG(SNMP_G(valueretrieval));
                   1785: }
                   1786: /* }}} */
                   1787: 
1.1.1.2   misho    1788: /* {{{ proto bool snmp_read_mib(string filename)
1.1       misho    1789:    Reads and parses a MIB file into the active MIB tree. */
                   1790: PHP_FUNCTION(snmp_read_mib)
                   1791: {
                   1792:        char *filename;
                   1793:        int filename_len;
                   1794: 
1.1.1.2   misho    1795:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) {
                   1796:                RETURN_FALSE;
1.1       misho    1797:        }
                   1798: 
                   1799:        if (!read_mib(filename)) {
                   1800:                char *error = strerror(errno);
                   1801:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading MIB file '%s': %s", filename, error);
                   1802:                RETURN_FALSE;
                   1803:        }
                   1804:        RETURN_TRUE;
                   1805: }
                   1806: /* }}} */
                   1807: 
1.1.1.2   misho    1808: /* {{{ proto SNMP SNMP::__construct(int version, string hostname, string community|securityName [, long timeout [, long retries]])
                   1809:        Creates a new SNMP session to specified host. */
                   1810: PHP_METHOD(snmp, __construct)
                   1811: {
                   1812:        php_snmp_object *snmp_object;
                   1813:        zval *object = getThis();
                   1814:        char *a1, *a2;
                   1815:        int a1_len, a2_len;
                   1816:        long timeout = SNMP_DEFAULT_TIMEOUT;
                   1817:        long retries = SNMP_DEFAULT_RETRIES;
                   1818:        long version = SNMP_DEFAULT_VERSION;
                   1819:        int argc = ZEND_NUM_ARGS();
                   1820:        zend_error_handling error_handling;
                   1821: 
                   1822:        snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC);
                   1823:        zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
                   1824:        
                   1825:        if (zend_parse_parameters(argc TSRMLS_CC, "lss|ll", &version, &a1, &a1_len, &a2, &a2_len, &timeout, &retries) == FAILURE) {
                   1826:                zend_restore_error_handling(&error_handling TSRMLS_CC);
                   1827:                return;
                   1828:        }
                   1829: 
                   1830:        zend_restore_error_handling(&error_handling TSRMLS_CC);
                   1831: 
                   1832:        switch(version) {
                   1833:                case SNMP_VERSION_1:
                   1834:                case SNMP_VERSION_2c:
                   1835:                case SNMP_VERSION_3:
                   1836:                        break;
                   1837:                default:
                   1838:                        zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Unknown SNMP protocol version", 0 TSRMLS_CC);
                   1839:                        return;
                   1840:        }
                   1841: 
                   1842:        /* handle re-open of snmp session */
                   1843:        if (snmp_object->session) {
                   1844:                netsnmp_session_free(&(snmp_object->session));
                   1845:        }
                   1846:        
                   1847:        if (netsnmp_session_init(&(snmp_object->session), version, a1, a2, timeout, retries TSRMLS_CC)) {
                   1848:                return;
                   1849:        }
                   1850:        snmp_object->max_oids = 0;
                   1851:        snmp_object->valueretrieval = SNMP_G(valueretrieval);
                   1852:        snmp_object->enum_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM);
                   1853:        snmp_object->oid_output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
                   1854:        snmp_object->quick_print = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT);
                   1855:        snmp_object->oid_increasing_check = TRUE;
                   1856:        snmp_object->exceptions_enabled = 0;
                   1857: }
                   1858: /* }}} */
                   1859: 
                   1860: /* {{{ proto bool SNMP::close() 
                   1861:        Close SNMP session */
                   1862: PHP_METHOD(snmp, close)
                   1863: {
                   1864:        php_snmp_object *snmp_object;
                   1865:        zval *object = getThis();
                   1866: 
                   1867:        snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC);
                   1868: 
                   1869:        if (zend_parse_parameters_none() == FAILURE) {
                   1870:                RETURN_FALSE;
                   1871:        }
                   1872: 
                   1873:        netsnmp_session_free(&(snmp_object->session));
                   1874: 
                   1875:        RETURN_TRUE;
                   1876: }
                   1877: /* }}} */
                   1878: 
                   1879: /* {{{ proto mixed SNMP::get(mixed object_id [, bool preserve_keys])
1.1.1.3   misho    1880:    Fetch a SNMP object returning scalar for single OID and array of oid->value pairs for multi OID request */
1.1.1.2   misho    1881: PHP_METHOD(snmp, get)
                   1882: {
                   1883:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, (-1));
                   1884: }
                   1885: /* }}} */
                   1886: 
                   1887: /* {{{ proto mixed SNMP::getnext(mixed object_id)
1.1.1.3   misho    1888:    Fetch a SNMP object returning scalar for single OID and array of oid->value pairs for multi OID request */
1.1.1.2   misho    1889: PHP_METHOD(snmp, getnext)
                   1890: {
                   1891:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, (-1));
                   1892: }
                   1893: /* }}} */
                   1894: 
                   1895: /* {{{ proto mixed SNMP::walk(mixed object_id [, bool $suffix_as_key = FALSE [, int $max_repetitions [, int $non_repeaters]])
                   1896:    Return all objects including their respective object id withing the specified one as array of oid->value pairs */
                   1897: PHP_METHOD(snmp, walk)
                   1898: {
                   1899:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_WALK, (-1));
                   1900: }
                   1901: /* }}} */
                   1902: 
                   1903: /* {{{ proto bool SNMP::set(mixed object_id, mixed type, mixed value) 
                   1904:    Set the value of a SNMP object */
                   1905: PHP_METHOD(snmp, set)
                   1906: {
                   1907:        php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_SET, (-1));
                   1908: }
                   1909: 
                   1910: /* {{{ proto bool SNMP::setSecurity(string sec_level, [ string auth_protocol, string auth_passphrase [, string priv_protocol, string priv_passphrase [, string contextName [, string contextEngineID]]]])
                   1911:        Set SNMPv3 security-related session parameters */
                   1912: PHP_METHOD(snmp, setSecurity)
                   1913: {
                   1914:        php_snmp_object *snmp_object;
                   1915:        zval *object = getThis();
                   1916:        char *a1 = "", *a2 = "", *a3 = "", *a4 = "", *a5 = "", *a6 = "", *a7 = "";
                   1917:        int a1_len = 0, a2_len = 0, a3_len = 0, a4_len = 0, a5_len = 0, a6_len = 0, a7_len = 0;
                   1918:        int argc = ZEND_NUM_ARGS();
                   1919: 
                   1920:        snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC);
                   1921:        
                   1922:        if (zend_parse_parameters(argc TSRMLS_CC, "s|ssssss", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len,
                   1923:                &a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len) == FAILURE) {
                   1924:                RETURN_FALSE;
                   1925:        }
                   1926: 
                   1927:        if (netsnmp_session_set_security(snmp_object->session, a1, a2, a3, a4, a5, a6, a7 TSRMLS_CC)) {
                   1928:                /* Warning message sent already, just bail out */
                   1929:                RETURN_FALSE;
                   1930:        }
                   1931:        RETURN_TRUE;
                   1932: }
                   1933: /* }}} */
                   1934: 
                   1935: /* {{{ proto long SNMP::getErrno() 
                   1936:        Get last error code number */
                   1937: PHP_METHOD(snmp, getErrno)
                   1938: {
                   1939:        php_snmp_object *snmp_object;
                   1940:        zval *object = getThis();
                   1941: 
                   1942:        snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC);
                   1943: 
                   1944:        RETVAL_LONG(snmp_object->snmp_errno);
                   1945:        return;
                   1946: }
                   1947: /* }}} */
                   1948: 
                   1949: /* {{{ proto long SNMP::getError() 
                   1950:        Get last error message */
                   1951: PHP_METHOD(snmp, getError)
                   1952: {
                   1953:        php_snmp_object *snmp_object;
                   1954:        zval *object = getThis();
                   1955: 
                   1956:        snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC);
                   1957: 
                   1958:        RETVAL_STRING(snmp_object->snmp_errstr, 1);
                   1959:        return;
                   1960: }
                   1961: /* }}} */
                   1962: 
                   1963: /* {{{ */
                   1964: 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 TSRMLS_DC)
                   1965: {
                   1966:        php_snmp_prop_handler p;
                   1967: 
                   1968:        p.name = (char*) name;
                   1969:        p.name_length = name_length;
                   1970:        p.read_func = (read_func) ? read_func : NULL;
                   1971:        p.write_func = (write_func) ? write_func : NULL;
                   1972:        zend_hash_add(h, (char *)name, name_length + 1, &p, sizeof(php_snmp_prop_handler), NULL);
                   1973: }
                   1974: /* }}} */
                   1975: 
                   1976: /* {{{ php_snmp_read_property(zval *object, zval *member, int type[, const zend_literal *key])
                   1977:    Generic object property reader */
                   1978: zval *php_snmp_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
                   1979: {
                   1980:        zval tmp_member;
                   1981:        zval *retval;
                   1982:        php_snmp_object *obj;
                   1983:        php_snmp_prop_handler *hnd;
                   1984:        int ret;
                   1985: 
                   1986:        ret = FAILURE;
                   1987:        obj = (php_snmp_object *)zend_objects_get_address(object TSRMLS_CC);
                   1988: 
                   1989:        if (Z_TYPE_P(member) != IS_STRING) {
                   1990:                tmp_member = *member;
                   1991:                zval_copy_ctor(&tmp_member);
                   1992:                convert_to_string(&tmp_member);
                   1993:                member = &tmp_member;
                   1994:        }
                   1995: 
                   1996:        ret = zend_hash_find(&php_snmp_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd);
                   1997: 
                   1998:        if (ret == SUCCESS && hnd->read_func) {
                   1999:                ret = hnd->read_func(obj, &retval TSRMLS_CC);
                   2000:                if (ret == SUCCESS) {
                   2001:                        /* ensure we're creating a temporary variable */
                   2002:                        Z_SET_REFCOUNT_P(retval, 0);
                   2003:                } else {
                   2004:                        retval = EG(uninitialized_zval_ptr);
                   2005:                }
                   2006:        } else {
                   2007:                zend_object_handlers * std_hnd = zend_get_std_object_handlers();
                   2008:                retval = std_hnd->read_property(object, member, type, key TSRMLS_CC);
                   2009:        }
                   2010: 
                   2011:        if (member == &tmp_member) {
                   2012:                zval_dtor(member);
                   2013:        }
                   2014:        return(retval);
                   2015: }
                   2016: /* }}} */
                   2017: 
                   2018: /* {{{ php_snmp_write_property(zval *object, zval *member, zval *value[, const zend_literal *key])
                   2019:    Generic object property writer */
                   2020: void php_snmp_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
                   2021: {
                   2022:        zval tmp_member;
                   2023:        php_snmp_object *obj;
                   2024:        php_snmp_prop_handler *hnd;
                   2025:        int ret;
                   2026: 
                   2027:        if (Z_TYPE_P(member) != IS_STRING) {
                   2028:                tmp_member = *member;
                   2029:                zval_copy_ctor(&tmp_member);
                   2030:                convert_to_string(&tmp_member);
                   2031:                member = &tmp_member;
                   2032:        }
                   2033: 
                   2034:        ret = FAILURE;
                   2035:        obj = (php_snmp_object *)zend_objects_get_address(object TSRMLS_CC);
                   2036: 
                   2037:        ret = zend_hash_find(&php_snmp_properties, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **) &hnd);
                   2038: 
                   2039:        if (ret == SUCCESS && hnd->write_func) {
                   2040:                hnd->write_func(obj, value TSRMLS_CC);
                   2041:                if (! PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) == 0) {
                   2042:                        Z_ADDREF_P(value);
                   2043:                        zval_ptr_dtor(&value);
                   2044:                }
                   2045:        } else {
                   2046:                zend_object_handlers * std_hnd = zend_get_std_object_handlers();
                   2047:                std_hnd->write_property(object, member, value, key TSRMLS_CC);
                   2048:        }
                   2049: 
                   2050:        if (member == &tmp_member) {
                   2051:                zval_dtor(member);
                   2052:        }
                   2053: }
                   2054: /* }}} */
                   2055: 
                   2056: /* {{{ php_snmp_has_property(zval *object, zval *member, int has_set_exists[, const zend_literal *key])
                   2057:    Generic object property checker */
                   2058: static int php_snmp_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC)
                   2059: {
                   2060:        php_snmp_prop_handler *hnd;
                   2061:        int ret = 0;
                   2062: 
                   2063:        if (zend_hash_find(&php_snmp_properties, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **)&hnd) == SUCCESS) {
                   2064:                switch (has_set_exists) {
                   2065:                        case 2:
                   2066:                                ret = 1;
                   2067:                                break;
                   2068:                        case 0: {
                   2069:                                zval *value = php_snmp_read_property(object, member, BP_VAR_IS, key TSRMLS_CC);
                   2070:                                if (value != EG(uninitialized_zval_ptr)) {
                   2071:                                        ret = Z_TYPE_P(value) != IS_NULL? 1:0;
                   2072:                                        /* refcount is 0 */
                   2073:                                        Z_ADDREF_P(value);
                   2074:                                        zval_ptr_dtor(&value);
                   2075:                                }
                   2076:                                break;
                   2077:                        }
                   2078:                        default: {
                   2079:                                zval *value = php_snmp_read_property(object, member, BP_VAR_IS, key TSRMLS_CC);
                   2080:                                if (value != EG(uninitialized_zval_ptr)) {
                   2081:                                        convert_to_boolean(value);
                   2082:                                        ret = Z_BVAL_P(value)? 1:0;
                   2083:                                        /* refcount is 0 */
                   2084:                                        Z_ADDREF_P(value);
                   2085:                                        zval_ptr_dtor(&value);
                   2086:                                }
                   2087:                                break;
                   2088:                        }
                   2089:                }
                   2090:        } else {
                   2091:                zend_object_handlers * std_hnd = zend_get_std_object_handlers();
                   2092:                ret = std_hnd->has_property(object, member, has_set_exists, key TSRMLS_CC);
                   2093:        }
                   2094:        return ret;
                   2095: }
                   2096: /* }}} */
                   2097: 
                   2098: /* {{{ php_snmp_get_properties(zval *object)
                   2099:    Returns all object properties. Injects SNMP properties into object on first call */
                   2100: static HashTable *php_snmp_get_properties(zval *object TSRMLS_DC)
                   2101: {
                   2102:        php_snmp_object *obj;
                   2103:        php_snmp_prop_handler *hnd;
                   2104:        HashTable *props;
                   2105:        zval *val;
                   2106:        char *key;
                   2107:        uint key_len;
                   2108:        HashPosition pos;
                   2109:        ulong num_key;
                   2110: 
                   2111:        obj = (php_snmp_object *)zend_objects_get_address(object TSRMLS_CC);
                   2112:        props = zend_std_get_properties(object TSRMLS_CC);
                   2113: 
                   2114:        zend_hash_internal_pointer_reset_ex(&php_snmp_properties, &pos);
                   2115: 
                   2116:        while (zend_hash_get_current_data_ex(&php_snmp_properties, (void**)&hnd, &pos) == SUCCESS) {
                   2117:                zend_hash_get_current_key_ex(&php_snmp_properties, &key, &key_len, &num_key, 0, &pos);
                   2118:                if (!hnd->read_func || hnd->read_func(obj, &val TSRMLS_CC) != SUCCESS) {
                   2119:                        val = EG(uninitialized_zval_ptr);
                   2120:                        Z_ADDREF_P(val);
                   2121:                }
                   2122:                zend_hash_update(props, key, key_len, (void *)&val, sizeof(zval *), NULL);
                   2123:                zend_hash_move_forward_ex(&php_snmp_properties, &pos);
                   2124:        }
                   2125:        return obj->zo.properties;
                   2126: }
                   2127: /* }}} */
                   2128: 
                   2129: /* {{{ */
                   2130: static int php_snmp_read_info(php_snmp_object *snmp_object, zval **retval TSRMLS_DC)
                   2131: {
                   2132:        zval *val;
                   2133: 
                   2134:        MAKE_STD_ZVAL(*retval);
                   2135:        array_init(*retval);
                   2136: 
                   2137:        if (snmp_object->session == NULL) {
                   2138:                return SUCCESS;
                   2139:        }
                   2140:                
                   2141:        MAKE_STD_ZVAL(val);
                   2142:        ZVAL_STRINGL(val, snmp_object->session->peername, strlen(snmp_object->session->peername), 1);
                   2143:        add_assoc_zval(*retval, "hostname", val);
                   2144:        
                   2145:        MAKE_STD_ZVAL(val);
                   2146:        ZVAL_LONG(val, snmp_object->session->remote_port);
                   2147:        add_assoc_zval(*retval, "port", val);
                   2148:        
                   2149:        MAKE_STD_ZVAL(val);
                   2150:        ZVAL_LONG(val, snmp_object->session->timeout);
                   2151:        add_assoc_zval(*retval, "timeout", val);
                   2152:        
                   2153:        MAKE_STD_ZVAL(val);
                   2154:        ZVAL_LONG(val, snmp_object->session->retries);
                   2155:        add_assoc_zval(*retval, "retries", val);
                   2156:        
                   2157:        return SUCCESS;
                   2158: }
                   2159: /* }}} */
                   2160: 
                   2161: /* {{{ */
                   2162: static int php_snmp_read_max_oids(php_snmp_object *snmp_object, zval **retval TSRMLS_DC)
                   2163: {
                   2164:        MAKE_STD_ZVAL(*retval);
                   2165:        if (snmp_object->max_oids > 0) {
                   2166:                ZVAL_LONG(*retval, snmp_object->max_oids);
                   2167:        } else {
                   2168:                ZVAL_NULL(*retval);
                   2169:        }
                   2170:        return SUCCESS;
                   2171: }
                   2172: /* }}} */
                   2173: 
                   2174: #define PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(name) \
                   2175:        static int php_snmp_read_##name(php_snmp_object *snmp_object, zval **retval TSRMLS_DC) \
                   2176:        { \
                   2177:                MAKE_STD_ZVAL(*retval); \
                   2178:                ZVAL_BOOL(*retval, snmp_object->name); \
                   2179:                return SUCCESS; \
                   2180:        }
                   2181: 
                   2182: PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(oid_increasing_check)
                   2183: PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(quick_print)
                   2184: PHP_SNMP_BOOL_PROPERTY_READER_FUNCTION(enum_print)
                   2185: 
                   2186: #define PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(name) \
                   2187:        static int php_snmp_read_##name(php_snmp_object *snmp_object, zval **retval TSRMLS_DC) \
                   2188:        { \
                   2189:                MAKE_STD_ZVAL(*retval); \
                   2190:                ZVAL_LONG(*retval, snmp_object->name); \
                   2191:                return SUCCESS; \
                   2192:        }
                   2193: 
                   2194: PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(valueretrieval)
                   2195: PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(oid_output_format)
                   2196: PHP_SNMP_LONG_PROPERTY_READER_FUNCTION(exceptions_enabled)
                   2197: 
                   2198: /* {{{ */
                   2199: static int php_snmp_write_info(php_snmp_object *snmp_object, zval *newval TSRMLS_DC)
                   2200: {
                   2201:        php_error_docref(NULL TSRMLS_CC, E_WARNING, "info property is read-only");
                   2202:        return FAILURE;
                   2203: }
                   2204: /* }}} */
                   2205: 
                   2206: /* {{{ */
                   2207: static int php_snmp_write_max_oids(php_snmp_object *snmp_object, zval *newval TSRMLS_DC)
                   2208: {
                   2209:        zval ztmp;
                   2210:        int ret = SUCCESS;
                   2211: 
                   2212:        if (Z_TYPE_P(newval) == IS_NULL) {
                   2213:                snmp_object->max_oids = 0;
                   2214:                return ret;
                   2215:        }
                   2216: 
                   2217:        if (Z_TYPE_P(newval) != IS_LONG) {
                   2218:                ztmp = *newval;
                   2219:                zval_copy_ctor(&ztmp);
                   2220:                convert_to_long(&ztmp);
                   2221:                newval = &ztmp;
                   2222:        }
                   2223: 
                   2224:        if (Z_LVAL_P(newval) > 0) {
                   2225:                snmp_object->max_oids = Z_LVAL_P(newval);
                   2226:        } else {
                   2227:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "max_oids should be positive integer or NULL, got %ld", Z_LVAL_P(newval));
                   2228:        }
                   2229:        
                   2230:        if (newval == &ztmp) {
                   2231:                zval_dtor(newval);
                   2232:        }
                   2233: 
                   2234:        return ret;
                   2235: }
                   2236: /* }}} */
                   2237: 
                   2238: /* {{{ */
                   2239: static int php_snmp_write_valueretrieval(php_snmp_object *snmp_object, zval *newval TSRMLS_DC)
                   2240: {
                   2241:        zval ztmp;
                   2242:        int ret = SUCCESS;
                   2243: 
                   2244:        if (Z_TYPE_P(newval) != IS_LONG) {
                   2245:                ztmp = *newval;
                   2246:                zval_copy_ctor(&ztmp);
                   2247:                convert_to_long(&ztmp);
                   2248:                newval = &ztmp;
                   2249:        }
                   2250: 
                   2251:        if (Z_LVAL_P(newval) >= 0 && Z_LVAL_P(newval) <= (SNMP_VALUE_LIBRARY|SNMP_VALUE_PLAIN|SNMP_VALUE_OBJECT)) {
                   2252:                snmp_object->valueretrieval = Z_LVAL_P(newval);
                   2253:        } else {
                   2254:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown SNMP value retrieval method '%ld'", Z_LVAL_P(newval));
                   2255:                ret = FAILURE;
                   2256:        }
                   2257:        
                   2258:        if (newval == &ztmp) {
                   2259:                zval_dtor(newval);
                   2260:        }
                   2261: 
                   2262:        return ret;
                   2263: }
                   2264: /* }}} */
                   2265: 
                   2266: #define PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(name) \
                   2267: static int php_snmp_write_##name(php_snmp_object *snmp_object, zval *newval TSRMLS_DC) \
                   2268: { \
                   2269:        zval ztmp; \
                   2270:        if (Z_TYPE_P(newval) != IS_BOOL) { \
                   2271:                ztmp = *newval; \
                   2272:                zval_copy_ctor(&ztmp); \
                   2273:                convert_to_boolean(&ztmp); \
                   2274:                newval = &ztmp; \
                   2275:        } \
                   2276: \
                   2277:        snmp_object->name = Z_LVAL_P(newval); \
                   2278: \
                   2279:        if (newval == &ztmp) { \
                   2280:                zval_dtor(newval); \
                   2281:        } \
                   2282:        return SUCCESS; \
                   2283: }
                   2284: 
                   2285: PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(quick_print)
                   2286: PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(enum_print)
                   2287: PHP_SNMP_BOOL_PROPERTY_WRITER_FUNCTION(oid_increasing_check)
                   2288: 
                   2289: /* {{{ */
                   2290: static int php_snmp_write_oid_output_format(php_snmp_object *snmp_object, zval *newval TSRMLS_DC)
                   2291: {
                   2292:        zval ztmp;
                   2293:        int ret = SUCCESS;
                   2294:        if (Z_TYPE_P(newval) != IS_LONG) {
                   2295:                ztmp = *newval;
                   2296:                zval_copy_ctor(&ztmp);
                   2297:                convert_to_long(&ztmp);
                   2298:                newval = &ztmp;
                   2299:        }
                   2300:        
                   2301:        switch(Z_LVAL_P(newval)) {
                   2302:                case NETSNMP_OID_OUTPUT_SUFFIX:
                   2303:                case NETSNMP_OID_OUTPUT_MODULE:
                   2304:                case NETSNMP_OID_OUTPUT_FULL:
                   2305:                case NETSNMP_OID_OUTPUT_NUMERIC:
                   2306:                case NETSNMP_OID_OUTPUT_UCD:
                   2307:                case NETSNMP_OID_OUTPUT_NONE:
                   2308:                        snmp_object->oid_output_format = Z_LVAL_P(newval);
                   2309:                        break;
                   2310:                default:
                   2311:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown SNMP output print format '%ld'", Z_LVAL_P(newval));
                   2312:                        ret = FAILURE;
                   2313:                        break;
                   2314:        }
                   2315: 
                   2316:        if (newval == &ztmp) {
                   2317:                zval_dtor(newval);
                   2318:        }
                   2319:        return ret;
                   2320: }
                   2321: /* }}} */
                   2322: 
                   2323: /* {{{ */
                   2324: static int php_snmp_write_exceptions_enabled(php_snmp_object *snmp_object, zval *newval TSRMLS_DC)
                   2325: {
                   2326:        zval ztmp;
                   2327:        int ret = SUCCESS;
                   2328:        if (Z_TYPE_P(newval) != IS_LONG) {
                   2329:                ztmp = *newval;
                   2330:                zval_copy_ctor(&ztmp);
                   2331:                convert_to_long(&ztmp);
                   2332:                newval = &ztmp;
                   2333:        }
                   2334: 
                   2335:        snmp_object->exceptions_enabled = Z_LVAL_P(newval);     
                   2336: 
                   2337:        if (newval == &ztmp) {
                   2338:                zval_dtor(newval);
                   2339:        }
                   2340:        return ret;
                   2341: }
                   2342: /* }}} */
                   2343: 
                   2344: /* {{{ php_snmp_class_methods[] */
                   2345: static zend_function_entry php_snmp_class_methods[] = {
                   2346:        PHP_ME(snmp,     __construct,                   arginfo_snmp_create,            ZEND_ACC_PUBLIC)
                   2347:        PHP_ME(snmp,     close,                         arginfo_snmp_void,              ZEND_ACC_PUBLIC)
                   2348:        PHP_ME(snmp,     setSecurity,                   arginfo_snmp_setSecurity,       ZEND_ACC_PUBLIC)
                   2349: 
                   2350:        PHP_ME(snmp,     get,                           arginfo_snmp_get,               ZEND_ACC_PUBLIC)
                   2351:        PHP_ME(snmp,     getnext,                       arginfo_snmp_get,               ZEND_ACC_PUBLIC)
                   2352:        PHP_ME(snmp,     walk,                          arginfo_snmp_walk,              ZEND_ACC_PUBLIC)
                   2353:        PHP_ME(snmp,     set,                           arginfo_snmp_set,               ZEND_ACC_PUBLIC)
                   2354:        PHP_ME(snmp,     getErrno,                      arginfo_snmp_void,              ZEND_ACC_PUBLIC)
                   2355:        PHP_ME(snmp,     getError,                      arginfo_snmp_void,              ZEND_ACC_PUBLIC)
                   2356: 
                   2357:        PHP_FE_END
                   2358: };
                   2359: 
                   2360: #define PHP_SNMP_PROPERTY_ENTRY_RECORD(name) \
                   2361:        { "" #name "",          sizeof("" #name "") - 1,        php_snmp_read_##name,   php_snmp_write_##name }
                   2362: 
                   2363: const php_snmp_prop_handler php_snmp_property_entries[] = {
                   2364:        PHP_SNMP_PROPERTY_ENTRY_RECORD(info),
                   2365:        PHP_SNMP_PROPERTY_ENTRY_RECORD(max_oids),
                   2366:        PHP_SNMP_PROPERTY_ENTRY_RECORD(valueretrieval),
                   2367:        PHP_SNMP_PROPERTY_ENTRY_RECORD(quick_print),
                   2368:        PHP_SNMP_PROPERTY_ENTRY_RECORD(enum_print),
                   2369:        PHP_SNMP_PROPERTY_ENTRY_RECORD(oid_output_format),
                   2370:        PHP_SNMP_PROPERTY_ENTRY_RECORD(oid_increasing_check),
                   2371:        PHP_SNMP_PROPERTY_ENTRY_RECORD(exceptions_enabled),
                   2372:        { NULL, 0, NULL, NULL}
                   2373: };
                   2374: /* }}} */
                   2375: 
                   2376: /* {{{ PHP_MINIT_FUNCTION
                   2377:  */
                   2378: PHP_MINIT_FUNCTION(snmp)
                   2379: {
                   2380:        netsnmp_log_handler *logh;
                   2381:        zend_class_entry ce, cex;
                   2382: 
                   2383:        le_snmp_session = zend_register_list_destructors_ex(php_snmp_session_destructor, NULL, PHP_SNMP_SESSION_RES_NAME, module_number);
                   2384: 
                   2385:        init_snmp("snmpapp");
                   2386: 
                   2387: #ifdef NETSNMP_DS_LIB_DONT_PERSIST_STATE
                   2388:        /* Prevent update of the snmpapp.conf file */
                   2389:        netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
                   2390: #endif
                   2391: 
                   2392:        /* Disable logging, use exit status'es and related variabled to detect errors */
                   2393:        shutdown_snmp_logging();
                   2394:        logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_NONE, LOG_ERR);
                   2395:        if (logh) {
                   2396:                logh->pri_max = LOG_ERR;
                   2397:        }
                   2398: 
                   2399:        memcpy(&php_snmp_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
                   2400:        php_snmp_object_handlers.read_property = php_snmp_read_property;
                   2401:        php_snmp_object_handlers.write_property = php_snmp_write_property;
                   2402:        php_snmp_object_handlers.has_property = php_snmp_has_property;
                   2403:        php_snmp_object_handlers.get_properties = php_snmp_get_properties;
                   2404: 
                   2405:        /* Register SNMP Class */
                   2406:        INIT_CLASS_ENTRY(ce, "SNMP", php_snmp_class_methods);
                   2407:        ce.create_object = php_snmp_object_new;
                   2408:        php_snmp_object_handlers.clone_obj = NULL;
                   2409:        php_snmp_ce = zend_register_internal_class(&ce TSRMLS_CC);
                   2410: 
                   2411:        /* Register SNMP Class properties */
                   2412:        zend_hash_init(&php_snmp_properties, 0, NULL, NULL, 1);
                   2413:        PHP_SNMP_ADD_PROPERTIES(&php_snmp_properties, php_snmp_property_entries);
                   2414: 
                   2415:        REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_SUFFIX",        NETSNMP_OID_OUTPUT_SUFFIX,      CONST_CS | CONST_PERSISTENT);
                   2416:        REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_MODULE",        NETSNMP_OID_OUTPUT_MODULE,      CONST_CS | CONST_PERSISTENT);
                   2417:        REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_FULL",          NETSNMP_OID_OUTPUT_FULL,        CONST_CS | CONST_PERSISTENT);
                   2418:        REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_NUMERIC",       NETSNMP_OID_OUTPUT_NUMERIC,     CONST_CS | CONST_PERSISTENT);
                   2419:        REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_UCD",           NETSNMP_OID_OUTPUT_UCD,         CONST_CS | CONST_PERSISTENT);
                   2420:        REGISTER_LONG_CONSTANT("SNMP_OID_OUTPUT_NONE",          NETSNMP_OID_OUTPUT_NONE,        CONST_CS | CONST_PERSISTENT);
                   2421: 
                   2422:        REGISTER_LONG_CONSTANT("SNMP_VALUE_LIBRARY",    SNMP_VALUE_LIBRARY,     CONST_CS | CONST_PERSISTENT);
                   2423:        REGISTER_LONG_CONSTANT("SNMP_VALUE_PLAIN",      SNMP_VALUE_PLAIN,       CONST_CS | CONST_PERSISTENT);
                   2424:        REGISTER_LONG_CONSTANT("SNMP_VALUE_OBJECT",     SNMP_VALUE_OBJECT,      CONST_CS | CONST_PERSISTENT);
                   2425: 
                   2426:        REGISTER_LONG_CONSTANT("SNMP_BIT_STR",          ASN_BIT_STR,    CONST_CS | CONST_PERSISTENT);
                   2427:        REGISTER_LONG_CONSTANT("SNMP_OCTET_STR",        ASN_OCTET_STR,  CONST_CS | CONST_PERSISTENT);
                   2428:        REGISTER_LONG_CONSTANT("SNMP_OPAQUE",           ASN_OPAQUE,     CONST_CS | CONST_PERSISTENT);
                   2429:        REGISTER_LONG_CONSTANT("SNMP_NULL",             ASN_NULL,       CONST_CS | CONST_PERSISTENT);
                   2430:        REGISTER_LONG_CONSTANT("SNMP_OBJECT_ID",        ASN_OBJECT_ID,  CONST_CS | CONST_PERSISTENT);
                   2431:        REGISTER_LONG_CONSTANT("SNMP_IPADDRESS",        ASN_IPADDRESS,  CONST_CS | CONST_PERSISTENT);
                   2432:        REGISTER_LONG_CONSTANT("SNMP_COUNTER",          ASN_GAUGE,      CONST_CS | CONST_PERSISTENT);
                   2433:        REGISTER_LONG_CONSTANT("SNMP_UNSIGNED",         ASN_UNSIGNED,   CONST_CS | CONST_PERSISTENT);
                   2434:        REGISTER_LONG_CONSTANT("SNMP_TIMETICKS",        ASN_TIMETICKS,  CONST_CS | CONST_PERSISTENT);
                   2435:        REGISTER_LONG_CONSTANT("SNMP_UINTEGER",         ASN_UINTEGER,   CONST_CS | CONST_PERSISTENT);
                   2436:        REGISTER_LONG_CONSTANT("SNMP_INTEGER",          ASN_INTEGER,    CONST_CS | CONST_PERSISTENT);
                   2437:        REGISTER_LONG_CONSTANT("SNMP_COUNTER64",        ASN_COUNTER64,  CONST_CS | CONST_PERSISTENT);
                   2438: 
                   2439:        REGISTER_SNMP_CLASS_CONST_LONG("VERSION_1",                     SNMP_VERSION_1);
                   2440:        REGISTER_SNMP_CLASS_CONST_LONG("VERSION_2c",                    SNMP_VERSION_2c);
                   2441:        REGISTER_SNMP_CLASS_CONST_LONG("VERSION_2C",                    SNMP_VERSION_2c);
                   2442:        REGISTER_SNMP_CLASS_CONST_LONG("VERSION_3",                     SNMP_VERSION_3);
                   2443: 
                   2444:        REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_NOERROR",                 PHP_SNMP_ERRNO_NOERROR);
                   2445:        REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_ANY",                     PHP_SNMP_ERRNO_ANY);
                   2446:        REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_GENERIC",                 PHP_SNMP_ERRNO_GENERIC);
                   2447:        REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_TIMEOUT",                 PHP_SNMP_ERRNO_TIMEOUT);
                   2448:        REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_ERROR_IN_REPLY",          PHP_SNMP_ERRNO_ERROR_IN_REPLY);
                   2449:        REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_OID_NOT_INCREASING",      PHP_SNMP_ERRNO_OID_NOT_INCREASING);
                   2450:        REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_OID_PARSING_ERROR",       PHP_SNMP_ERRNO_OID_PARSING_ERROR);
                   2451:        REGISTER_SNMP_CLASS_CONST_LONG("ERRNO_MULTIPLE_SET_QUERIES",    PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES);
                   2452: 
                   2453:        /* Register SNMPException class */
                   2454:        INIT_CLASS_ENTRY(cex, "SNMPException", NULL);
                   2455: #ifdef HAVE_SPL
                   2456:        php_snmp_exception_ce = zend_register_internal_class_ex(&cex, spl_ce_RuntimeException, NULL TSRMLS_CC);
                   2457: #else
                   2458:        php_snmp_exception_ce = zend_register_internal_class_ex(&cex, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
                   2459: #endif
                   2460: 
                   2461:        return SUCCESS;
                   2462: }
                   2463: /* }}} */
                   2464: 
                   2465: /* {{{ PHP_MSHUTDOWN_FUNCTION
                   2466:  */
                   2467: PHP_MSHUTDOWN_FUNCTION(snmp)
                   2468: {
                   2469:        snmp_shutdown("snmpapp");
                   2470:        
                   2471:        zend_hash_destroy(&php_snmp_properties);
                   2472: 
                   2473:        return SUCCESS;
                   2474: }
                   2475: /* }}} */
                   2476: 
                   2477: /* {{{ PHP_MINFO_FUNCTION
                   2478:  */
                   2479: PHP_MINFO_FUNCTION(snmp)
                   2480: {
                   2481:        php_info_print_table_start();
                   2482:        php_info_print_table_row(2, "NET-SNMP Support", "enabled");
                   2483:        php_info_print_table_row(2, "NET-SNMP Version", netsnmp_get_version());
                   2484:        php_info_print_table_row(2, "PHP SNMP Version", PHP_SNMP_VERSION);
                   2485:        php_info_print_table_end();
                   2486: }
                   2487: /* }}} */
                   2488: 
                   2489: /* {{{ snmp_module_deps[]
                   2490:  */
                   2491: static const zend_module_dep snmp_module_deps[] = {
                   2492: #ifdef HAVE_SPL
                   2493:        ZEND_MOD_REQUIRED("spl")
                   2494: #endif
                   2495:        ZEND_MOD_END
                   2496: };
                   2497: /* }}} */
                   2498: 
                   2499: /* {{{ snmp_module_entry
                   2500:  */
                   2501: zend_module_entry snmp_module_entry = {
                   2502:        STANDARD_MODULE_HEADER_EX,
                   2503:        NULL,
                   2504:        snmp_module_deps,
                   2505:        "snmp",
                   2506:        snmp_functions,
                   2507:        PHP_MINIT(snmp),
                   2508:        PHP_MSHUTDOWN(snmp),
                   2509:        NULL,
                   2510:        NULL,
                   2511:        PHP_MINFO(snmp),
                   2512:        PHP_SNMP_VERSION,
                   2513:        PHP_MODULE_GLOBALS(snmp),
                   2514:        PHP_GINIT(snmp),
                   2515:        NULL,
                   2516:        NULL,
                   2517:        STANDARD_MODULE_PROPERTIES_EX
                   2518: };
                   2519: /* }}} */
                   2520: 
1.1       misho    2521: #endif
                   2522: 
                   2523: /*
                   2524:  * Local variables:
                   2525:  * tab-width: 4
                   2526:  * c-basic-offset: 4
                   2527:  * End:
                   2528:  * vim600: sw=4 ts=4 fdm=marker
                   2529:  * vim<600: sw=4 ts=4
                   2530:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>