diff options
Diffstat (limited to 'python/netsnmp/client_intf.c')
-rw-r--r-- | python/netsnmp/client_intf.c | 2601 |
1 files changed, 2601 insertions, 0 deletions
diff --git a/python/netsnmp/client_intf.c b/python/netsnmp/client_intf.c new file mode 100644 index 0000000..0b74e0e --- /dev/null +++ b/python/netsnmp/client_intf.c @@ -0,0 +1,2601 @@ +#include <Python.h> + +#if PY_VERSION_HEX < 0x02050000 +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +#endif + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> +#include <sys/types.h> +#include <arpa/inet.h> +#include <errno.h> +#include <stdio.h> +#include <ctype.h> +#ifdef I_SYS_TIME +#include <sys/time.h> +#endif +#include <netdb.h> +#include <stdlib.h> + +#ifdef HAVE_REGEX_H +#include <regex.h> +#endif + +#define SUCCESS 1 +#define FAILURE 0 + +#define VARBIND_TAG_F 0 +#define VARBIND_IID_F 1 +#define VARBIND_VAL_F 2 +#define VARBIND_TYPE_F 3 + +#define TYPE_UNKNOWN 0 +#define MAX_TYPE_NAME_LEN 32 +#define STR_BUF_SIZE (MAX_TYPE_NAME_LEN * MAX_OID_LEN) +#define ENG_ID_BUF_SIZE 32 + +#define NO_RETRY_NOSUCH 0 + +/* these should be part of transform_oids.h ? */ +#define USM_AUTH_PROTO_MD5_LEN 10 +#define USM_AUTH_PROTO_SHA_LEN 10 +#define USM_PRIV_PROTO_DES_LEN 10 + +#define STRLEN(x) (x ? strlen(x) : 0) + +/* from perl/SNMP/perlsnmp.h: */ +#ifndef timeradd +#define timeradd(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ + if ((result)->tv_usec >= 1000000) \ + { \ + ++(result)->tv_sec; \ + (result)->tv_usec -= 1000000; \ + } \ + } while (0) +#endif + +#ifndef timersub +#define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +typedef netsnmp_session SnmpSession; +typedef struct tree SnmpMibNode; +static int __is_numeric_oid (char*); +static int __is_leaf (struct tree*); +static int __translate_appl_type (char*); +static int __translate_asn_type (int); +static int __snprint_value (char *, size_t, + netsnmp_variable_list*, struct tree *, + int, int); +static int __sprint_num_objid (char *, oid *, int); +static int __scan_num_objid (char *, oid *, size_t *); +static int __get_type_str (int, char *); +static int __get_label_iid (char *, char **, char **, int); +static struct tree * __tag2oid (char *, char *, oid *, int *, int *, int); +static int __concat_oid_str (oid *, int *, char *); +static int __add_var_val_str (netsnmp_pdu *, oid *, int, char *, + int, int); +#define USE_NUMERIC_OIDS 0x08 +#define NON_LEAF_NAME 0x04 +#define USE_LONG_NAMES 0x02 +#define FAIL_ON_NULL_IID 0x01 +#define NO_FLAGS 0x00 + + +/* Wrapper around fprintf(stderr, ...) for clean and easy debug output. */ +static int _debug_level = 0; +#ifdef DEBUGGING +#define DBPRT(severity, otherargs) \ + do { \ + if (_debug_level && severity <= _debug_level) { \ + (void)printf(otherargs); \ + } \ + } while (/*CONSTCOND*/0) +#else /* DEBUGGING */ +#define DBPRT(severity, otherargs) /* Ignore */ +#endif /* DEBUGGING */ + +#define SAFE_FREE(x) do {if (x != NULL) free(x);} while(/*CONSTCOND*/0) + +void +__libraries_init(char *appname) +{ + static int have_inited = 0; + + if (have_inited) + return; + have_inited = 1; + + snmp_set_quick_print(1); + snmp_enable_stderrlog(); + init_snmp(appname); + + netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS, 1); + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY, 1); + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_SUFFIX); +} + +static int +__is_numeric_oid (oidstr) +char* oidstr; +{ + if (!oidstr) return 0; + for (; *oidstr; oidstr++) { + if (isalpha((int)*oidstr)) return 0; + } + return(1); +} + +static int +__is_leaf (tp) +struct tree* tp; +{ + char buf[MAX_TYPE_NAME_LEN]; + return (tp && (__get_type_str(tp->type,buf) || + (tp->parent && __get_type_str(tp->parent->type,buf) ))); +} + +static int +__translate_appl_type(typestr) +char* typestr; +{ + if (typestr == NULL || *typestr == '\0') return TYPE_UNKNOWN; + + if (!strncasecmp(typestr,"INTEGER32",8)) + return(TYPE_INTEGER32); + if (!strncasecmp(typestr,"INTEGER",3)) + return(TYPE_INTEGER); + if (!strncasecmp(typestr,"UNSIGNED32",3)) + return(TYPE_UNSIGNED32); + if (!strcasecmp(typestr,"COUNTER")) /* check all in case counter64 */ + return(TYPE_COUNTER); + if (!strncasecmp(typestr,"GAUGE",3)) + return(TYPE_GAUGE); + if (!strncasecmp(typestr,"IPADDR",3)) + return(TYPE_IPADDR); + if (!strncasecmp(typestr,"OCTETSTR",3)) + return(TYPE_OCTETSTR); + if (!strncasecmp(typestr,"TICKS",3)) + return(TYPE_TIMETICKS); + if (!strncasecmp(typestr,"OPAQUE",3)) + return(TYPE_OPAQUE); + if (!strncasecmp(typestr,"OBJECTID",3)) + return(TYPE_OBJID); + if (!strncasecmp(typestr,"NETADDR",3)) + return(TYPE_NETADDR); + if (!strncasecmp(typestr,"COUNTER64",3)) + return(TYPE_COUNTER64); + if (!strncasecmp(typestr,"NULL",3)) + return(TYPE_NULL); + if (!strncasecmp(typestr,"BITS",3)) + return(TYPE_BITSTRING); + if (!strncasecmp(typestr,"ENDOFMIBVIEW",3)) + return(SNMP_ENDOFMIBVIEW); + if (!strncasecmp(typestr,"NOSUCHOBJECT",7)) + return(SNMP_NOSUCHOBJECT); + if (!strncasecmp(typestr,"NOSUCHINSTANCE",7)) + return(SNMP_NOSUCHINSTANCE); + if (!strncasecmp(typestr,"UINTEGER",3)) + return(TYPE_UINTEGER); /* historic - should not show up */ + /* but it does? */ + if (!strncasecmp(typestr, "NOTIF", 3)) + return(TYPE_NOTIFTYPE); + if (!strncasecmp(typestr, "TRAP", 4)) + return(TYPE_TRAPTYPE); + return(TYPE_UNKNOWN); +} + +static int +__translate_asn_type(type) +int type; +{ + switch (type) { + case ASN_INTEGER: + return(TYPE_INTEGER); + case ASN_OCTET_STR: + return(TYPE_OCTETSTR); + case ASN_OPAQUE: + return(TYPE_OPAQUE); + case ASN_OBJECT_ID: + return(TYPE_OBJID); + case ASN_TIMETICKS: + return(TYPE_TIMETICKS); + case ASN_GAUGE: + return(TYPE_GAUGE); + case ASN_COUNTER: + return(TYPE_COUNTER); + case ASN_IPADDRESS: + return(TYPE_IPADDR); + case ASN_BIT_STR: + return(TYPE_BITSTRING); + case ASN_NULL: + return(TYPE_NULL); + /* no translation for these exception type values */ + case SNMP_ENDOFMIBVIEW: + case SNMP_NOSUCHOBJECT: + case SNMP_NOSUCHINSTANCE: + return(type); + case ASN_UINTEGER: + return(TYPE_UINTEGER); + case ASN_COUNTER64: + return(TYPE_COUNTER64); + default: + fprintf(stderr, "translate_asn_type: unhandled asn type (%d)\n",type); + return(TYPE_OTHER); + } +} + +#define USE_BASIC 0 +#define USE_ENUMS 1 +#define USE_SPRINT_VALUE 2 +static int +__snprint_value (buf, buf_len, var, tp, type, flag) +char * buf; +size_t buf_len; +netsnmp_variable_list * var; +struct tree * tp; +int type; +int flag; +{ + int len = 0; + u_char* ip; + struct enum_list *ep; + + + buf[0] = '\0'; + if (flag == USE_SPRINT_VALUE) { + snprint_value(buf, buf_len, var->name, var->name_length, var); + len = STRLEN(buf); + } else { + switch (var->type) { + case ASN_INTEGER: + if (flag == USE_ENUMS) { + for(ep = tp->enums; ep; ep = ep->next) { + if (ep->value == *var->val.integer) { + strlcpy(buf, ep->label, buf_len); + len = STRLEN(buf); + break; + } + } + } + if (!len) { + snprintf(buf, buf_len, "%ld", *var->val.integer); + len = STRLEN(buf); + } + break; + + case ASN_GAUGE: + case ASN_COUNTER: + case ASN_TIMETICKS: + case ASN_UINTEGER: + snprintf(buf, buf_len, "%lu", (unsigned long) *var->val.integer); + len = STRLEN(buf); + break; + + case ASN_OCTET_STR: + case ASN_OPAQUE: + len = var->val_len; + if (len > buf_len) + len = buf_len; + memcpy(buf, (char*)var->val.string, len); + break; + + case ASN_IPADDRESS: + ip = (u_char*)var->val.string; + snprintf(buf, buf_len, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + len = STRLEN(buf); + break; + + case ASN_NULL: + break; + + case ASN_OBJECT_ID: + __sprint_num_objid(buf, (oid *)(var->val.objid), + var->val_len/sizeof(oid)); + len = STRLEN(buf); + break; + + case SNMP_ENDOFMIBVIEW: + snprintf(buf, buf_len, "%s", "ENDOFMIBVIEW"); + break; + case SNMP_NOSUCHOBJECT: + snprintf(buf, buf_len, "%s", "NOSUCHOBJECT"); + break; + case SNMP_NOSUCHINSTANCE: + snprintf(buf, buf_len, "%s", "NOSUCHINSTANCE"); + break; + + case ASN_COUNTER64: +#ifdef OPAQUE_SPECIAL_TYPES + case ASN_OPAQUE_COUNTER64: + case ASN_OPAQUE_U64: +#endif + printU64(buf,(struct counter64 *)var->val.counter64); + len = STRLEN(buf); + break; + +#ifdef OPAQUE_SPECIAL_TYPES + case ASN_OPAQUE_I64: + printI64(buf,(struct counter64 *)var->val.counter64); + len = STRLEN(buf); + break; +#endif + + case ASN_BIT_STR: + snprint_bitstring(buf, buf_len, var, NULL, NULL, NULL); + len = STRLEN(buf); + break; +#ifdef OPAQUE_SPECIAL_TYPES + case ASN_OPAQUE_FLOAT: + if (var->val.floatVal) + snprintf(buf, buf_len, "%f", *var->val.floatVal); + break; + + case ASN_OPAQUE_DOUBLE: + if (var->val.doubleVal) + snprintf(buf, buf_len, "%f", *var->val.doubleVal); + break; +#endif + + case ASN_NSAP: + default: + fprintf(stderr,"snprint_value: asn type not handled %d\n",var->type); + } + } + return(len); +} + +static int +__sprint_num_objid (buf, objid, len) +char *buf; +oid *objid; +int len; +{ + int i; + buf[0] = '\0'; + for (i=0; i < len; i++) { + sprintf(buf,".%lu",*objid++); + buf += STRLEN(buf); + } + return SUCCESS; +} + +static int +__scan_num_objid (buf, objid, len) +char *buf; +oid *objid; +size_t *len; +{ + char *cp; + *len = 0; + if (*buf == '.') buf++; + cp = buf; + while (*buf) { + if (*buf++ == '.') { + sscanf(cp, "%lu", objid++); + /* *objid++ = atoi(cp); */ + (*len)++; + cp = buf; + } else { + if (isalpha((int)*buf)) { + return FAILURE; + } + } + } + sscanf(cp, "%lu", objid++); + /* *objid++ = atoi(cp); */ + (*len)++; + return SUCCESS; +} + +static int +__get_type_str (type, str) +int type; +char * str; +{ + switch (type) { + case TYPE_OBJID: + strcpy(str, "OBJECTID"); + break; + case TYPE_OCTETSTR: + strcpy(str, "OCTETSTR"); + break; + case TYPE_INTEGER: + strcpy(str, "INTEGER"); + break; + case TYPE_INTEGER32: + strcpy(str, "INTEGER32"); + break; + case TYPE_UNSIGNED32: + strcpy(str, "UNSIGNED32"); + break; + case TYPE_NETADDR: + strcpy(str, "NETADDR"); + break; + case TYPE_IPADDR: + strcpy(str, "IPADDR"); + break; + case TYPE_COUNTER: + strcpy(str, "COUNTER"); + break; + case TYPE_GAUGE: + strcpy(str, "GAUGE"); + break; + case TYPE_TIMETICKS: + strcpy(str, "TICKS"); + break; + case TYPE_OPAQUE: + strcpy(str, "OPAQUE"); + break; + case TYPE_COUNTER64: + strcpy(str, "COUNTER64"); + break; + case TYPE_NULL: + strcpy(str, "NULL"); + break; + case SNMP_ENDOFMIBVIEW: + strcpy(str, "ENDOFMIBVIEW"); + break; + case SNMP_NOSUCHOBJECT: + strcpy(str, "NOSUCHOBJECT"); + break; + case SNMP_NOSUCHINSTANCE: + strcpy(str, "NOSUCHINSTANCE"); + break; + case TYPE_UINTEGER: + strcpy(str, "UINTEGER"); /* historic - should not show up */ + /* but it does? */ + break; + case TYPE_NOTIFTYPE: + strcpy(str, "NOTIF"); + break; + case TYPE_BITSTRING: + strcpy(str, "BITS"); + break; + case TYPE_TRAPTYPE: + strcpy(str, "TRAP"); + break; + case TYPE_OTHER: /* not sure if this is a valid leaf type?? */ + case TYPE_NSAPADDRESS: + default: /* unsupported types for now */ + strcpy(str, ""); + if (_debug_level) printf("__get_type_str:FAILURE(%d)\n", type); + + return(FAILURE); + } + return SUCCESS; +} + +/* does a destructive disection of <label1>...<labeln>.<iid> returning + <labeln> and <iid> in seperate strings (note: will destructively + alter input string, 'name') */ +static int +__get_label_iid (name, last_label, iid, flag) +char * name; +char ** last_label; +char ** iid; +int flag; +{ + char *lcp; + char *icp; + int len = STRLEN(name); + int found_label = 0; + + *last_label = *iid = NULL; + + if (len == 0) return(FAILURE); + + /* Handle case where numeric oid's have been requested. The input 'name' + ** in this case should be a numeric OID -- return failure if not. + */ + if ((flag & USE_NUMERIC_OIDS)) { + if (!__is_numeric_oid(name)) + return(FAILURE); + + /* Walk backward through the string, looking for first two '.' chars */ + lcp = &(name[len]); + icp = NULL; + while (lcp > name) { + if (*lcp == '.') { + + /* If this is the first occurence of '.', note it in icp. + ** Otherwise, this must be the second occurrence, so break + ** out of the loop. + */ + if (icp == NULL) + icp = lcp; + else + break; + } + lcp --; + } + + /* Make sure we found at least a label and index. */ + if (!icp) + return(FAILURE); + + /* Push forward past leading '.' chars and separate the strings. */ + lcp ++; + *icp ++ = '\0'; + + *last_label = (flag & USE_LONG_NAMES) ? name : lcp; + *iid = icp; + + return(SUCCESS); + } + + lcp = icp = &(name[len]); + + while (lcp > name) { + if (*lcp == '.') { + if (found_label) { + lcp++; + break; + } else { + icp = lcp; + } + } + if (!found_label && isalpha((int)*lcp)) found_label = 1; + lcp--; + } + + if (!found_label || (!isdigit((int)*(icp+1)) && (flag & FAIL_ON_NULL_IID))) + return(FAILURE); + + if (flag & NON_LEAF_NAME) { /* dont know where to start instance id */ + /* put the whole thing in label */ + icp = &(name[len]); + flag |= USE_LONG_NAMES; + /* special hack in case no mib loaded - object identifiers will + * start with .iso.<num>.<num>...., in which case it is preferable + * to make the label entirely numeric (i.e., convert "iso" => "1") + */ + if (*lcp == '.' && lcp == name) { + if (!strncmp(".ccitt.",lcp,7)) { + name += 2; + *name = '.'; + *(name+1) = '0'; + } else if (!strncmp(".iso.",lcp,5)) { + name += 2; + *name = '.'; + *(name+1) = '1'; + } else if (!strncmp(".joint-iso-ccitt.",lcp,17)) { + name += 2; + *name = '.'; + *(name+1) = '2'; + } + } + } else if (*icp) { + *(icp++) = '\0'; + } + *last_label = (flag & USE_LONG_NAMES ? name : lcp); + + *iid = icp; + + return(SUCCESS); +} + +/* Convert a tag (string) to an OID array */ +/* Tag can be either a symbolic name, or an OID string */ +static struct tree * +__tag2oid(tag, iid, oid_arr, oid_arr_len, type, best_guess) +char * tag; +char * iid; +oid * oid_arr; +int * oid_arr_len; +int * type; +int best_guess; +{ + struct tree *tp = NULL; + struct tree *rtp = NULL; + oid newname[MAX_OID_LEN], *op; + size_t newname_len = 0; + + if (type) *type = TYPE_UNKNOWN; + if (oid_arr_len) *oid_arr_len = 0; + if (!tag) goto done; + + /*********************************************************/ + /* best_guess = 0 - same as no switches (read_objid) */ + /* if multiple parts, or uses find_node */ + /* if a single leaf */ + /* best_guess = 1 - same as -Ib (get_wild_node) */ + /* best_guess = 2 - same as -IR (get_node) */ + /*********************************************************/ + + /* numeric scalar (1,2) */ + /* single symbolic (1,2) */ + /* single regex (1) */ + /* partial full symbolic (2) */ + /* full symbolic (2) */ + /* module::single symbolic (2) */ + /* module::partial full symbolic (2) */ + if (best_guess == 1 || best_guess == 2) { + if (!__scan_num_objid(tag, newname, &newname_len)) { /* make sure it's not a numeric tag */ + newname_len = MAX_OID_LEN; + if (best_guess == 2) { /* Random search -IR */ + if (get_node(tag, newname, &newname_len)) { + rtp = tp = get_tree(newname, newname_len, get_tree_head()); + } + } + else if (best_guess == 1) { /* Regex search -Ib */ + clear_tree_flags(get_tree_head()); + if (get_wild_node(tag, newname, &newname_len)) { + rtp = tp = get_tree(newname, newname_len, get_tree_head()); + } + } + } + else { + rtp = tp = get_tree(newname, newname_len, get_tree_head()); + } + if (type) *type = (tp ? tp->type : TYPE_UNKNOWN); + if ((oid_arr == NULL) || (oid_arr_len == NULL)) return rtp; + memcpy(oid_arr,(char*)newname,newname_len*sizeof(oid)); + *oid_arr_len = newname_len; + } + + /* if best_guess is off and multi part tag or module::tag */ + /* numeric scalar */ + /* module::single symbolic */ + /* module::partial full symbolic */ + /* FULL symbolic OID */ + else if (strchr(tag,'.') || strchr(tag,':')) { + if (!__scan_num_objid(tag, newname, &newname_len)) { /* make sure it's not a numeric tag */ + newname_len = MAX_OID_LEN; + if (read_objid(tag, newname, &newname_len)) { /* long name */ + rtp = tp = get_tree(newname, newname_len, get_tree_head()); + } + } + else { + rtp = tp = get_tree(newname, newname_len, get_tree_head()); + } + if (type) *type = (tp ? tp->type : TYPE_UNKNOWN); + if ((oid_arr == NULL) || (oid_arr_len == NULL)) return rtp; + memcpy(oid_arr,(char*)newname,newname_len*sizeof(oid)); + *oid_arr_len = newname_len; + } + + /* else best_guess is off and it is a single leaf */ + /* single symbolic */ + else { + rtp = tp = find_node(tag, get_tree_head()); + if (tp) { + if (type) *type = tp->type; + if ((oid_arr == NULL) || (oid_arr_len == NULL)) return rtp; + /* code taken from get_node in snmp_client.c */ + for(op = newname + MAX_OID_LEN - 1; op >= newname; op--){ + *op = tp->subid; + tp = tp->parent; + if (tp == NULL) + break; + } + *oid_arr_len = newname + MAX_OID_LEN - op; + memcpy(oid_arr, op, *oid_arr_len * sizeof(oid)); + } else { + return(rtp); /* HACK: otherwise, concat_oid_str confuses things */ + } + } + done: + if (iid && *iid && oid_arr_len) + __concat_oid_str(oid_arr, oid_arr_len, iid); + return(rtp); +} + +/* function: __concat_oid_str + * + * This function converts a dotted-decimal string, soid_str, to an array + * of oid types and concatenates them on doid_arr begining at the index + * specified by doid_arr_len. + * + * returns : SUCCESS, FAILURE + */ +static int +__concat_oid_str(doid_arr, doid_arr_len, soid_str) +oid *doid_arr; +int *doid_arr_len; +char * soid_str; +{ + char *soid_buf; + char *cp; + char *st; + + if (!soid_str || !*soid_str) return SUCCESS;/* successfully added nothing */ + if (*soid_str == '.') soid_str++; + soid_buf = strdup(soid_str); + if (!soid_buf) + return FAILURE; + cp = strtok_r(soid_buf,".",&st); + while (cp) { + sscanf(cp, "%lu", &(doid_arr[(*doid_arr_len)++])); + /* doid_arr[(*doid_arr_len)++] = atoi(cp); */ + cp = strtok_r(NULL,".",&st); + } + free(soid_buf); + return(SUCCESS); +} + +/* + * add a varbind to PDU + */ +static int +__add_var_val_str(pdu, name, name_length, val, len, type) + netsnmp_pdu *pdu; + oid *name; + int name_length; + char * val; + int len; + int type; +{ + netsnmp_variable_list *vars; + oid oidbuf[MAX_OID_LEN]; + int ret = SUCCESS; + + if (pdu->variables == NULL){ + pdu->variables = vars = + (netsnmp_variable_list *)calloc(1,sizeof(netsnmp_variable_list)); + } else { + for(vars = pdu->variables; + vars->next_variable; + vars = vars->next_variable) + /*EXIT*/; + vars->next_variable = + (netsnmp_variable_list *)calloc(1,sizeof(netsnmp_variable_list)); + vars = vars->next_variable; + } + + vars->next_variable = NULL; + vars->name = snmp_duplicate_objid(name, name_length); + vars->name_length = name_length; + switch (type) { + case TYPE_INTEGER: + case TYPE_INTEGER32: + vars->type = ASN_INTEGER; + vars->val.integer = (long *)malloc(sizeof(long)); + if (val) + *(vars->val.integer) = strtol(val,NULL,0); + else { + ret = FAILURE; + *(vars->val.integer) = 0; + } + vars->val_len = sizeof(long); + break; + + case TYPE_GAUGE: + case TYPE_UNSIGNED32: + vars->type = ASN_GAUGE; + goto UINT; + case TYPE_COUNTER: + vars->type = ASN_COUNTER; + goto UINT; + case TYPE_TIMETICKS: + vars->type = ASN_TIMETICKS; + goto UINT; + case TYPE_UINTEGER: + vars->type = ASN_UINTEGER; +UINT: + vars->val.integer = (long *)malloc(sizeof(long)); + if (val) + sscanf(val,"%lu",vars->val.integer); + else { + ret = FAILURE; + *(vars->val.integer) = 0; + } + vars->val_len = sizeof(long); + break; + + case TYPE_OCTETSTR: + vars->type = ASN_OCTET_STR; + goto OCT; + + case TYPE_BITSTRING: + vars->type = ASN_OCTET_STR; + goto OCT; + + case TYPE_OPAQUE: + vars->type = ASN_OCTET_STR; +OCT: + vars->val.string = (u_char *)malloc(len); + vars->val_len = len; + if (val && len) + memcpy((char *)vars->val.string, val, len); + else { + ret = FAILURE; + vars->val.string = (u_char*)strdup(""); + vars->val_len = 0; + } + break; + + case TYPE_IPADDR: + vars->type = ASN_IPADDRESS; + vars->val.integer = (long *)malloc(sizeof(long)); + if (val) + *(vars->val.integer) = inet_addr(val); + else { + ret = FAILURE; + *(vars->val.integer) = 0; + } + vars->val_len = sizeof(long); + break; + + case TYPE_OBJID: + vars->type = ASN_OBJECT_ID; + vars->val_len = MAX_OID_LEN; + /* if (read_objid(val, oidbuf, &(vars->val_len))) { */ + /* tp = __tag2oid(val,NULL,oidbuf,&(vars->val_len),NULL,0); */ + if (!val || !snmp_parse_oid(val, oidbuf, &vars->val_len)) { + vars->val.objid = NULL; + ret = FAILURE; + } else { + vars->val.objid = snmp_duplicate_objid(oidbuf, vars->val_len); + vars->val_len *= sizeof(oid); + } + break; + + default: + vars->type = ASN_NULL; + vars->val_len = 0; + vars->val.string = NULL; + ret = FAILURE; + } + + return ret; +} + +/* takes ss and pdu as input and updates the 'response' argument */ +/* the input 'pdu' argument will be freed */ +static int +__send_sync_pdu(ss, pdu, response, retry_nosuch, + err_str, err_num, err_ind) +netsnmp_session *ss; +netsnmp_pdu *pdu; +netsnmp_pdu **response; +int retry_nosuch; +char *err_str; +int *err_num; +int *err_ind; +{ + int status = 0; + long command = pdu->command; + char *tmp_err_str; + + *err_num = 0; + *err_ind = 0; + *response = NULL; + tmp_err_str = NULL; + memset(err_str, '\0', STR_BUF_SIZE); + + if (ss == NULL) { + *err_num = 0; + *err_ind = SNMPERR_BAD_SESSION; + strlcpy(err_str, snmp_api_errstring(*err_ind), STR_BUF_SIZE); + goto done; + } + +retry: + + Py_BEGIN_ALLOW_THREADS + status = snmp_sess_synch_response(ss, pdu, response); + Py_END_ALLOW_THREADS + + if ((*response == NULL) && (status == STAT_SUCCESS)) status = STAT_ERROR; + + switch (status) { + case STAT_SUCCESS: + switch ((*response)->errstat) { + case SNMP_ERR_NOERROR: + break; + + case SNMP_ERR_NOSUCHNAME: + if (retry_nosuch && (pdu = snmp_fix_pdu(*response, command))) { + if (*response) snmp_free_pdu(*response); + goto retry; + } + + /* Pv1, SNMPsec, Pv2p, v2c, v2u, v2*, and SNMPv3 PDUs */ + case SNMP_ERR_TOOBIG: + case SNMP_ERR_BADVALUE: + case SNMP_ERR_READONLY: + case SNMP_ERR_GENERR: + /* in SNMPv2p, SNMPv2c, SNMPv2u, SNMPv2*, and SNMPv3 PDUs */ + case SNMP_ERR_NOACCESS: + case SNMP_ERR_WRONGTYPE: + case SNMP_ERR_WRONGLENGTH: + case SNMP_ERR_WRONGENCODING: + case SNMP_ERR_WRONGVALUE: + case SNMP_ERR_NOCREATION: + case SNMP_ERR_INCONSISTENTVALUE: + case SNMP_ERR_RESOURCEUNAVAILABLE: + case SNMP_ERR_COMMITFAILED: + case SNMP_ERR_UNDOFAILED: + case SNMP_ERR_AUTHORIZATIONERROR: + case SNMP_ERR_NOTWRITABLE: + /* in SNMPv2c, SNMPv2u, SNMPv2*, and SNMPv3 PDUs */ + case SNMP_ERR_INCONSISTENTNAME: + default: + strlcpy(err_str, (char*)snmp_errstring((*response)->errstat), + STR_BUF_SIZE); + *err_num = (int)(*response)->errstat; + *err_ind = (*response)->errindex; + status = (*response)->errstat; + break; + } + break; + + case STAT_TIMEOUT: + case STAT_ERROR: + snmp_sess_error(ss, err_num, err_ind, &tmp_err_str); + strlcpy(err_str, tmp_err_str, STR_BUF_SIZE); + break; + + default: + strcat(err_str, "send_sync_pdu: unknown status"); + *err_num = ss->s_snmp_errno; + break; + } +done: + if (tmp_err_str) { + free(tmp_err_str); + } + if (_debug_level && *err_num) printf("XXX sync PDU: %s\n", err_str); + return(status); +} + +static PyObject * +py_netsnmp_construct_varbind(void) +{ + PyObject *module; + PyObject *dict; + PyObject *callable; + + module = PyImport_ImportModule("netsnmp"); + dict = PyModule_GetDict(module); + + callable = PyDict_GetItemString(dict, "Varbind"); + + return PyObject_CallFunction(callable, ""); +} + +static int +py_netsnmp_attr_string(PyObject *obj, char * attr_name, char **val, + Py_ssize_t *len) +{ + *val = NULL; + if (obj && attr_name && PyObject_HasAttrString(obj, attr_name)) { + PyObject *attr = PyObject_GetAttrString(obj, attr_name); + if (attr) { + int retval; + retval = PyString_AsStringAndSize(attr, val, len); + Py_DECREF(attr); + return retval; + } + } + + return -1; +} + +static long long +py_netsnmp_attr_long(PyObject *obj, char * attr_name) +{ + long long val = -1; + + if (obj && attr_name && PyObject_HasAttrString(obj, attr_name)) { + PyObject *attr = PyObject_GetAttrString(obj, attr_name); + if (attr) { + val = PyInt_AsLong(attr); + Py_DECREF(attr); + } + } + + return val; +} + +static void * +py_netsnmp_attr_void_ptr(PyObject *obj, char * attr_name) +{ + void *val = NULL; + + if (obj && attr_name && PyObject_HasAttrString(obj, attr_name)) { + PyObject *attr = PyObject_GetAttrString(obj, attr_name); + if (attr) { + val = PyLong_AsVoidPtr(attr); + Py_DECREF(attr); + } + } + + return val; +} + +static int +py_netsnmp_verbose(void) +{ + int verbose = 0; + PyObject *pkg = PyImport_ImportModule("netsnmp"); + if (pkg) { + verbose = py_netsnmp_attr_long(pkg, "verbose"); + Py_DECREF(pkg); + } + + return verbose; +} + +static int +py_netsnmp_attr_set_string(PyObject *obj, char *attr_name, + char *val, size_t len) +{ + int ret = -1; + if (obj && attr_name) { + PyObject* val_obj = (val ? + Py_BuildValue("s#", val, len) : + Py_BuildValue("")); + ret = PyObject_SetAttrString(obj, attr_name, val_obj); + Py_DECREF(val_obj); + } + return ret; +} + +/** + * Update python session object error attributes. + * + * Copy the error info which may have been returned from __send_sync_pdu(...) + * into the python object. This will allow the python code to determine if + * an error occured during an snmp operation. + * + * Currently there are 3 attributes we care about + * + * ErrorNum - Copy of the value of netsnmp_session.s_errno. This is the system + * errno that was generated during our last call into the net-snmp library. + * + * ErrorInd - Copy of the value of netsmp_session.s_snmp_errno. These error + * numbers are separate from the system errno's and describe SNMP errors. + * + * ErrorStr - A string describing the ErrorInd that was returned during our last + * operation. + * + * @param[in] session The python object that represents our current Session + * @param[in|out] err_str A string describing err_ind + * @param[in|out] err_num The system errno currently stored by our session + * @param[in|out] err_ind The snmp errno currently stored by our session + */ +static void +__py_netsnmp_update_session_errors(PyObject *session, char *err_str, + int err_num, int err_ind) +{ + PyObject *tmp_for_conversion; + + py_netsnmp_attr_set_string(session, "ErrorStr", err_str, STRLEN(err_str)); + + tmp_for_conversion = PyInt_FromLong(err_num); + PyObject_SetAttrString(session, "ErrorNum", tmp_for_conversion); + Py_DECREF(tmp_for_conversion); + + tmp_for_conversion = PyInt_FromLong(err_ind); + PyObject_SetAttrString(session, "ErrorInd", tmp_for_conversion); + Py_DECREF(tmp_for_conversion); +} + +static PyObject * +netsnmp_create_session(PyObject *self, PyObject *args) +{ + int version; + char *community; + char *peer; + int lport; + int retries; + int timeout; + SnmpSession session = {0}; + SnmpSession *ss = NULL; + int verbose = py_netsnmp_verbose(); + + if (!PyArg_ParseTuple(args, "issiii", &version, + &community, &peer, &lport, + &retries, &timeout)) + return NULL; + + __libraries_init("python"); + + snmp_sess_init(&session); + + session.version = -1; +#ifndef DISABLE_SNMPV1 + if (version == 1) { + session.version = SNMP_VERSION_1; + } +#endif +#ifndef DISABLE_SNMPV2C + if (version == 2) { + session.version = SNMP_VERSION_2c; + } +#endif + if (version == 3) { + session.version = SNMP_VERSION_3; + } + if (session.version == -1) { + if (verbose) + printf("error:snmp_new_session:Unsupported SNMP version (%d)\n", version); + goto end; + } + + session.community_len = STRLEN((char *)community); + session.community = (u_char *)community; + session.peername = peer; + session.local_port = lport; + session.retries = retries; /* 5 */ + session.timeout = timeout; /* 1000000L */ + session.authenticator = NULL; + + ss = snmp_sess_open(&session); + + if (ss == NULL) { + if (verbose) + printf("error:snmp_new_session: Couldn't open SNMP session"); + } + end: + return PyLong_FromVoidPtr((void *)ss); +} + +static PyObject * +netsnmp_create_session_v3(PyObject *self, PyObject *args) +{ + int version; + char *peer; + int lport; + int retries; + int timeout; + char * sec_name; + int sec_level; + char * sec_eng_id; + char * context_eng_id; + char * context; + char * auth_proto; + char * auth_pass; + char * priv_proto; + char * priv_pass; + int eng_boots; + int eng_time; + SnmpSession session = {0}; + SnmpSession *ss = NULL; + int verbose = py_netsnmp_verbose(); + + if (!PyArg_ParseTuple(args, "isiiisisssssssii", &version, + &peer, &lport, &retries, &timeout, + &sec_name, &sec_level, &sec_eng_id, + &context_eng_id, &context, + &auth_proto, &auth_pass, + &priv_proto, &priv_pass, + &eng_boots, &eng_time)) + return NULL; + + __libraries_init("python"); + snmp_sess_init(&session); + + if (version == 3) { + session.version = SNMP_VERSION_3; + } else { + if (verbose) + printf("error:snmp_new_v3_session:Unsupported SNMP version (%d)\n", version); + goto end; + } + + session.peername = peer; + session.retries = retries; /* 5 */ + session.timeout = timeout; /* 1000000L */ + session.authenticator = NULL; + session.contextNameLen = STRLEN(context); + session.contextName = context; + session.securityNameLen = STRLEN(sec_name); + session.securityName = sec_name; + session.securityLevel = sec_level; + session.securityModel = USM_SEC_MODEL_NUMBER; + session.securityEngineIDLen = + hex_to_binary2((unsigned char*)sec_eng_id, STRLEN(sec_eng_id), + (char **) &session.securityEngineID); + session.contextEngineIDLen = + hex_to_binary2((unsigned char*)sec_eng_id, STRLEN(sec_eng_id), + (char **) &session.contextEngineID); + session.engineBoots = eng_boots; + session.engineTime = eng_time; + +#ifndef DISABLE_MD5 + if (!strcmp(auth_proto, "MD5")) { + session.securityAuthProto = + snmp_duplicate_objid(usmHMACMD5AuthProtocol, + USM_AUTH_PROTO_MD5_LEN); + session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN; + } else +#endif + if (!strcmp(auth_proto, "SHA")) { + session.securityAuthProto = + snmp_duplicate_objid(usmHMACSHA1AuthProtocol, + USM_AUTH_PROTO_SHA_LEN); + session.securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN; + } else if (!strcmp(auth_proto, "DEFAULT")) { + const oid* a = get_default_authtype(&session.securityAuthProtoLen); + session.securityAuthProto + = snmp_duplicate_objid(a, session.securityAuthProtoLen); + } else { + if (verbose) + printf("error:snmp_new_v3_session:Unsupported authentication protocol(%s)\n", auth_proto); + goto end; + } + if (session.securityLevel >= SNMP_SEC_LEVEL_AUTHNOPRIV) { + if (STRLEN(auth_pass) > 0) { + session.securityAuthKeyLen = USM_AUTH_KU_LEN; + if (generate_Ku(session.securityAuthProto, + session.securityAuthProtoLen, + (u_char *)auth_pass, STRLEN(auth_pass), + session.securityAuthKey, + &session.securityAuthKeyLen) != SNMPERR_SUCCESS) { + if (verbose) + printf("error:snmp_new_v3_session:Error generating Ku from authentication password.\n"); + goto end; + } + } + } +#ifndef DISABLE_DES + if (!strcmp(priv_proto, "DES")) { + session.securityPrivProto = + snmp_duplicate_objid(usmDESPrivProtocol, + USM_PRIV_PROTO_DES_LEN); + session.securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN; + } else +#endif + if (!strncmp(priv_proto, "AES", 3)) { + session.securityPrivProto = + snmp_duplicate_objid(usmAESPrivProtocol, + USM_PRIV_PROTO_AES_LEN); + session.securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN; + } else if (!strcmp(priv_proto, "DEFAULT")) { + const oid *p = get_default_privtype(&session.securityPrivProtoLen); + session.securityPrivProto + = snmp_duplicate_objid(p, session.securityPrivProtoLen); + } else { + if (verbose) + printf("error:snmp_new_v3_session:Unsupported privacy protocol(%s)\n", priv_proto); + goto end; + } + + if (session.securityLevel >= SNMP_SEC_LEVEL_AUTHPRIV) { + session.securityPrivKeyLen = USM_PRIV_KU_LEN; + if (generate_Ku(session.securityAuthProto, + session.securityAuthProtoLen, + (u_char *)priv_pass, STRLEN(priv_pass), + session.securityPrivKey, + &session.securityPrivKeyLen) != SNMPERR_SUCCESS) { + if (verbose) + printf("error:v3_session: couldn't gen Ku from priv pass phrase.\n"); + goto end; + } + } + + ss = snmp_sess_open(&session); + + end: + if (ss == NULL) { + if (verbose) + printf("error:v3_session: couldn't open SNMP session(%s).\n", + snmp_api_errstring(snmp_errno)); + } + free (session.securityEngineID); + free (session.contextEngineID); + + return PyLong_FromVoidPtr((void *)ss); +} + +static PyObject * +netsnmp_create_session_tunneled(PyObject *self, PyObject *args) +{ + int version; + char *peer; + int lport; + int retries; + int timeout; + char * sec_name; + int sec_level; + char * context_eng_id; + char * context; + char * our_identity; + char * their_identity; + char * their_hostname; + char * trust_cert; + SnmpSession session = {0}; + SnmpSession *ss = NULL; + int verbose = py_netsnmp_verbose(); + + if (!PyArg_ParseTuple(args, "isiiisissssss", &version, + &peer, &lport, &retries, &timeout, + &sec_name, &sec_level, + &context_eng_id, &context, + &our_identity, &their_identity, + &their_hostname, &trust_cert)) + return NULL; + + __libraries_init("python"); + snmp_sess_init(&session); + + if (version != 3) { + session.version = SNMP_VERSION_3; + if (verbose) + printf("Using version 3 as it's the only version that supports tunneling\n"); + } + + session.peername = peer; + session.retries = retries; /* 5 */ + session.timeout = timeout; /* 1000000L */ + session.contextNameLen = STRLEN(context); + session.contextName = context; + session.securityNameLen = STRLEN(sec_name); + session.securityName = sec_name; + session.securityLevel = sec_level; + session.securityModel = NETSNMP_TSM_SECURITY_MODEL; + + /* create the transport configuration store */ + if (!session.transport_configuration) { + netsnmp_container_init_list(); + session.transport_configuration = + netsnmp_container_find("transport_configuration:fifo"); + if (!session.transport_configuration) { + fprintf(stderr, "failed to initialize the transport configuration container\n"); + return NULL; + } + + session.transport_configuration->compare = + (netsnmp_container_compare*) + netsnmp_transport_config_compare; + } + + if (our_identity && our_identity[0] != '\0') + CONTAINER_INSERT(session.transport_configuration, + netsnmp_transport_create_config("localCert", + our_identity)); + + if (their_identity && their_identity[0] != '\0') + CONTAINER_INSERT(session.transport_configuration, + netsnmp_transport_create_config("peerCert", + their_identity)); + + if (their_hostname && their_hostname[0] != '\0') + CONTAINER_INSERT(session.transport_configuration, + netsnmp_transport_create_config("their_hostname", + their_hostname)); + + if (trust_cert && trust_cert[0] != '\0') + CONTAINER_INSERT(session.transport_configuration, + netsnmp_transport_create_config("trust_cert", + trust_cert)); + + ss = snmp_sess_open(&session); + + if (!ss) + return NULL; + /* + * Note: on a 64-bit system the statement below discards the upper 32 bits of + * "ss", which is most likely a bug. + */ + return Py_BuildValue("i", (int)(uintptr_t)ss); +} + +static PyObject * +netsnmp_delete_session(PyObject *self, PyObject *args) +{ + PyObject *session; + SnmpSession *ss = NULL; + + if (!PyArg_ParseTuple(args, "O", &session)) { + return NULL; + } + + ss = (SnmpSession *)py_netsnmp_attr_void_ptr(session, "sess_ptr"); + + snmp_sess_close(ss); + return (Py_BuildValue("")); +} + + +static PyObject * +netsnmp_get(PyObject *self, PyObject *args) +{ + PyObject *session; + PyObject *varlist; + PyObject *varbind; + PyObject *val_tuple = NULL; + int varlist_len = 0; + int varlist_ind; + netsnmp_session *ss; + netsnmp_pdu *pdu, *response; + netsnmp_variable_list *vars; + struct tree *tp; + int len; + oid *oid_arr; + int oid_arr_len = MAX_OID_LEN; + int type; + char type_str[MAX_TYPE_NAME_LEN]; + u_char str_buf[STR_BUF_SIZE], *str_bufp = str_buf; + size_t str_buf_len = sizeof(str_buf); + size_t out_len = 0; + int buf_over = 0; + char *tag; + char *iid; + int getlabel_flag = NO_FLAGS; + int sprintval_flag = USE_BASIC; + int verbose = py_netsnmp_verbose(); + int old_format; + int best_guess; + int retry_nosuch; + int err_ind; + int err_num; + char err_str[STR_BUF_SIZE]; + char *tmpstr; + Py_ssize_t tmplen; + + oid_arr = calloc(MAX_OID_LEN, sizeof(oid)); + + if (oid_arr && args) { + + if (!PyArg_ParseTuple(args, "OO", &session, &varlist)) { + goto done; + } + + ss = (SnmpSession *)py_netsnmp_attr_void_ptr(session, "sess_ptr"); + + if (py_netsnmp_attr_string(session, "ErrorStr", &tmpstr, &tmplen) < 0) { + goto done; + } + + if (py_netsnmp_attr_long(session, "UseLongNames")) + getlabel_flag |= USE_LONG_NAMES; + if (py_netsnmp_attr_long(session, "UseNumeric")) + getlabel_flag |= USE_NUMERIC_OIDS; + if (py_netsnmp_attr_long(session, "UseEnums")) + sprintval_flag = USE_ENUMS; + if (py_netsnmp_attr_long(session, "UseSprintValue")) + sprintval_flag = USE_SPRINT_VALUE; + best_guess = py_netsnmp_attr_long(session, "BestGuess"); + retry_nosuch = py_netsnmp_attr_long(session, "RetryNoSuch"); + + pdu = snmp_pdu_create(SNMP_MSG_GET); + + if (varlist) { + PyObject *varlist_iter = PyObject_GetIter(varlist); + + while (varlist_iter && (varbind = PyIter_Next(varlist_iter))) { + if (py_netsnmp_attr_string(varbind, "tag", &tag, NULL) < 0 || + py_netsnmp_attr_string(varbind, "iid", &iid, NULL) < 0) + { + oid_arr_len = 0; + } else { + tp = __tag2oid(tag, iid, oid_arr, &oid_arr_len, NULL, best_guess); + } + + if (oid_arr_len) { + snmp_add_null_var(pdu, oid_arr, oid_arr_len); + varlist_len++; + } else { + if (verbose) + printf("error: get: unknown object ID (%s)", + (tag ? tag : "<null>")); + snmp_free_pdu(pdu); + goto done; + } + /* release reference when done */ + Py_DECREF(varbind); + } + + Py_DECREF(varlist_iter); + + if (PyErr_Occurred()) { + /* propagate error */ + if (verbose) + printf("error: get: unknown python error"); + snmp_free_pdu(pdu); + goto done; + } + } + + __send_sync_pdu(ss, pdu, &response, retry_nosuch, err_str, &err_num, + &err_ind); + __py_netsnmp_update_session_errors(session, err_str, err_num, err_ind); + + /* + ** Set up for numeric or full OID's, if necessary. Save the old + ** output format so that it can be restored when we finish -- this + ** is a library-wide global, and has to be set/restored for each + ** session. + */ + old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT); + + if (py_netsnmp_attr_long(session, "UseLongNames")) { + getlabel_flag |= USE_LONG_NAMES; + + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_FULL); + } + /* Setting UseNumeric forces UseLongNames on so check for UseNumeric + after UseLongNames (above) to make sure the final outcome of + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT is NETSNMP_OID_OUTPUT_NUMERIC */ + if (py_netsnmp_attr_long(session, "UseNumeric")) { + getlabel_flag |= USE_LONG_NAMES; + getlabel_flag |= USE_NUMERIC_OIDS; + + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_NUMERIC); + } + + val_tuple = PyTuple_New(varlist_len); + /* initialize return tuple */ + for (varlist_ind = 0; varlist_ind < varlist_len; varlist_ind++) { + PyTuple_SetItem(val_tuple, varlist_ind, Py_BuildValue("")); + } + + for(vars = (response ? response->variables : NULL), varlist_ind = 0; + vars && (varlist_ind < varlist_len); + vars = vars->next_variable, varlist_ind++) { + + varbind = PySequence_GetItem(varlist, varlist_ind); + + if (PyObject_HasAttrString(varbind, "tag")) { + *str_buf = '.'; + *(str_buf+1) = '\0'; + out_len = 0; + tp = netsnmp_sprint_realloc_objid_tree(&str_bufp, &str_buf_len, + &out_len, 0, &buf_over, + vars->name,vars->name_length); + if (_debug_level) + printf("netsnmp_get:str_bufp:%s:%d:%d\n", str_bufp, + (int)str_buf_len, (int)out_len); + + str_buf[sizeof(str_buf)-1] = '\0'; + + if (__is_leaf(tp)) { + type = (tp->type ? tp->type : tp->parent->type); + getlabel_flag &= ~NON_LEAF_NAME; + if (_debug_level) printf("netsnmp_get:is_leaf:%d\n",type); + } else { + getlabel_flag |= NON_LEAF_NAME; + type = __translate_asn_type(vars->type); + if (_debug_level) printf("netsnmp_get:!is_leaf:%d\n",tp->type); + } + + if (_debug_level) printf("netsnmp_get:str_buf:%s\n",str_buf); + + __get_label_iid((char *) str_buf, &tag, &iid, getlabel_flag); + + py_netsnmp_attr_set_string(varbind, "tag", tag, STRLEN(tag)); + py_netsnmp_attr_set_string(varbind, "iid", iid, STRLEN(iid)); + + __get_type_str(type, type_str); + + py_netsnmp_attr_set_string(varbind, "type", type_str, strlen(type_str)); + + len = __snprint_value((char *) str_buf, sizeof(str_buf), + vars, tp, type, sprintval_flag); + str_buf[len] = '\0'; + py_netsnmp_attr_set_string(varbind, "val", (char *) str_buf, len); + + /* save in return tuple as well */ + PyTuple_SetItem(val_tuple, varlist_ind, + (len ? Py_BuildValue("s#", str_buf, len) : + Py_BuildValue(""))); + + Py_DECREF(varbind); + } else { + printf("netsnmp_get: bad varbind (%d)\n", varlist_ind); + } + } + + /* Reset the library's behavior for numeric/symbolic OID's. */ + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + old_format); + + if (response) snmp_free_pdu(response); + } + + done: + SAFE_FREE(oid_arr); + return (val_tuple ? val_tuple : Py_BuildValue("")); +} + +static PyObject * +netsnmp_getnext(PyObject *self, PyObject *args) +{ + PyObject *session; + PyObject *varlist; + PyObject *varbind; + PyObject *val_tuple = NULL; + int varlist_len = 0; + int varlist_ind; + netsnmp_session *ss; + netsnmp_pdu *pdu, *response; + netsnmp_variable_list *vars; + struct tree *tp; + int len; + oid *oid_arr; + int oid_arr_len = MAX_OID_LEN; + int type; + char type_str[MAX_TYPE_NAME_LEN]; + u_char str_buf[STR_BUF_SIZE], *str_bufp = str_buf; + size_t str_buf_len = sizeof(str_buf); + size_t out_len = 0; + int buf_over = 0; + char *tag; + char *iid = NULL; + int getlabel_flag = NO_FLAGS; + int sprintval_flag = USE_BASIC; + int verbose = py_netsnmp_verbose(); + int old_format; + int best_guess; + int retry_nosuch; + int err_ind; + int err_num; + char err_str[STR_BUF_SIZE]; + char *tmpstr; + Py_ssize_t tmplen; + + oid_arr = calloc(MAX_OID_LEN, sizeof(oid)); + + if (oid_arr && args) { + + if (!PyArg_ParseTuple(args, "OO", &session, &varlist)) { + goto done; + } + + ss = (SnmpSession *)py_netsnmp_attr_void_ptr(session, "sess_ptr"); + + if (py_netsnmp_attr_string(session, "ErrorStr", &tmpstr, &tmplen) < 0) { + goto done; + } + memcpy(&err_str, tmpstr, tmplen); + err_num = py_netsnmp_attr_long(session, "ErrorNum"); + err_ind = py_netsnmp_attr_long(session, "ErrorInd"); + + if (py_netsnmp_attr_long(session, "UseLongNames")) + getlabel_flag |= USE_LONG_NAMES; + if (py_netsnmp_attr_long(session, "UseNumeric")) + getlabel_flag |= USE_NUMERIC_OIDS; + if (py_netsnmp_attr_long(session, "UseEnums")) + sprintval_flag = USE_ENUMS; + if (py_netsnmp_attr_long(session, "UseSprintValue")) + sprintval_flag = USE_SPRINT_VALUE; + best_guess = py_netsnmp_attr_long(session, "BestGuess"); + retry_nosuch = py_netsnmp_attr_long(session, "RetryNoSuch"); + + pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); + + if (varlist) { + PyObject *varlist_iter = PyObject_GetIter(varlist); + + while (varlist_iter && (varbind = PyIter_Next(varlist_iter))) { + if (py_netsnmp_attr_string(varbind, "tag", &tag, NULL) < 0 || + py_netsnmp_attr_string(varbind, "iid", &iid, NULL) < 0) + { + oid_arr_len = 0; + } else { + tp = __tag2oid(tag, iid, oid_arr, &oid_arr_len, NULL, best_guess); + } + + if (_debug_level) + printf("netsnmp_getnext: filling request: %s:%s:%d:%d\n", + tag, iid, oid_arr_len,best_guess); + + if (oid_arr_len) { + snmp_add_null_var(pdu, oid_arr, oid_arr_len); + varlist_len++; + } else { + if (verbose) + printf("error: get: unknown object ID (%s)", + (tag ? tag : "<null>")); + snmp_free_pdu(pdu); + goto done; + } + /* release reference when done */ + Py_DECREF(varbind); + } + + Py_DECREF(varlist_iter); + + if (PyErr_Occurred()) { + /* propagate error */ + if (verbose) + printf("error: get: unknown python error"); + snmp_free_pdu(pdu); + goto done; + } + } + + __send_sync_pdu(ss, pdu, &response, retry_nosuch, err_str, &err_num, + &err_ind); + __py_netsnmp_update_session_errors(session, err_str, err_num, err_ind); + + /* + ** Set up for numeric or full OID's, if necessary. Save the old + ** output format so that it can be restored when we finish -- this + ** is a library-wide global, and has to be set/restored for each + ** session. + */ + old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT); + + if (py_netsnmp_attr_long(session, "UseLongNames")) { + getlabel_flag |= USE_LONG_NAMES; + + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_FULL); + } + /* Setting UseNumeric forces UseLongNames on so check for UseNumeric + after UseLongNames (above) to make sure the final outcome of + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT is NETSNMP_OID_OUTPUT_NUMERIC */ + if (py_netsnmp_attr_long(session, "UseNumeric")) { + getlabel_flag |= USE_LONG_NAMES; + getlabel_flag |= USE_NUMERIC_OIDS; + + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_NUMERIC); + } + + val_tuple = PyTuple_New(varlist_len); + /* initialize return tuple */ + val_tuple = PyTuple_New(varlist_len); + for (varlist_ind = 0; varlist_ind < varlist_len; varlist_ind++) { + PyTuple_SetItem(val_tuple, varlist_ind, Py_BuildValue("")); + } + + for(vars = (response ? response->variables : NULL), varlist_ind = 0; + vars && (varlist_ind < varlist_len); + vars = vars->next_variable, varlist_ind++) { + + varbind = PySequence_GetItem(varlist, varlist_ind); + + if (PyObject_HasAttrString(varbind, "tag")) { + *str_buf = '.'; + *(str_buf+1) = '\0'; + out_len = 0; + tp = netsnmp_sprint_realloc_objid_tree(&str_bufp, &str_buf_len, + &out_len, 0, &buf_over, + vars->name,vars->name_length); + str_buf[sizeof(str_buf)-1] = '\0'; + + if (__is_leaf(tp)) { + type = (tp->type ? tp->type : tp->parent->type); + getlabel_flag &= ~NON_LEAF_NAME; + } else { + getlabel_flag |= NON_LEAF_NAME; + type = __translate_asn_type(vars->type); + } + + __get_label_iid((char *) str_buf, &tag, &iid, getlabel_flag); + + if (_debug_level) + printf("netsnmp_getnext: filling response: %s:%s\n", tag, iid); + + py_netsnmp_attr_set_string(varbind, "tag", tag, STRLEN(tag)); + py_netsnmp_attr_set_string(varbind, "iid", iid, STRLEN(iid)); + + __get_type_str(type, type_str); + + py_netsnmp_attr_set_string(varbind, "type", type_str, + strlen(type_str)); + + len = __snprint_value((char *) str_buf, sizeof(str_buf), + vars, tp, type, sprintval_flag); + str_buf[len] = '\0'; + + py_netsnmp_attr_set_string(varbind, "val", (char *) str_buf, len); + + /* save in return tuple as well */ + PyTuple_SetItem(val_tuple, varlist_ind, + (len ? Py_BuildValue("s#", str_buf, len) : + Py_BuildValue(""))); + + Py_DECREF(varbind); + } else { + printf("netsnmp_getnext: bad varbind (%d)\n", varlist_ind); + } + } + + /* Reset the library's behavior for numeric/symbolic OID's. */ + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + old_format); + + if (response) snmp_free_pdu(response); + } + + done: + SAFE_FREE(oid_arr); + return (val_tuple ? val_tuple : Py_BuildValue("")); +} + +static PyObject * +netsnmp_walk(PyObject *self, PyObject *args) +{ + PyObject *session; + PyObject *varlist; + PyObject *varlist_iter; + PyObject *varbind; + PyObject *val_tuple = NULL; + PyObject *varbinds = NULL; + int varlist_len = 0; + int varlist_ind; + netsnmp_session *ss; + netsnmp_pdu *pdu, *response; + netsnmp_pdu *newpdu; + netsnmp_variable_list *vars, *oldvars; + struct tree *tp; + int len; + oid **oid_arr = NULL; + int *oid_arr_len = NULL; + oid **oid_arr_broken_check = NULL; + int *oid_arr_broken_check_len = NULL; + int type; + char type_str[MAX_TYPE_NAME_LEN]; + int status; + u_char str_buf[STR_BUF_SIZE], *str_bufp = str_buf; + size_t str_buf_len = sizeof(str_buf); + size_t out_len = 0; + int buf_over = 0; + char *tag; + char *iid = NULL; + int getlabel_flag = NO_FLAGS; + int sprintval_flag = USE_BASIC; + int verbose = py_netsnmp_verbose(); + int old_format; + int best_guess; + int retry_nosuch; + int err_ind; + int err_num; + char err_str[STR_BUF_SIZE]; + int notdone = 1; + int result_count = 0; + char *tmpstr; + Py_ssize_t tmplen; + + if (args) { + + if (!PyArg_ParseTuple(args, "OO", &session, &varlist)) { + goto done; + } + + if (!varlist) { + goto done; + } + + if ((varbinds = PyObject_GetAttrString(varlist, "varbinds")) == NULL) { + goto done; + } + ss = (SnmpSession *)py_netsnmp_attr_void_ptr(session, "sess_ptr"); + + if (py_netsnmp_attr_string(session, "ErrorStr", &tmpstr, &tmplen) < 0) { + goto done; + } + memcpy(&err_str, tmpstr, tmplen); + err_num = py_netsnmp_attr_long(session, "ErrorNum"); + err_ind = py_netsnmp_attr_long(session, "ErrorInd"); + + if (py_netsnmp_attr_long(session, "UseLongNames")) + getlabel_flag |= USE_LONG_NAMES; + if (py_netsnmp_attr_long(session, "UseNumeric")) + getlabel_flag |= USE_NUMERIC_OIDS; + if (py_netsnmp_attr_long(session, "UseEnums")) + sprintval_flag = USE_ENUMS; + if (py_netsnmp_attr_long(session, "UseSprintValue")) + sprintval_flag = USE_SPRINT_VALUE; + best_guess = py_netsnmp_attr_long(session, "BestGuess"); + retry_nosuch = py_netsnmp_attr_long(session, "RetryNoSuch"); + + pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); + + /* we need an initial count for memory allocation */ + varlist_iter = PyObject_GetIter(varlist); + varlist_len = 0; + while (varlist_iter && (varbind = PyIter_Next(varlist_iter))) { + varlist_len++; + } + Py_DECREF(varlist_iter); + + oid_arr_len = calloc(varlist_len, sizeof(int)); + oid_arr_broken_check_len = calloc(varlist_len, sizeof(int)); + + oid_arr = calloc(varlist_len, sizeof(oid *)); + oid_arr_broken_check = calloc(varlist_len, sizeof(oid *)); + + for(varlist_ind = 0; varlist_ind < varlist_len; varlist_ind++) { + + oid_arr[varlist_ind] = calloc(MAX_OID_LEN, sizeof(oid)); + oid_arr_broken_check[varlist_ind] = calloc(MAX_OID_LEN, sizeof(oid)); + + oid_arr_len[varlist_ind] = MAX_OID_LEN; + oid_arr_broken_check_len[varlist_ind] = MAX_OID_LEN; + } + + /* get the initial starting oids*/ + varlist_iter = PyObject_GetIter(varlist); + varlist_ind = 0; + while (varlist_iter && (varbind = PyIter_Next(varlist_iter))) { + + if (py_netsnmp_attr_string(varbind, "tag", &tag, NULL) < 0 || + py_netsnmp_attr_string(varbind, "iid", &iid, NULL) < 0) + { + oid_arr_len[varlist_ind] = 0; + } else { + tp = __tag2oid(tag, iid, + oid_arr[varlist_ind], &oid_arr_len[varlist_ind], + NULL, best_guess); + } + + if (_debug_level) + printf("netsnmp_walk: filling request: %s:%s:%d:%d\n", + tag, iid, oid_arr_len[varlist_ind],best_guess); + + if (oid_arr_len[varlist_ind]) { + snmp_add_null_var(pdu, oid_arr[varlist_ind], oid_arr_len[varlist_ind]); + } else { + if (verbose) + printf("error: walk: unknown object ID (%s)", + (tag ? tag : "<null>")); + snmp_free_pdu(pdu); + goto done; + } + /* release reference when done */ + Py_DECREF(varbind); + varlist_ind++; + } + + if (varlist_iter) + Py_DECREF(varlist_iter); + + if (PyErr_Occurred()) { + /* propagate error */ + if (verbose) + printf("error: walk: unknown python error (varlist)"); + snmp_free_pdu(pdu); + goto done; + } + + /* pre-allocate the return tuples */ + val_tuple = PyTuple_New(0); + + if (!val_tuple) { + /* propagate error */ + if (verbose) + printf("error: walk: couldn't allocate a new value tuple"); + snmp_free_pdu(pdu); + goto done; + } + + /* + ** Set up for numeric or full OID's, if necessary. Save the old + ** output format so that it can be restored when we finish -- this + ** is a library-wide global, and has to be set/restored for each + ** session. + */ + old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT); + + if (py_netsnmp_attr_long(session, "UseLongNames")) { + getlabel_flag |= USE_LONG_NAMES; + + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_FULL); + } + + /* Setting UseNumeric forces UseLongNames on so check for UseNumeric + after UseLongNames (above) to make sure the final outcome of + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT is NETSNMP_OID_OUTPUT_NUMERIC */ + if (py_netsnmp_attr_long(session, "UseNumeric")) { + getlabel_flag |= USE_LONG_NAMES; + getlabel_flag |= USE_NUMERIC_OIDS; + + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_NUMERIC); + } + + /* delete the existing varbinds that we'll replace */ + PySequence_DelSlice(varbinds, 0, PySequence_Length(varbinds)); + + if (PyErr_Occurred()) { + /* propagate error */ + if (verbose) + printf("error: walk: deleting old varbinds failed\n"); + snmp_free_pdu(pdu); + goto done; + } + + /* save the starting OID */ + + for(vars = pdu->variables, varlist_ind = 0; + vars != NULL; + vars = vars->next_variable, varlist_ind++) { + + oid_arr_broken_check[varlist_ind] = calloc(MAX_OID_LEN, sizeof(oid)); + + oid_arr_broken_check_len[varlist_ind] = vars->name_length; + memcpy(oid_arr_broken_check[varlist_ind], + vars->name, vars->name_length * sizeof(oid)); + } + + while(notdone) { + + status = __send_sync_pdu(ss, pdu, &response, retry_nosuch, + err_str, &err_num, &err_ind); + __py_netsnmp_update_session_errors(session, err_str, err_num, err_ind); + + if (!response || !response->variables || + status != STAT_SUCCESS || + response->errstat != SNMP_ERR_NOERROR) { + notdone = 0; + } else { + newpdu = snmp_pdu_create(SNMP_MSG_GETNEXT); + + for(vars = (response ? response->variables : NULL), + varlist_ind = 0, + oldvars = (pdu ? pdu->variables : NULL); + vars && (varlist_ind < varlist_len); + vars = vars->next_variable, varlist_ind++, + oldvars = (oldvars ? oldvars->next_variable : NULL)) { + + if ((vars->name_length < oid_arr_len[varlist_ind]) || + (memcmp(oid_arr[varlist_ind], vars->name, + oid_arr_len[varlist_ind] * sizeof(oid)) != 0)) { + notdone = 0; + break; + } + + if ((vars->type == SNMP_ENDOFMIBVIEW) || + (vars->type == SNMP_NOSUCHOBJECT) || + (vars->type == SNMP_NOSUCHINSTANCE)) { + notdone = 0; + break; + } + + if (snmp_oid_compare(vars->name, vars->name_length, + oid_arr_broken_check[varlist_ind], + oid_arr_broken_check_len[varlist_ind]) <= 0) { + /* The agent responded with an illegal response + as the returning OID was lexogragically less + then or equal to the requested OID... + We need to give up here because an infite + loop will result otherwise. + + XXX: this really should be an option to + continue like the -Cc option to the snmpwalk + application. + */ + notdone = 0; + break; + } + + varbind = py_netsnmp_construct_varbind(); + + if (PyObject_HasAttrString(varbind, "tag")) { + str_buf[0] = '.'; + str_buf[1] = '\0'; + out_len = 0; + tp = netsnmp_sprint_realloc_objid_tree(&str_bufp, &str_buf_len, + &out_len, 0, &buf_over, + vars->name,vars->name_length); + str_buf[sizeof(str_buf)-1] = '\0'; + + if (__is_leaf(tp)) { + type = (tp->type ? tp->type : tp->parent->type); + getlabel_flag &= ~NON_LEAF_NAME; + } else { + getlabel_flag |= NON_LEAF_NAME; + type = __translate_asn_type(vars->type); + } + + __get_label_iid((char *) str_buf, &tag, &iid, getlabel_flag); + + if (_debug_level) printf("netsnmp_walk: filling response: %s:%s\n", tag, iid); + + py_netsnmp_attr_set_string(varbind, "tag", tag, STRLEN(tag)); + py_netsnmp_attr_set_string(varbind, "iid", iid, STRLEN(iid)); + + __get_type_str(type, type_str); + + py_netsnmp_attr_set_string(varbind, "type", type_str, + strlen(type_str)); + + len = __snprint_value((char *) str_buf,sizeof(str_buf), + vars,tp,type,sprintval_flag); + str_buf[len] = '\0'; + + py_netsnmp_attr_set_string(varbind, "val", (char *) str_buf, + len); + + /* push the varbind onto the return varbinds */ + PyList_Append(varbinds, varbind); + + /* save in return tuple as well */ + /* save in return tuple as well - steals ref */ + _PyTuple_Resize(&val_tuple, result_count+1); + PyTuple_SetItem(val_tuple, result_count++, + (len ? Py_BuildValue("s#", str_buf, len) : + Py_BuildValue(""))); + + + } else { + /* Return None for this variable. */ + _PyTuple_Resize(&val_tuple, result_count+1); + PyTuple_SetItem(val_tuple, result_count++, Py_BuildValue("")); + printf("netsnmp_walk: bad varbind (%d)\n", varlist_ind); + } + Py_XDECREF(varbind); + + memcpy(oid_arr_broken_check[varlist_ind], vars->name, + sizeof(oid) * vars->name_length); + oid_arr_broken_check_len[varlist_ind] = vars->name_length; + + snmp_add_null_var(newpdu, vars->name, + vars->name_length); + } + pdu = newpdu; + } + if (response) + snmp_free_pdu(response); + } + + /* Reset the library's behavior for numeric/symbolic OID's. */ + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + old_format); + + + if (PyErr_Occurred()) { + /* propagate error */ + if (verbose) + printf("error: walk response processing: unknown python error"); + Py_DECREF(val_tuple); + } + } + + done: + Py_XDECREF(varbinds); + SAFE_FREE(oid_arr_len); + SAFE_FREE(oid_arr_broken_check_len); + for(varlist_ind = 0; varlist_ind < varlist_len; varlist_ind ++) { + SAFE_FREE(oid_arr[varlist_ind]); + SAFE_FREE(oid_arr_broken_check[varlist_ind]); + } + SAFE_FREE(oid_arr); + SAFE_FREE(oid_arr_broken_check); + return (val_tuple ? val_tuple : Py_BuildValue("")); +} + + +static PyObject * +netsnmp_getbulk(PyObject *self, PyObject *args) +{ + int nonrepeaters; + int maxrepetitions; + PyObject *session; + PyObject *varlist; + PyObject *varbinds; + PyObject *varbind; + PyObject *varbinds_iter; + PyObject *val_tuple = NULL; + int varbind_ind; + netsnmp_session *ss; + netsnmp_pdu *pdu, *response; + netsnmp_variable_list *vars; + struct tree *tp; + int len; + oid *oid_arr; + int oid_arr_len = MAX_OID_LEN; + int type; + char type_str[MAX_TYPE_NAME_LEN]; + u_char str_buf[STR_BUF_SIZE], *str_bufp = str_buf; + size_t str_buf_len = sizeof(str_buf); + size_t out_len = 0; + int buf_over = 0; + char *tag; + char *iid; + int getlabel_flag = NO_FLAGS; + int sprintval_flag = USE_BASIC; + int verbose = py_netsnmp_verbose(); + int old_format; + int best_guess; + int retry_nosuch; + int err_ind; + int err_num; + char err_str[STR_BUF_SIZE]; + char *tmpstr; + Py_ssize_t tmplen; + + oid_arr = calloc(MAX_OID_LEN, sizeof(oid)); + + if (oid_arr && args) { + + if (!PyArg_ParseTuple(args, "OiiO", &session, &nonrepeaters, + &maxrepetitions, &varlist)) { + goto done; + } + + if (varlist && (varbinds = PyObject_GetAttrString(varlist, "varbinds"))) { + + ss = (SnmpSession *)py_netsnmp_attr_void_ptr(session, "sess_ptr"); + + if (py_netsnmp_attr_string(session, "ErrorStr", &tmpstr, &tmplen) < 0) { + goto done; + } + memcpy(&err_str, tmpstr, tmplen); + err_num = py_netsnmp_attr_long(session, "ErrorNum"); + err_ind = py_netsnmp_attr_long(session, "ErrorInd"); + + if (py_netsnmp_attr_long(session, "UseLongNames")) + getlabel_flag |= USE_LONG_NAMES; + if (py_netsnmp_attr_long(session, "UseNumeric")) + getlabel_flag |= USE_NUMERIC_OIDS; + if (py_netsnmp_attr_long(session, "UseEnums")) + sprintval_flag = USE_ENUMS; + if (py_netsnmp_attr_long(session, "UseSprintValue")) + sprintval_flag = USE_SPRINT_VALUE; + best_guess = py_netsnmp_attr_long(session, "BestGuess"); + retry_nosuch = py_netsnmp_attr_long(session, "RetryNoSuch"); + + pdu = snmp_pdu_create(SNMP_MSG_GETBULK); + + pdu->errstat = nonrepeaters; + pdu->errindex = maxrepetitions; + + varbinds_iter = PyObject_GetIter(varbinds); + + while (varbinds_iter && (varbind = PyIter_Next(varbinds_iter))) { + if (py_netsnmp_attr_string(varbind, "tag", &tag, NULL) < 0 || + py_netsnmp_attr_string(varbind, "iid", &iid, NULL) < 0) + { + oid_arr_len = 0; + } else { + tp = __tag2oid(tag, iid, oid_arr, &oid_arr_len, NULL, best_guess); + } + + if (oid_arr_len) { + snmp_add_null_var(pdu, oid_arr, oid_arr_len); + } else { + if (verbose) + printf("error: get: unknown object ID (%s)", + (tag ? tag : "<null>")); + snmp_free_pdu(pdu); + goto done; + } + /* release reference when done */ + Py_DECREF(varbind); + } + + Py_DECREF(varbinds_iter); + + if (PyErr_Occurred()) { + /* propagate error */ + if (verbose) + printf("error: get: unknown python error"); + snmp_free_pdu(pdu); + goto done; + } + + __send_sync_pdu(ss, pdu, &response, retry_nosuch, err_str, &err_num, + &err_ind); + __py_netsnmp_update_session_errors(session, err_str, err_num, err_ind); + + /* + ** Set up for numeric or full OID's, if necessary. Save the old + ** output format so that it can be restored when we finish -- this + ** is a library-wide global, and has to be set/restored for each + ** session. + */ + old_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT); + + if (py_netsnmp_attr_long(session, "UseLongNames")) { + getlabel_flag |= USE_LONG_NAMES; + + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_FULL); + } + /* Setting UseNumeric forces UseLongNames on so check for UseNumeric + after UseLongNames (above) to make sure the final outcome of + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT is NETSNMP_OID_OUTPUT_NUMERIC */ + if (py_netsnmp_attr_long(session, "UseNumeric")) { + getlabel_flag |= USE_LONG_NAMES; + getlabel_flag |= USE_NUMERIC_OIDS; + + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_NUMERIC); + } + + /* create tuple in which to return results */ + val_tuple = PyTuple_New(0); + + if(response && response->variables) { + /* clear varlist to receive response varbinds*/ + PySequence_DelSlice(varbinds, 0, PySequence_Length(varbinds)); + + if (PyErr_Occurred()) { + /* propagate error */ + if (verbose) + printf("error: bulk: deleting old varbinds failed\n"); + snmp_free_pdu(pdu); + goto done; + } + + for(vars = response->variables, varbind_ind=0; + vars; + vars = vars->next_variable, varbind_ind++) { + + varbind = py_netsnmp_construct_varbind(); + + if (PyObject_HasAttrString(varbind, "tag")) { + *str_buf = '.'; + *(str_buf+1) = '\0'; + out_len = 0; + buf_over = 0; + str_bufp = str_buf; + tp = netsnmp_sprint_realloc_objid_tree(&str_bufp, &str_buf_len, + &out_len, 0, &buf_over, + vars->name,vars->name_length); + str_buf[sizeof(str_buf)-1] = '\0'; + if (__is_leaf(tp)) { + type = (tp->type ? tp->type : tp->parent->type); + getlabel_flag &= ~NON_LEAF_NAME; + } else { + getlabel_flag |= NON_LEAF_NAME; + type = __translate_asn_type(vars->type); + } + + __get_label_iid((char *) str_buf, &tag, &iid, getlabel_flag); + + py_netsnmp_attr_set_string(varbind, "tag", tag, STRLEN(tag)); + py_netsnmp_attr_set_string(varbind, "iid", iid, STRLEN(iid)); + + __get_type_str(type, type_str); + + py_netsnmp_attr_set_string(varbind, "type", type_str, + strlen(type_str)); + + len = __snprint_value((char *) str_buf, sizeof(str_buf), + vars, tp, type, sprintval_flag); + str_buf[len] = '\0'; + + py_netsnmp_attr_set_string(varbind, "val", (char *) str_buf, len); + + /* push varbind onto varbinds */ + PyList_Append(varbinds, varbind); + + /* save in return tuple as well - steals ref */ + _PyTuple_Resize(&val_tuple, varbind_ind+1); + PyTuple_SetItem(val_tuple, varbind_ind, + Py_BuildValue("s#", str_buf, len)); + + Py_DECREF(varbind); + + } else { + PyObject *none = Py_BuildValue(""); /* new ref */ + /* not sure why making vabind failed - should not happen*/ + PyList_Append(varbinds, none); /* increments ref */ + /* Return None for this variable. */ + PyTuple_SetItem(val_tuple, varbind_ind, none); /* steals ref */ + } + } + } + + /* Reset the library's behavior for numeric/symbolic OID's. */ + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + old_format); + + if (response) snmp_free_pdu(response); + + Py_DECREF(varbinds); + + } + + if (PyErr_Occurred()) { + /* propagate error */ + if (verbose) + printf("error: getbulk response processing: unknown python error"); + if (val_tuple) + Py_DECREF(val_tuple); + val_tuple = NULL; + } + } + + done: + SAFE_FREE(oid_arr); + return (val_tuple ? val_tuple : Py_BuildValue("")); +} + +static PyObject * +netsnmp_set(PyObject *self, PyObject *args) +{ + PyObject *session; + PyObject *varlist; + PyObject *varbind; + PyObject *ret = NULL; + netsnmp_session *ss; + netsnmp_pdu *pdu, *response; + struct tree *tp; + char *tag; + char *iid; + char *val; + char *type_str; + int len; + oid *oid_arr; + int oid_arr_len = MAX_OID_LEN; + int type; + u_char tmp_val_str[STR_BUF_SIZE]; + int use_enums; + struct enum_list *ep; + int verbose = py_netsnmp_verbose(); + int best_guess; + int status; + int err_ind; + int err_num; + char err_str[STR_BUF_SIZE]; + char *tmpstr; + Py_ssize_t tmplen; + + oid_arr = calloc(MAX_OID_LEN, sizeof(oid)); + + if (oid_arr && args) { + + if (!PyArg_ParseTuple(args, "OO", &session, &varlist)) { + goto done; + } + + ss = (SnmpSession *)py_netsnmp_attr_void_ptr(session, "sess_ptr"); + + /* PyObject_SetAttrString(); */ + if (py_netsnmp_attr_string(session, "ErrorStr", &tmpstr, &tmplen) < 0) { + goto done; + } + + use_enums = py_netsnmp_attr_long(session, "UseEnums"); + + best_guess = py_netsnmp_attr_long(session, "BestGuess"); + + pdu = snmp_pdu_create(SNMP_MSG_SET); + + if (varlist) { + PyObject *varlist_iter = PyObject_GetIter(varlist); + + while (varlist_iter && (varbind = PyIter_Next(varlist_iter))) { + if (py_netsnmp_attr_string(varbind, "tag", &tag, NULL) < 0 || + py_netsnmp_attr_string(varbind, "iid", &iid, NULL) < 0) + { + oid_arr_len = 0; + } else { + tp = __tag2oid(tag, iid, oid_arr, &oid_arr_len, &type, best_guess); + } + + if (oid_arr_len==0) { + if (verbose) + printf("error: set: unknown object ID (%s)", + (tag?tag:"<null>")); + snmp_free_pdu(pdu); + goto done; + } + + if (type == TYPE_UNKNOWN) { + if (py_netsnmp_attr_string(varbind, "type", &type_str, NULL) < 0) { + snmp_free_pdu(pdu); + goto done; + } + type = __translate_appl_type(type_str); + if (type == TYPE_UNKNOWN) { + if (verbose) + printf("error: set: no type found for object"); + snmp_free_pdu(pdu); + goto done; + } + } + + if (py_netsnmp_attr_string(varbind, "val", &val, &tmplen) < 0) { + snmp_free_pdu(pdu); + goto done; + } + memset(tmp_val_str, 0, sizeof(tmp_val_str)); + if ( tmplen >= sizeof(tmp_val_str)) { + tmplen = sizeof(tmp_val_str)-1; + } + memcpy(tmp_val_str, val, tmplen); + if (type==TYPE_INTEGER && use_enums && tp && tp->enums) { + for(ep = tp->enums; ep; ep = ep->next) { + if (val && !strcmp(ep->label, val)) { + snprintf((char *) tmp_val_str, sizeof(tmp_val_str), "%d", + ep->value); + break; + } + } + } + len = (int)tmplen; + status = __add_var_val_str(pdu, oid_arr, oid_arr_len, + (char *) tmp_val_str, len, type); + + if (verbose && status == FAILURE) + printf("error: set: adding variable/value to PDU"); + + /* release reference when done */ + Py_DECREF(varbind); + } + + Py_DECREF(varlist_iter); + + if (PyErr_Occurred()) { + /* propagate error */ + if (verbose) + printf("error: set: unknown python error"); + snmp_free_pdu(pdu); + goto done; + } + } + + status = __send_sync_pdu(ss, pdu, &response, NO_RETRY_NOSUCH, + err_str, &err_num, &err_ind); + __py_netsnmp_update_session_errors(session, err_str, err_num, err_ind); + + if (response) snmp_free_pdu(response); + + if (status == STAT_SUCCESS) + ret = Py_BuildValue("i",1); /* success, return True */ + else + ret = Py_BuildValue("i",0); /* fail, return False */ + } + done: + SAFE_FREE(oid_arr); + return (ret ? ret : Py_BuildValue("")); +} + + +static PyMethodDef ClientMethods[] = { + {"session", netsnmp_create_session, METH_VARARGS, + "create a netsnmp session."}, + {"session_v3", netsnmp_create_session_v3, METH_VARARGS, + "create a netsnmp session."}, + {"session_tunneled", netsnmp_create_session_tunneled, METH_VARARGS, + "create a tunneled netsnmp session over tls, dtls or ssh."}, + {"delete_session", netsnmp_delete_session, METH_VARARGS, + "create a netsnmp session."}, + {"get", netsnmp_get, METH_VARARGS, + "perform an SNMP GET operation."}, + {"getnext", netsnmp_getnext, METH_VARARGS, + "perform an SNMP GETNEXT operation."}, + {"getbulk", netsnmp_getbulk, METH_VARARGS, + "perform an SNMP GETBULK operation."}, + {"set", netsnmp_set, METH_VARARGS, + "perform an SNMP SET operation."}, + {"walk", netsnmp_walk, METH_VARARGS, + "perform an SNMP WALK operation."}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +PyMODINIT_FUNC +initclient_intf(void) +{ + (void) Py_InitModule("client_intf", ClientMethods); +} + + + + + |