/* * RFC 1908: Coexistence between SNMPv1 and SNMPv2 * * These convert: * * V1 PDUs from an ** AGENT ** to V2 PDUs for an ** MANAGER ** * V2 PDUs from an ** MANAGER ** to V1 PDUs for an ** AGENT ** * * We will never convert V1 information from a manager into V2 PDUs. V1 * requests are always honored by V2 agents, and the responses will be * valid V1 responses. (I think. XXXXX) * */ int snmp_coexist_V2toV1(struct snmp_pdu *PDU) { /* Per 3.1.1: */ switch (PDU->command) { case SNMP_PDU_GET: case SNMP_PDU_GETNEXT: #if SNMP_PDU_SET case SNMP_PDU_SET: #endif return (1); break; case SNMP_PDU_GETBULK: PDU->non_repeaters = 0; PDU->max_repetitions = 0; PDU->command = SNMP_PDU_GETNEXT; return (1); break; default: snmplib_debug(2, "Unable to translate PDU %d to SNMPv1!\n", PDU->command); snmp_set_api_error(SNMPERR_PDU_TRANSLATION); return (0); } }
u_char * snmp_msg_Decode(u_char * Packet, int *PacketLenP, u_char * Community, int *CommLenP, int *Version, struct snmp_pdu * PDU) { u_char *bufp; u_char type; bufp = asn_parse_header(Packet, PacketLenP, &type); if (bufp == NULL) { snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Header)!\n"); ASN_PARSE_ERROR(NULL); } if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) { snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Header)!\n"); ASN_PARSE_ERROR(NULL); } bufp = asn_parse_int(bufp, PacketLenP, &type, (int *) Version, sizeof(*Version)); if (bufp == NULL) { snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Version)!\n"); ASN_PARSE_ERROR(NULL); } bufp = asn_parse_string(bufp, PacketLenP, &type, Community, CommLenP); if (bufp == NULL) { snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Community)!\n"); ASN_PARSE_ERROR(NULL); } Community[*CommLenP] = '\0'; if ((*Version != SNMP_VERSION_1) && (*Version != SNMP_VERSION_2)) { /* Don't know how to handle this one. */ snmplib_debug(4, "snmp_msg_Decode:Unable to parse Version %u\n", *Version); snmplib_debug(4, "snmp_msg_Decode:Continuing anyway\n"); } /* Now that we know the header, decode the PDU */ /* XXXXX -- More than one PDU? */ bufp = snmp_pdu_decode(bufp, PacketLenP, PDU); if (bufp == NULL) /* snmp_pdu_decode registered failure */ return (NULL); bufp = snmp_var_DecodeVarBind(bufp, PacketLenP, &(PDU->variables), *Version); if (bufp == NULL) /* snmp_var_DecodeVarBind registered failure */ return (NULL); return (u_char *) bufp; }
u_char * snmp_msg_Encode(u_char * Buffer, int *BufLenP, u_char * Community, int CommLen, int Version, struct snmp_pdu *PDU) { u_char *bufp, *tmp; u_char *PDUHeaderPtr, *VARHeaderPtr; u_char *PDUDataStart, *VARDataStart; u_char *MsgPtr; int FakeArg = 1024; snmplib_debug(4, "Buffer=%p BufLenP=%p, buflen=%d\n", Buffer, BufLenP, *BufLenP); /* Header for the entire thing, with a false, large length */ bufp = asn_build_header(Buffer, BufLenP, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), (*BufLenP)); if (bufp == NULL) { snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Header)!\n"); return (NULL); } MsgPtr = bufp; /* Version */ bufp = asn_build_int(bufp, BufLenP, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), (int *) (&Version), sizeof(Version)); if (bufp == NULL) { snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Version)!\n"); return (NULL); } snmplib_debug(8, "snmp_msg_Encode: Encoding community (%s) (%d)\n", Community, CommLen); /* Community */ bufp = asn_build_string(bufp, BufLenP, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), Community, CommLen); if (bufp == NULL) { snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Community)!\n"); return (NULL); } /* Encode the rest. */ /* A nice header for this PDU. * Encoded with the wrong length. We'll fix it later. */ snmplib_debug(8, "snmp_msg_Encode:Encoding PDU Header at 0x%p (fake len %d) (%d bytes so far)\n", bufp, *BufLenP, *BufLenP); PDUHeaderPtr = bufp; bufp = asn_build_header(bufp, BufLenP, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), (*BufLenP)); if (bufp == NULL) return (NULL); /* Encode this PDU. */ PDUDataStart = bufp; bufp = snmp_pdu_encode(bufp, BufLenP, PDU); if (bufp == NULL) return (NULL); /* snmp_pdu_encode registered failure */ VARHeaderPtr = bufp; bufp = asn_build_header(bufp, BufLenP, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), FakeArg); if (bufp == NULL) return (NULL); VARDataStart = bufp; /* And build the variables */ bufp = snmp_var_EncodeVarBind(bufp, BufLenP, PDU->variables, Version); if (bufp == NULL) return (NULL); /* snmp_var_EncodeVarBind registered failure */ /* Cool. Now insert the appropriate lengths. */ #if DEBUG_MSG_ENCODE snmplib_debug(9, "Msg: Vars returned 0x%x. PDU Started at 0x%x\n", bufp, PDUHeaderPtr); snmplib_debug(9, "MSG: Entire PDU length is %d (0x%x - 0x%x)\n", (int) (bufp - PDUDataStart), PDUHeaderPtr, bufp); #endif tmp = asn_build_header(PDUHeaderPtr, &FakeArg, (u_char) PDU->command, (int) (bufp - PDUDataStart)); /* Length of the PDU and Vars */ if (tmp == NULL) return (NULL); #if DEBUG_MSG_ENCODE snmplib_debug(9, "MSG: Entire message length is %d (0x%x - 0x%x)\n", (int) (bufp - MsgPtr), MsgPtr, bufp); #endif tmp = asn_build_header(Buffer, &FakeArg, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), (bufp - MsgPtr)); /* Length of everything */ if (tmp == NULL) return (NULL); tmp = asn_build_header(VARHeaderPtr, &FakeArg, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), (bufp - VARDataStart)); /* Length of everything */ if (tmp == NULL) return (NULL); *BufLenP = (bufp - Buffer); return (u_char *) bufp; }
static int parse_subtree(struct snmp_mib_tree *subtree, char *input, oid *output, int *out_len) { char buf[128], *to = buf; u_int subid = 0; struct snmp_mib_tree *tp; /* * No empty strings. Can happen if there is a trailing '.' or two '.'s * in a row, i.e. "..". */ if ((*input == '\0') || (*input == '.')) return (0); if (xisdigit(*input)) { /* * Read the number, then try to find it in the subtree. */ while (xisdigit(*input)) { subid *= 10; subid += *input++ - '0'; } for (tp = subtree; tp; tp = tp->next_peer) { if (tp->subid == subid) goto found; } tp = NULL; } else { /* * Read the name into a buffer. */ while ((*input != '\0') && (*input != '.')) { *to++ = *input++; } *to = '\0'; /* * Find the name in the subtree; */ for (tp = subtree; tp; tp = tp->next_peer) { if (lc_cmp(tp->label, buf) == 0) { subid = tp->subid; goto found; } } /* * If we didn't find the entry, punt... */ if (tp == NULL) { snmplib_debug(0, "sub-identifier not found: %s\n", buf); return (0); } } found: if (subid > (u_int) MAX_SUBID) { snmplib_debug(0, "sub-identifier too large: %s\n", buf); return (0); } if ((*out_len)-- <= 0) { snmplib_debug(0, "object identifier too long\n"); return (0); } *output++ = subid; if (*input != '.') return (1); if ((*out_len = parse_subtree(tp ? tp->child_list : NULL, ++input, output, out_len)) == 0) return (0); return (++*out_len); }
/* Parse all Vars from the buffer */ u_char * snmp_var_DecodeVarBind(u_char * Buffer, int *BufLen, struct variable_list ** VarP, int Version) { struct variable_list *Var = NULL, **VarLastP; u_char *bufp, *tmp; u_char VarBindType; u_char *DataPtr; int DataLen; oid TmpBuf[MAX_NAME_LEN]; int AllVarLen = *BufLen; int ThisVarLen = 0; VarLastP = VarP; #ifdef DEBUG_VARS_DECODE printf("VARS: Decoding buffer of length %d\n", *BufLen); #endif /* Now parse the variables */ bufp = asn_parse_header(Buffer, &AllVarLen, &VarBindType); if (bufp == NULL) return (NULL); if (VarBindType != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) { snmp_set_api_error(SNMPERR_PDU_PARSE); return (NULL); } #ifdef DEBUG_VARS_DECODE printf("VARS: All Variable length %d\n", AllVarLen); #endif #define PARSE_ERROR { snmp_var_free(Var); return(NULL); } /* We know how long the variable list is. Parse it. */ while ((int) AllVarLen > 0) { /* Create a new variable */ Var = snmp_var_new(NULL, MAX_NAME_LEN); if (Var == NULL) return (NULL); /* Parse the header to find out the length of this variable. */ ThisVarLen = AllVarLen; tmp = asn_parse_header(bufp, &ThisVarLen, &VarBindType); if (tmp == NULL) PARSE_ERROR; /* Now that we know the length , figure out how it relates to * the entire variable list */ AllVarLen = AllVarLen - (ThisVarLen + (tmp - bufp)); bufp = tmp; /* Is it valid? */ if (VarBindType != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) { snmp_set_api_error(SNMPERR_PDU_PARSE); PARSE_ERROR; } #ifdef DEBUG_VARS_DECODE printf("VARS: Header type 0x%x (%d bytes left)\n", VarBindType, ThisVarLen); #endif /* Parse the OBJID */ bufp = asn_parse_objid(bufp, &ThisVarLen, &VarBindType, Var->name, &(Var->name_length)); if (bufp == NULL) PARSE_ERROR; if (VarBindType != (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID)) { snmp_set_api_error(SNMPERR_PDU_PARSE); PARSE_ERROR; } #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded OBJID (%d bytes). (%d bytes left)\n", Var->name_length, ThisVarLen); #endif /* Keep a pointer to this object */ DataPtr = bufp; DataLen = ThisVarLen; /* find out type of object */ bufp = asn_parse_header(bufp, &ThisVarLen, &(Var->type)); if (bufp == NULL) PARSE_ERROR; ThisVarLen = DataLen; #ifdef DEBUG_VARS_DECODE printf("VARS: Data type %d\n", Var->type); #endif /* Parse the type */ switch ((short) Var->type) { case ASN_INTEGER: Var->val.integer = (int *) xmalloc(sizeof(int)); if (Var->val.integer == NULL) { snmp_set_api_error(SNMPERR_OS_ERR); PARSE_ERROR; } Var->val_len = sizeof(int); bufp = asn_parse_int(DataPtr, &ThisVarLen, &Var->type, (int *) Var->val.integer, Var->val_len); #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded integer '%d' (%d bytes left)\n", *(Var->val.integer), ThisVarLen); #endif break; case SMI_COUNTER32: case SMI_GAUGE32: /* case SMI_UNSIGNED32: */ case SMI_TIMETICKS: Var->val.integer = (int *) xmalloc(sizeof(u_int)); if (Var->val.integer == NULL) { snmp_set_api_error(SNMPERR_OS_ERR); PARSE_ERROR; } Var->val_len = sizeof(u_int); bufp = asn_parse_unsigned_int(DataPtr, &ThisVarLen, &Var->type, (u_int *) Var->val.integer, Var->val_len); #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded timeticks '%d' (%d bytes left)\n", *(Var->val.integer), ThisVarLen); #endif break; case ASN_OCTET_STR: case SMI_IPADDRESS: case SMI_OPAQUE: Var->val_len = *&ThisVarLen; /* String is this at most */ Var->val.string = (u_char *) xmalloc((unsigned) Var->val_len); if (Var->val.string == NULL) { snmp_set_api_error(SNMPERR_OS_ERR); PARSE_ERROR; } bufp = asn_parse_string(DataPtr, &ThisVarLen, &Var->type, Var->val.string, &Var->val_len); #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded string '%s' (length %d) (%d bytes left)\n", (Var->val.string), Var->val_len, ThisVarLen); #endif break; case ASN_OBJECT_ID: Var->val_len = MAX_NAME_LEN; bufp = asn_parse_objid(DataPtr, &ThisVarLen, &Var->type, TmpBuf, &Var->val_len); Var->val_len *= sizeof(oid); Var->val.objid = (oid *) xmalloc((unsigned) Var->val_len); if (Var->val.integer == NULL) { snmp_set_api_error(SNMPERR_OS_ERR); PARSE_ERROR; } /* Only copy if we successfully decoded something */ if (bufp) { xmemcpy((char *) Var->val.objid, (char *) TmpBuf, Var->val_len); } #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded OBJID (length %d) (%d bytes left)\n", Var->val_len, ThisVarLen); #endif break; case ASN_NULL: case SMI_NOSUCHINSTANCE: case SMI_NOSUCHOBJECT: case SMI_ENDOFMIBVIEW: break; case SMI_COUNTER64: snmplib_debug(2, "Unable to parse type SMI_COUNTER64!\n"); snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE); PARSE_ERROR; default: snmplib_debug(2, "bad type returned (%x)\n", Var->type); snmp_set_api_error(SNMPERR_PDU_PARSE); PARSE_ERROR; } /* End of var type switch */ if (bufp == NULL) PARSE_ERROR; #ifdef DEBUG_VARS_DECODE printf("VARS: Adding to list.\n"); #endif /* Add variable to the list */ *VarLastP = Var; VarLastP = &(Var->next_variable); } #undef PARSE_ERROR return (bufp); }
/* Build a variable binding. * * RFC 1905: Protocol Operations for SNMPv2 * * VarBind ::= * SEQUENCE { * name ObjectName * CHOICE { * value ObjectSyntax * unSpecified NULL * noSuchObject[0] NULL * noSuchInstance[1] NULL * endOfMibView[2] NULL * } * } */ u_char * snmp_var_EncodeVarBind(u_char * Buffer, int *BufLenP, variable_list * VarList, int Version) { struct variable_list *Vars; u_char *bufp; u_char *HeaderStart; u_char *HeaderEnd; int FakeArg = *BufLenP; bufp = Buffer; for (Vars = VarList; Vars; Vars = Vars->next_variable) { /* Build the header for this variable * * Use Maximum size. */ HeaderStart = bufp; HeaderEnd = asn_build_header(HeaderStart, BufLenP, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), FakeArg); if (HeaderEnd == NULL) return (NULL); /* Now, let's put the Object Identifier into the buffer */ bufp = asn_build_objid(HeaderEnd, BufLenP, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID), Vars->name, Vars->name_length); if (bufp == NULL) return (NULL); /* Now put the data in */ switch (Vars->type) { case ASN_INTEGER: bufp = asn_build_int(bufp, BufLenP, Vars->type, (int *) Vars->val.integer, Vars->val_len); break; case SMI_COUNTER32: case SMI_GAUGE32: /* case SMI_UNSIGNED32: */ case SMI_TIMETICKS: bufp = asn_build_unsigned_int(bufp, BufLenP, Vars->type, (u_int *) Vars->val.integer, Vars->val_len); break; case ASN_OCTET_STR: case SMI_IPADDRESS: case SMI_OPAQUE: bufp = asn_build_string(bufp, BufLenP, Vars->type, Vars->val.string, Vars->val_len); break; case ASN_OBJECT_ID: bufp = asn_build_objid(bufp, BufLenP, Vars->type, (oid *) Vars->val.objid, Vars->val_len / sizeof(oid)); break; case SMI_NOSUCHINSTANCE: case SMI_NOSUCHOBJECT: case SMI_ENDOFMIBVIEW: if (Version == SNMP_VERSION_1) { /* SNMP Version 1 does not support these error codes. */ bufp = asn_build_null(bufp, BufLenP, SMI_NOSUCHOBJECT); } else { bufp = asn_build_exception(bufp, BufLenP, Vars->type); } break; case ASN_NULL: bufp = asn_build_null(bufp, BufLenP, Vars->type); break; case SMI_COUNTER64: snmplib_debug(2, "Unable to encode type SMI_COUNTER64!\n"); /* Fall through */ default: snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE); return (NULL); } /* ASSERT: bufp should now point to the next valid byte. */ if (bufp == NULL) return (NULL); /* Rebuild the header with the appropriate length */ HeaderEnd = asn_build_header(HeaderStart, &FakeArg, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), (bufp - HeaderEnd)); /* Returns NULL */ if (HeaderEnd == NULL) return (NULL); } /* or the end of the entire thing */ return (bufp); }