| #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 = (oid *)malloc(name_length * sizeof(oid)); |
| memcpy((char *)vars->name, (char *)name, name_length * sizeof(oid)); |
| vars->name_length = name_length; |
| switch (type) { |
| case TYPE_INTEGER: |
| case TYPE_INTEGER32: |
| vars->type = ASN_INTEGER; |
| vars->val.integer = 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 = 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 = 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; |
| { |
| in_addr_t addr; |
| |
| if (val) |
| addr = inet_addr(val); |
| else { |
| ret = FAILURE; |
| addr = 0; |
| } |
| vars->val.integer = netsnmp_memdup(&addr, sizeof(addr)); |
| vars->val_len = sizeof(addr); |
| } |
| 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_len *= sizeof(oid); |
| vars->val.objid = (oid *)malloc(vars->val_len); |
| memcpy((char *)vars->val.objid, (char *)oidbuf, vars->val_len); |
| } |
| 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(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: |
| |
| status = snmp_synch_response(ss, pdu, response); |
| |
| 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"); |
| |
| 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_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_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_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); |
| Py_DECREF(varbind); |
| 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); |
| Py_XDECREF(varbind); |
| } |
| } |
| |
| /* 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); |
| Py_DECREF(varbind); |
| 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); |
| Py_XDECREF(varbind); |
| } |
| } |
| |
| /* 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_variable_list *vars; |
| struct tree *tp; |
| int len; |
| oid *oid_arr; |
| int oid_arr_len; |
| 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; |
| |
| oid_arr = calloc(MAX_OID_LEN, sizeof(oid)); |
| |
| if (oid_arr && 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"); |
| |
| varlist_iter = PyObject_GetIter(varlist); |
| |
| pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); |
| |
| /* get the initial starting oids*/ |
| 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_walk: 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: walk: unknown object ID (%s)", |
| (tag ? tag : "<null>")); |
| snmp_free_pdu(pdu); |
| Py_DECREF(varbind); |
| goto done; |
| } |
| /* release reference when done */ |
| Py_DECREF(varbind); |
| } |
| |
| 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; |
| } |
| |
| 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 || |
| (response->variables->name_length < oid_arr_len) || |
| (memcmp(oid_arr, response->variables->name, |
| oid_arr_len * sizeof(oid))) || |
| status != STAT_SUCCESS || |
| response->errstat != SNMP_ERR_NOERROR) { |
| notdone = 0; |
| } else { |
| for(vars = (response ? response->variables : NULL), varlist_ind = 0; |
| vars && (varlist_ind < varlist_len); |
| vars = vars->next_variable, varlist_ind++) { |
| |
| if ((vars->type == SNMP_ENDOFMIBVIEW) || |
| (vars->type == SNMP_NOSUCHOBJECT) || |
| (vars->type == SNMP_NOSUCHINSTANCE)) { |
| 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); |
| } |
| /* reuse the response as the next pdu to send */ |
| pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); |
| snmp_add_null_var(pdu, response->variables->name, |
| response->variables->name_length); |
| } |
| 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); |
| 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); |
| Py_DECREF(varbind); |
| 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 */ |
| Py_XDECREF(varbind); |
| } |
| } |
| } |
| |
| /* 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; |
| } |
| 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: |
| Py_XDECREF(varbind); |
| 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."}, |
| {"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); |
| } |
| |
| |
| |
| |
| |