snmp_api.c
上传用户:cxs890
上传日期:2021-05-22
资源大小:347k
文件大小:144k
源码类别:

SNMP编程

开发平台:

C/C++

  1.   DEBUGINDENTADD(-8); 
  2.   if (after_header != NULL)
  3.     *length = tmp_buf_len;
  4.   if (ret != SNMPERR_SUCCESS) {
  5.     ERROR_MSG("error parsing PDU");
  6.     snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  7.     return SNMPERR_ASN_PARSE_ERR;
  8.   }
  9.   return SNMPERR_SUCCESS;
  10. }  /* end snmpv3_parse() */
  11. #define ERROR_STAT_LENGTH 11
  12. int
  13. snmpv3_make_report(struct snmp_pdu *pdu, int error)
  14. {
  15.   long ltmp;
  16.   static oid unknownSecurityLevel[] = {1,3,6,1,6,3,15,1,1,1,0};
  17.   static oid notInTimeWindow[]      = {1,3,6,1,6,3,15,1,1,2,0};
  18.   static oid unknownUserName[]      = {1,3,6,1,6,3,15,1,1,3,0};
  19.   static oid unknownEngineID[]      = {1,3,6,1,6,3,15,1,1,4,0};
  20.   static oid wrongDigest[]          = {1,3,6,1,6,3,15,1,1,5,0};
  21.   static oid decryptionError[]      = {1,3,6,1,6,3,15,1,1,6,0};
  22.   oid *err_var;
  23.   int err_var_len;
  24.   int stat_ind;
  25.   switch (error) {
  26.   case SNMPERR_USM_UNKNOWNENGINEID:
  27.     stat_ind = STAT_USMSTATSUNKNOWNENGINEIDS;
  28.     err_var = unknownEngineID;
  29.     err_var_len = ERROR_STAT_LENGTH;
  30.     break;
  31.   case SNMPERR_USM_UNKNOWNSECURITYNAME:
  32.     stat_ind = STAT_USMSTATSUNKNOWNUSERNAMES;
  33.     err_var = unknownUserName;
  34.     err_var_len = ERROR_STAT_LENGTH;
  35.     break;
  36.   case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
  37.     stat_ind = STAT_USMSTATSUNSUPPORTEDSECLEVELS;
  38.     err_var = unknownSecurityLevel;
  39.     err_var_len = ERROR_STAT_LENGTH;
  40.     break;
  41.   case SNMPERR_USM_AUTHENTICATIONFAILURE:
  42.     stat_ind = STAT_USMSTATSWRONGDIGESTS;
  43.     err_var = wrongDigest;
  44.     err_var_len = ERROR_STAT_LENGTH;
  45.     break;
  46.   case SNMPERR_USM_NOTINTIMEWINDOW:
  47.     stat_ind = STAT_USMSTATSNOTINTIMEWINDOWS;
  48.     err_var = notInTimeWindow;
  49.     err_var_len = ERROR_STAT_LENGTH;
  50.     break;
  51.   case SNMPERR_USM_DECRYPTIONERROR:
  52.     stat_ind = STAT_USMSTATSDECRYPTIONERRORS;
  53.     err_var = decryptionError;
  54.     err_var_len = ERROR_STAT_LENGTH;
  55.     break;
  56.   default:
  57.     return SNMPERR_GENERR;
  58.     break;
  59.   }
  60.   snmp_free_varbind(pdu->variables); /* free the current varbind */
  61.   pdu->variables = NULL;
  62.   SNMP_FREE(pdu->securityEngineID);
  63.   pdu->securityEngineID = snmpv3_generate_engineID(&pdu->securityEngineIDLen);
  64.   SNMP_FREE(pdu->contextEngineID);
  65.   pdu->contextEngineID = snmpv3_generate_engineID(&pdu->contextEngineIDLen);
  66.   pdu->command = SNMP_MSG_REPORT;
  67.   pdu->errstat = 0;
  68.   pdu->errindex = 0;
  69.   pdu->contextName = strdup("");
  70.   pdu->contextNameLen = strlen(pdu->contextName);
  71.   /* reports shouldn't cache previous data. */
  72.   /* FIX - yes they should but USM needs to follow new EoP to determine
  73.      which cached values to use 
  74.   */
  75.   if (pdu->securityStateRef) {
  76.     usm_free_usmStateReference(pdu->securityStateRef);
  77.     pdu->securityStateRef = NULL;
  78.   }
  79.   
  80.   if (error != SNMPERR_USM_NOTINTIMEWINDOW) 
  81.     pdu->securityLevel          = SNMP_SEC_LEVEL_NOAUTH;
  82.   else
  83.     pdu->securityLevel          = SNMP_SEC_LEVEL_AUTHNOPRIV;
  84.   /* find the appropriate error counter
  85.    */
  86.   ltmp = snmp_get_statistic(stat_ind);
  87.   /* return the appropriate error counter
  88.    */
  89.   snmp_pdu_add_variable(pdu, err_var, err_var_len,
  90.                         ASN_COUNTER, (u_char *) &ltmp, sizeof(ltmp));
  91.   return SNMPERR_SUCCESS;
  92. }  /* end snmpv3_make_report() */
  93. int
  94. snmpv3_get_report_type(struct snmp_pdu *pdu)
  95. {
  96.   static oid snmpMPDStats[] = {1,3,6,1,6,3,11,2,1};
  97.   static oid usmStats[] = {1,3,6,1,6,3,15,1,1};
  98.   struct variable_list *vp;
  99.   int rpt_type = SNMPERR_UNKNOWN_REPORT;
  100.   if (pdu == NULL || pdu->variables == NULL) return rpt_type;
  101.   vp = pdu->variables;
  102.   if (vp->name_length == REPORT_STATS_LEN+2) {
  103.     if (memcmp(snmpMPDStats,vp->name,REPORT_STATS_LEN*sizeof(oid)) == 0) {
  104.       switch (vp->name[REPORT_STATS_LEN]) {
  105.       case REPORT_snmpUnknownSecurityModels_NUM:
  106. rpt_type = SNMPERR_UNKNOWN_SEC_MODEL;
  107. break;
  108.       case REPORT_snmpInvalidMsgs_NUM:
  109. rpt_type = SNMPERR_INVALID_MSG;
  110. break;
  111.       }
  112.     } else if (memcmp(usmStats,vp->name,REPORT_STATS_LEN*sizeof(oid)) == 0) {
  113.       switch (vp->name[REPORT_STATS_LEN]) {
  114.       case REPORT_usmStatsUnsupportedSecLevels_NUM:
  115. rpt_type = SNMPERR_UNSUPPORTED_SEC_LEVEL;
  116. break;
  117.       case REPORT_usmStatsNotInTimeWindows_NUM:
  118. rpt_type = SNMPERR_NOT_IN_TIME_WINDOW;
  119. break;
  120.       case REPORT_usmStatsUnknownUserNames_NUM:
  121. rpt_type = SNMPERR_UNKNOWN_USER_NAME;
  122. break;
  123.       case REPORT_usmStatsUnknownEngineIDs_NUM:
  124. rpt_type = SNMPERR_UNKNOWN_ENG_ID;
  125. break;
  126.       case REPORT_usmStatsWrongDigests_NUM:
  127. rpt_type = SNMPERR_AUTHENTICATION_FAILURE;
  128. break;
  129.       case REPORT_usmStatsDecryptionErrors_NUM:
  130. rpt_type = SNMPERR_DECRYPTION_ERR;
  131. break;
  132.       }
  133.     }
  134.   }
  135.   DEBUGMSGTL(("report", "Report type: %dn", rpt_type));
  136.   return rpt_type;
  137. }
  138. /*
  139.  * Parses the packet received on the input session, and places the data into
  140.  * the input pdu.  length is the length of the input packet.
  141.  * If any errors are encountered, -1 or USM error is returned.
  142.  * Otherwise, a 0 is returned.
  143.  */
  144. static int
  145. _snmp_parse(void * sessp,
  146.    struct snmp_session *session,
  147.    struct snmp_pdu *pdu,
  148.    u_char *data,
  149.    size_t length)
  150. {
  151.     u_char community[COMMUNITY_MAX_LEN];
  152.     size_t community_length = COMMUNITY_MAX_LEN;
  153.     int result = -1;
  154.     snmp_current_community = NULL;
  155.     session->s_snmp_errno = 0;
  156.     session->s_errno = 0;
  157. /* Ensure all incoming PDUs have a unique means of identification 
  158. (This is not restricted to AgentX handling,
  159.  though that is where the need becomes visible) */
  160.     pdu->transid = snmp_get_next_transid();
  161.     if (session->version != SNMP_DEFAULT_VERSION)
  162. pdu->version = session->version;
  163.     else
  164.         pdu->version = snmp_parse_version(data,length);
  165.     switch (pdu->version) {
  166.     case SNMP_VERSION_1:
  167.     case SNMP_VERSION_2c:
  168.         DEBUGMSGTL(("snmp_api","Parsing SNMPv%d message...n", (1 + pdu->version)));
  169. /* authenticates message and returns length if valid */
  170.         DEBUGDUMPSETUP("dump_recv", data, 4);
  171.         DEBUGMSG(("dump_recv", "SNMPv%d messagen", (1+pdu->version)));
  172.         DEBUGINDENTMORE();
  173. data = snmp_comstr_parse(data, &length, community, &community_length, &pdu->version);
  174.         DEBUGINDENTLESS();
  175. if (data == NULL)
  176.     return -1;
  177.         if (pdu->version != session->version &&
  178.     session->version != SNMP_DEFAULT_VERSION)
  179. {
  180.             session->s_snmp_errno = SNMPERR_BAD_VERSION;
  181.             return -1;
  182. }
  183. /* maybe get the community string. */
  184. pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
  185. pdu->securityModel = (pdu->version == SNMP_VERSION_1) ?
  186.           SNMP_SEC_MODEL_SNMPv1 : SNMP_SEC_MODEL_SNMPv2c;
  187. SNMP_FREE(pdu->community);
  188. pdu->community_len = 0;
  189. pdu->community = (u_char *)0;
  190. if (community_length) {
  191.     pdu->community_len = community_length;
  192.     snmp_current_community = pdu->community = (u_char *)malloc(community_length + 1);
  193. if (pdu->community == NULL)
  194. return -1;
  195.     memmove(pdu->community, community, community_length);
  196. snmp_current_community[community_length] = 0;
  197. }
  198. if (session->authenticator){
  199.     data = session->authenticator(data, &length,
  200.   community,
  201.                                           community_length);
  202.     if (data == NULL)
  203.     {
  204. session->s_snmp_errno = SNMPERR_AUTHENTICATION_FAILURE;
  205. return -1;
  206.     }
  207. }
  208. result = snmp_pdu_parse(pdu, data, &length);
  209. if (result < 0) 
  210. {
  211. snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  212. }
  213.         break;
  214.     case SNMP_VERSION_3:
  215.       result = snmpv3_parse(pdu, data, &length, NULL);
  216.       DEBUGMSGTL(("snmp_parse",
  217.                    "Parsed SNMPv3 message (secName:%s, secLevel:%s): %sn",
  218.                    pdu->securityName, usmSecLevelName[pdu->securityLevel],
  219.                    snmp_api_errstring(result)));
  220.       if (result) {
  221. if (!sessp)
  222.   session->s_snmp_errno = result;
  223. else
  224. /* handle reportable errors */
  225. switch (result) {
  226. case SNMPERR_USM_UNKNOWNENGINEID:
  227. case SNMPERR_USM_UNKNOWNSECURITYNAME:
  228. case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
  229. case SNMPERR_USM_AUTHENTICATIONFAILURE:
  230. case SNMPERR_USM_NOTINTIMEWINDOW:
  231. case SNMPERR_USM_DECRYPTIONERROR:
  232.           if (SNMP_CMD_CONFIRMED(pdu->command) ||
  233.       (pdu->command == 0 && 
  234.               (pdu->flags & SNMP_MSG_FLAG_RPRT_BIT ))) {
  235.     struct snmp_pdu *pdu2;
  236.     int flags = pdu->flags;
  237.     pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
  238.     pdu2 = snmp_clone_pdu(pdu);
  239.     pdu->flags = pdu2->flags = flags;
  240.     snmpv3_make_report(pdu2, result);
  241.     snmp_sess_send(sessp, pdu2);
  242.   }
  243.   break;
  244. default:
  245.   session->s_snmp_errno = result;
  246.   break;
  247. }
  248.       }
  249.       break;
  250.     case SNMPERR_BAD_VERSION:
  251.       ERROR_MSG("error parsing snmp message version");
  252.       snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
  253.       session->s_snmp_errno = SNMPERR_BAD_VERSION;
  254.       break;
  255.     case SNMP_VERSION_sec:
  256.     case SNMP_VERSION_2u:
  257.     case SNMP_VERSION_2star:
  258.     case SNMP_VERSION_2p:
  259.     default:
  260.         ERROR_MSG("unsupported snmp message version");
  261. snmp_increment_statistic(STAT_SNMPINBADVERSIONS);
  262. session->s_snmp_errno = SNMPERR_BAD_VERSION;
  263.         break;
  264.     }
  265.     return result;
  266. }
  267. static int
  268. snmp_parse(void *sessp,
  269.    struct snmp_session *pss,
  270.    struct snmp_pdu *pdu,
  271.    u_char *data,
  272.    size_t length)
  273. {
  274.     int rc;
  275.     rc = _snmp_parse(sessp,pss,pdu,data,length);
  276.     if (rc) {
  277.         if ( !pss->s_snmp_errno)
  278.             pss->s_snmp_errno = SNMPERR_BAD_PARSE;
  279.         SET_SNMP_ERROR(pss->s_snmp_errno);
  280.     }
  281.     return rc;
  282. }
  283. int
  284. snmp_pdu_parse(struct snmp_pdu *pdu, u_char  *data, size_t *length) {
  285.   u_char  type;
  286.   u_char  msg_type;
  287.   u_char  *var_val;
  288.   int      badtype;
  289.   size_t   len;
  290.   size_t   four;
  291.   struct variable_list *vp = NULL;
  292.   struct soaddr_in *pduIp = (struct soaddr_in *)&(pdu->agent_addr);
  293.   oid objid[MAX_OID_LEN];
  294.   badtype = 0;
  295.   DEBUGINDENTMORE();
  296.   DEBUGMSG(("dump_recv", "PDUn"));
  297.   /* Get the PDU type */
  298.   data = asn_parse_header(data, length, &msg_type);
  299.   if (data == NULL)
  300.     return -1;
  301.   pdu->command = msg_type;
  302.   pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
  303.   /* get the fields in the PDU preceeding the variable-bindings sequence */
  304.   switch (pdu->command) {
  305.   case SNMP_MSG_TRAP:
  306.     /* enterprise */
  307.     pdu->enterprise_length = MAX_OID_LEN;
  308.     data = asn_parse_objid(data, length, &type, objid,
  309.    &pdu->enterprise_length);
  310.     if (data == NULL)
  311.       return -1;
  312.     pdu->enterprise = (oid *)malloc(pdu->enterprise_length * sizeof(oid));
  313. if (pdu->enterprise == NULL)
  314. return -1;
  315.     memmove(pdu->enterprise, objid, pdu->enterprise_length * sizeof(oid));
  316.     /* agent-addr */
  317.     four = 4;
  318.     pduIp->sin_family = AF_INET;
  319.     data = asn_parse_string(data, length, &type,
  320.     (u_char *)&pduIp->sin_addr.s_addr,
  321.     &four);
  322.     if (data == NULL)
  323.       return -1;
  324.     /* generic trap */
  325.     data = asn_parse_int(data, length, &type, (long *)&pdu->trap_type,
  326.  sizeof(pdu->trap_type));
  327.     if (data == NULL)
  328.       return -1;
  329.     /* specific trap */
  330.     data = asn_parse_int(data, length, &type, (long *)&pdu->specific_type,
  331.  sizeof(pdu->specific_type));
  332.     if (data == NULL)
  333.       return -1;
  334.     /* timestamp  */
  335.     data = asn_parse_unsigned_int(data, length, &type, &pdu->time,
  336.   sizeof(pdu->time));
  337.     if (data == NULL)
  338.       return -1;
  339.     break;
  340.   case SNMP_MSG_RESPONSE:
  341.   case SNMP_MSG_REPORT:
  342.     pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
  343.     /* fallthrough */
  344.   default:
  345.     /* PDU is not an SNMPv1 TRAP */
  346.     /* request id */
  347.     DEBUGDUMPHEADER("dump_recv", "Parsing request_idn");
  348.     data = asn_parse_int(data, length, &type, &pdu->reqid,
  349.  sizeof(pdu->reqid));
  350.     DEBUGINDENTLESS();
  351.     if (data == NULL) {
  352.       return -1;
  353.     }
  354.     /* error status (getbulk non-repeaters) */
  355.     DEBUGDUMPHEADER("dump_recv", "Parsing error statusn");
  356.     data = asn_parse_int(data, length, &type, &pdu->errstat,
  357.  sizeof(pdu->errstat));
  358.     DEBUGINDENTLESS();
  359.     if (data == NULL) {
  360.       return -1;
  361.     }
  362.     /* error index (getbulk max-repetitions) */
  363.     DEBUGDUMPHEADER("dump_recv", "Parsing error indexn");
  364.     data = asn_parse_int(data, length, &type, &pdu->errindex,
  365.  sizeof(pdu->errindex));
  366.     DEBUGINDENTLESS();
  367.     if (data == NULL) {
  368.       return -1;
  369.     }
  370.   }
  371.   /* get header for variable-bindings sequence */
  372.   DEBUGDUMPHEADER("dump_recv", "VarBindList:n");
  373.   data = asn_parse_sequence(data, length, &type,
  374.                         (ASN_SEQUENCE | ASN_CONSTRUCTOR), "varbinds");
  375.   if (data == NULL)
  376.     return -1;
  377.     /* get each varBind sequence */
  378.   while((int)*length > 0){
  379.     struct variable_list *vptemp;
  380.     vptemp = (struct variable_list *)malloc(sizeof(*vptemp));
  381.     if (0 == vptemp) {
  382.         return -1;
  383.     }
  384.     if (0 == vp){
  385.         pdu->variables = vptemp;
  386.     } else {
  387.         vp->next_variable = vptemp;
  388.     }
  389.     vp = vptemp;
  390.     vp->next_variable = NULL;
  391.     vp->val.string = NULL;
  392.     vp->name_length = MAX_OID_LEN;
  393.     vp->name = 0;
  394.     DEBUGDUMPHEADER("dump_recv", "VarBind:n");
  395.     data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type,
  396.      &vp->val_len, &var_val, length);
  397.     if (data == NULL)
  398.       return -1;
  399.     if (snmp_set_var_objid(vp, objid, vp->name_length))
  400.         return -1;
  401.     len = PACKET_LENGTH;
  402.     switch((short)vp->type){
  403.     case ASN_INTEGER:
  404.       vp->val.integer = (long *)vp->buf;
  405.       vp->val_len = sizeof(long);
  406.       asn_parse_int(var_val, &len, &vp->type,
  407.     (long *)vp->val.integer,
  408.     sizeof(vp->val.integer));
  409.       break;
  410.     case ASN_COUNTER:
  411.     case ASN_GAUGE:
  412.     case ASN_TIMETICKS:
  413.     case ASN_UINTEGER:
  414.       vp->val.integer = (long *)vp->buf;
  415.       vp->val_len = sizeof(u_long);
  416.       asn_parse_unsigned_int(var_val, &len, &vp->type,
  417.      (u_long *)vp->val.integer,
  418.      sizeof(vp->val.integer));
  419.       break;
  420. #ifdef OPAQUE_SPECIAL_TYPES
  421.     case ASN_OPAQUE_COUNTER64:
  422.     case ASN_OPAQUE_U64:
  423. #endif /* OPAQUE_SPECIAL_TYPES */
  424.     case ASN_COUNTER64:
  425.       vp->val.counter64 = (struct counter64 *)vp->buf;
  426.       vp->val_len = sizeof(struct counter64);
  427.       asn_parse_unsigned_int64(var_val, &len, &vp->type,
  428.        (struct counter64 *)vp->val.counter64,
  429.        sizeof(*vp->val.counter64));
  430.       break;
  431. #ifdef OPAQUE_SPECIAL_TYPES
  432.     case ASN_OPAQUE_FLOAT:
  433.       vp->val.floatVal = (float *)vp->buf;
  434.       vp->val_len = sizeof(float);
  435.       asn_parse_float(var_val, &len, &vp->type,
  436.       vp->val.floatVal,
  437.       vp->val_len);
  438.       break;
  439.     case ASN_OPAQUE_DOUBLE:
  440.       vp->val.doubleVal = (double *)vp->buf;
  441.       vp->val_len = sizeof(double);
  442.       asn_parse_double(var_val, &len, &vp->type,
  443.        vp->val.doubleVal,
  444.        vp->val_len);
  445.       break;
  446.     case ASN_OPAQUE_I64:
  447.       vp->val.counter64 = (struct counter64 *)vp->buf;
  448.       vp->val_len = sizeof(struct counter64);
  449.       asn_parse_signed_int64(var_val, &len, &vp->type,
  450.      (struct counter64 *)vp->val.counter64,
  451.      sizeof(*vp->val.counter64));
  452.       break;
  453. #endif /* OPAQUE_SPECIAL_TYPES */
  454.       case ASN_OCTET_STR:
  455.       case ASN_IPADDRESS:
  456.       case ASN_OPAQUE:
  457.       case ASN_NSAP:
  458.         if (vp->val_len < sizeof(vp->buf)){
  459.           vp->val.string = (u_char *)vp->buf;
  460.         } else {
  461.           vp->val.string = (u_char *)malloc((unsigned)vp->val_len);
  462.   if (vp->val.string == NULL)
  463.   return -1;
  464.         }
  465.         asn_parse_string(var_val, &len, &vp->type, vp->val.string,
  466.                          &vp->val_len);
  467.         break;
  468.       case ASN_OBJECT_ID:
  469.         vp->val_len = MAX_OID_LEN;
  470.         asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
  471.         vp->val_len *= sizeof(oid);
  472.         vp->val.objid = (oid *)malloc((unsigned)vp->val_len);
  473. if (vp->val.objid == NULL)
  474. return -1;
  475.         memmove(vp->val.objid, objid, vp->val_len);
  476.         break;
  477.       case SNMP_NOSUCHOBJECT:
  478.       case SNMP_NOSUCHINSTANCE:
  479.       case SNMP_ENDOFMIBVIEW:
  480.       case ASN_NULL:
  481.         break;
  482.       case ASN_BIT_STR:
  483.         vp->val.bitstring = (u_char *)malloc(vp->val_len);
  484. if (vp->val.bitstring == NULL)
  485. return -1;
  486.         asn_parse_bitstring(var_val, &len, &vp->type,
  487.                             vp->val.bitstring, &vp->val_len);
  488.         break;
  489.       default:
  490.         snmp_log(LOG_ERR,"bad type returned (%x)n", vp->type);
  491.         badtype = 1;
  492.         break;
  493.     }
  494.     DEBUGINDENTLESS();
  495.   }
  496.   DEBUGINDENTLESS();
  497.   DEBUGINDENTLESS();
  498.   return badtype;
  499. }
  500. /* snmp v3 utility function to parse into the scopedPdu. stores contextName
  501.    and contextEngineID in pdu struct. Also stores pdu->command (handy for 
  502.    Report generation).
  503.    returns pointer to begining of PDU or NULL on error.
  504. */
  505. u_char *
  506. snmpv3_scopedPDU_parse(struct snmp_pdu *pdu,
  507. u_char  *cp,
  508. size_t  *length)
  509. {
  510.   u_char  tmp_buf[SNMP_MAX_MSG_SIZE];
  511.   size_t  tmp_buf_len;
  512.   u_char  type;
  513.   size_t  asn_len;
  514.   u_char* data;
  515.   pdu->command = 0; /* initialize so we know if it got parsed */
  516.   asn_len = *length;
  517.   data = asn_parse_sequence(cp, &asn_len, &type,
  518.                         (ASN_SEQUENCE | ASN_CONSTRUCTOR), "plaintext scopedPDU");
  519.   if (data == NULL){
  520.     return NULL;
  521.   }
  522.   *length -= data - cp;
  523.   /* contextEngineID from scopedPdu  */
  524.   DEBUGDUMPHEADER("dump_recv", "Parsing contextEngineIDn");
  525.   data = asn_parse_string(data, length, &type, pdu->contextEngineID, 
  526.   &pdu->contextEngineIDLen);
  527.   DEBUGINDENTLESS();
  528.   if (data == NULL) {
  529.     ERROR_MSG("error parsing contextEngineID from scopedPdu");
  530.     return NULL;
  531.   }
  532.   /* check that it agrees with engineID returned from USM above
  533.    * only a warning because this could be legal if we are a proxy
  534.    */
  535.   if (pdu->securityEngineIDLen != pdu->contextEngineIDLen ||
  536.       memcmp(pdu->securityEngineID, pdu->contextEngineID,
  537.      pdu->securityEngineIDLen) != 0) {
  538.     DEBUGMSGTL(("scopedPDU_parse",
  539.                 "inconsistent engineID information in messagen"));
  540.   }
  541.   /* parse contextName from scopedPdu
  542.    */
  543.   tmp_buf_len = SNMP_MAX_CONTEXT_SIZE;
  544.   DEBUGDUMPHEADER("dump_recv", "Parsing contextNamen");
  545.   data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
  546.   DEBUGINDENTLESS();
  547.   if (data == NULL) {
  548.     ERROR_MSG("error parsing contextName from scopedPdu");
  549.     return NULL;
  550.   }
  551.   if (tmp_buf_len) {
  552.     pdu->contextName  = (char *)malloc(tmp_buf_len);
  553. if (pdu->contextName == NULL)
  554. return NULL;
  555.     memmove(pdu->contextName, tmp_buf, tmp_buf_len);
  556.     pdu->contextNameLen  = tmp_buf_len;
  557.   } else {
  558.     pdu->contextName  = strdup("");
  559. if (pdu->contextName == NULL)
  560. return NULL;
  561.     pdu->contextNameLen  = 0;
  562.   }
  563.   /* Get the PDU type */
  564.   asn_len = *length;
  565.   DEBUGDUMPHEADER("dump_recv", "Parsing PDU typen");
  566.   cp = asn_parse_header(data, &asn_len, &type);
  567.   DEBUGINDENTLESS();
  568.   if (cp == NULL)
  569.     return NULL;
  570.   pdu->command = type;
  571.   return data;
  572. }
  573. /*
  574.  * Sends the input pdu on the session after calling snmp_build to create
  575.  * a serialized packet.  If necessary, set some of the pdu data from the
  576.  * session defaults.  Add a request corresponding to this pdu to the list
  577.  * of outstanding requests on this session, then send the pdu.
  578.  * Returns the request id of the generated packet if applicable, otherwise 1.
  579.  * On any error, 0 is returned.
  580.  * The pdu is freed by snmp_send() unless a failure occured.
  581.  */
  582. int
  583. snmp_send(struct snmp_session *session,
  584.   struct snmp_pdu *pdu)
  585. {
  586.   return snmp_async_send(session, pdu, NULL, NULL);
  587. }
  588. int
  589. snmp_sess_send(void *sessp,
  590.        struct snmp_pdu *pdu)
  591. {
  592.   return snmp_sess_async_send(sessp, pdu, NULL, NULL);
  593. }
  594. /*
  595.  * int snmp_async_send(session, pdu, callback, cb_data)
  596.  *     struct snmp_session *session;
  597.  *     struct snmp_pdu *pdu;
  598.  *     snmp_callback callback;
  599.  *     void   *cb_data;
  600.  *
  601.  * Sends the input pdu on the session after calling snmp_build to create
  602.  * a serialized packet.  If necessary, set some of the pdu data from the
  603.  * session defaults.  Add a request corresponding to this pdu to the list
  604.  * of outstanding requests on this session and store callback and data,
  605.  * then send the pdu.
  606.  * Returns the request id of the generated packet if applicable, otherwise 0.
  607.  * On any error, 0 is returned.
  608.  * The pdu is freed by snmp_send() unless a failure occurred.
  609.  */
  610. int
  611. snmp_async_send(struct snmp_session *session,
  612. struct snmp_pdu *pdu,
  613. snmp_callback callback,
  614. void *cb_data)
  615. {
  616.     void *sessp = snmp_sess_pointer(session);
  617.     return snmp_sess_async_send(sessp, pdu, callback, cb_data);
  618. }
  619. static int
  620. _sess_async_send(void *sessp,
  621.      struct snmp_pdu *pdu,
  622.      snmp_callback callback,
  623.      void *cb_data)
  624. {
  625.     struct session_list *slp = (struct session_list *)sessp;
  626.     struct snmp_session *session;
  627.     struct snmp_internal_session *isp;
  628.     u_char  *packet;
  629.     size_t length = PACKET_LENGTH;
  630.     struct soaddr_in *isp_addr;
  631.     struct soaddr_in *pduIp;
  632.     int result, addr_size;
  633.     long reqid;
  634. packet = packet_buffer_read;
  635.     session = slp->session; isp = slp->internal;
  636.     if (!session || !isp) {
  637.       DEBUGMSGTL(("sess_read","send fail: closing...n"));
  638.       return 0;
  639.     }
  640.     session->s_snmp_errno = 0;
  641.     session->s_errno = 0;
  642.     if (pdu == NULL) {
  643.         session->s_snmp_errno = SNMPERR_NULL_PDU;
  644.         return 0;
  645.     }
  646. #if TEMPORARILY_DISABLED
  647.  /*
  648.   *  NULL variable are allowed in certain PDU types.
  649.   *  In particular, SNMPv3 engineID probes are of this form.
  650.   *  There is an internal PDU flag to indicate that this
  651.   *    is acceptable, but until the construction of engineID
  652.   *    probes can be amended to set this flag, we'll simply
  653.   *    skip this test altogether.
  654.   */
  655.     if (pdu->variables == NULL) {
  656. switch (pdu->command) {
  657. case SNMP_MSG_GET:
  658. case SNMP_MSG_SET:
  659. case SNMP_MSG_GETNEXT:
  660. case SNMP_MSG_GETBULK:
  661. case SNMP_MSG_RESPONSE:
  662. case SNMP_MSG_TRAP2:
  663. case SNMP_MSG_REPORT:
  664. case SNMP_MSG_INFORM:
  665.     session->s_snmp_errno = snmp_errno = SNMPERR_NO_VARS;
  666.     return 0;
  667. case SNMP_MSG_TRAP:
  668.     break;
  669.         }
  670.     }
  671. #endif
  672.     pduIp = (struct soaddr_in *)&(pdu->address);
  673.     pdu->flags |= UCD_MSG_FLAG_EXPECT_RESPONSE;
  674.     /* check/setup the version */
  675.     if (pdu->version == SNMP_DEFAULT_VERSION) {
  676.         if (session->version == SNMP_DEFAULT_VERSION) {
  677.     session->s_snmp_errno = SNMPERR_BAD_VERSION;
  678.     return 0;
  679.         }
  680.         pdu->version = session->version;
  681.     } else if (session->version == SNMP_DEFAULT_VERSION) {
  682. /* It's OK */
  683.     } else if (pdu->version != session->version) {
  684.       /* ENHANCE: we should support multi-lingual sessions */
  685.         session->s_snmp_errno = SNMPERR_BAD_VERSION;
  686.         return 0;
  687.     }
  688.     if (pdu->address.sa_family == AF_UNSPEC){
  689. isp_addr = (struct soaddr_in *)&(isp->addr);
  690. if (isp->addr.sa_family == AF_UNSPEC ||
  691.    (isp->addr.sa_family == AF_INET &&
  692.     isp_addr->sin_addr.s_addr == SNMP_DEFAULT_ADDRESS)){
  693.         session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
  694.         return 0;
  695. }
  696. memmove(&pdu->address, &(isp->addr), sizeof(isp->addr));
  697.     }
  698.     addr_size = snmp_socket_length(pdu->address.sa_family);
  699.     /* build the message to send */
  700.     if (isp->hook_build)
  701. result = isp->hook_build(session, pdu, packet, &length);
  702.     else
  703. result = snmp_build(session, pdu, packet, &length);
  704.     if (result < 0){
  705. return 0;
  706.     }
  707. /*
  708. *if the packet size is larger than the local constraint
  709.     *of maximum message size, act as defined in RFC 1905.
  710. * --sxf 2000-1-4
  711. */
  712. if (length > snmp_para.packetsize)
  713. {
  714. snmp_log (LOG_ERR, "Out packet to bign");
  715. snmp_increment_statistic(STAT_SNMPOUTTOOBIGS);
  716. snmp_increment_statistic(STAT_SNMPSILENTDROPS);
  717. snmp_free_varbind (pdu->variables);
  718. pdu->variables = NULL;
  719. pdu->errstat = SNMP_ERR_TOOBIG;
  720. pdu->errindex = 0;
  721.     if (isp->hook_build)
  722. result = isp->hook_build(session, pdu, packet, &length);
  723. else
  724. result = snmp_build(session, pdu, packet, &length);
  725. if (result < 0){
  726. return 0;
  727. }
  728. /*
  729. *The pdu's type is response pdu, we don't know if it is the from getbulk request.
  730. *May be it should be processed earlier;
  731. */
  732. /*
  733. else
  734. {
  735. int count, i;
  736. struct variable_list *vptr;
  737. VARIABLE_CUT_RETRY:
  738. count = 0;
  739. for (vptr = pdu->variables; vptr != NULL; vptr = vptr->next_variable)
  740. count++;
  741. if (count > 0)
  742. {
  743. vptr = pdu->variables;
  744. for (i = 0; i < count/2; i++)
  745. {
  746. vptr = vptr->next_variable;
  747. }
  748. if (vptr != NULL)
  749. {
  750. snmp_free_varbind (vptr->next_variable);
  751. vptr->next_variable = NULL;
  752. }
  753. if (isp->hook_build)
  754. result = isp->hook_build(session, pdu, packet, &length);
  755. else
  756. result = snmp_build(session, pdu, packet, &length);
  757. if (result < 0){
  758. return 0;
  759. }
  760. if (length > snmp_para.packetsize)
  761. goto VARIABLE_CUT_RETRY;
  762. }
  763. else
  764. {
  765. pdu->errstat = SNMPERR_TOO_LONG;
  766. pdu->errindex = 0;
  767.     if (isp->hook_build)
  768. result = isp->hook_build(session, pdu, packet, &length);
  769. else
  770. result = snmp_build(session, pdu, packet, &length);
  771. if (result < 0){
  772. return 0;
  773. }
  774. }
  775. }/*end of if (pdu->command != SNMP_MSG_GETBULK)*/
  776. }
  777. if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET)){
  778. snmp_log(LOG_DEBUG, "nSending %u bytes to %s:%hun", length,
  779.    inet_ntoa(pduIp->sin_addr), ntohs(pduIp->sin_port));
  780. xdump(packet, length, "");
  781. }
  782. /* send the message */
  783. /*fanghao(A):2005-06-17*/
  784. #ifndef SWITCH
  785. if(session->vrfname[0]){
  786. if(so_bind_udp_vrf_byname(isp->sd, session->vrfname,0) < 0){
  787. session->s_snmp_errno = SNMPERR_BIND_VRF;
  788. session->s_errno = errno;
  789. return 0;
  790. }
  791. }else if(session->vrfid !=0){
  792. if( so_bind_udp_vrf_byid(isp->sd, (unsigned long)session->vrfid, 0) ){
  793. session->s_snmp_errno = SNMPERR_BIND_VRF;
  794. session->s_errno = errno;
  795. return 0;
  796. }
  797. }
  798. #endif
  799. result = so_sendto(isp->sd, (char *)packet, length, 0,
  800.    (struct soaddr *)&pdu->address, addr_size);
  801. #ifndef SWITCH
  802. /*fanghao(A):2005-06-17*/
  803. addr_size = snmp_socket_length(isp->me.sa_family);
  804. if (udp_bind_localaddr(isp->sd, (struct soaddr *)&isp->me, addr_size) != 0){
  805. session->s_snmp_errno = SNMPERR_BAD_LOCPORT;
  806. session->s_errno = errno;
  807. snmp_set_detail(strerror(errno));
  808. snmp_sess_close(slp);
  809. return 0;
  810.      }
  811. #endif
  812.     if ( result < 0){
  813. session->s_snmp_errno = SNMPERR_BAD_SENDTO;
  814. session->s_errno = errno;
  815.     return 0;
  816.     }
  817.     reqid = pdu->reqid;
  818.     /* add to pending requests list if expect a response */
  819.     if (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE) {
  820.         struct request_list *rp;
  821.         struct timeval tv;
  822. rp = (struct request_list *)calloc( 1, sizeof(struct request_list));
  823. if (rp == NULL) {
  824.     session->s_snmp_errno = SNMPERR_GENERR;
  825.     return 0;
  826. }
  827. gettimeofday(&tv, (struct timezone *)0);
  828. rp->pdu = pdu;
  829. rp->request_id = pdu->reqid;
  830. rp->message_id = pdu->msgid;
  831. rp->callback = callback;
  832. rp->cb_data = cb_data;
  833. rp->retries = 0;
  834. rp->timeout = session->timeout;
  835. rp->time = tv;
  836. tv.tv_usec += rp->timeout;
  837. tv.tv_sec += tv.tv_usec / 1000000L;
  838. tv.tv_usec %= 1000000L;
  839. rp->expire = tv;
  840. /* XX lock should be per session ! */
  841.       snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  842. if (isp->requestsEnd){
  843.     rp->next_request = isp->requestsEnd->next_request;
  844.     isp->requestsEnd->next_request = rp;
  845.     isp->requestsEnd = rp;
  846. } else {
  847.     rp->next_request = isp->requests;
  848.     isp->requests = rp;
  849.     isp->requestsEnd = rp;
  850. }
  851.       snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  852.     }
  853.     else
  854.         snmp_free_pdu(pdu);  /* free v1 or v2 TRAP PDU */
  855.     if (reqid == 0) {
  856.         syslog(LOG_WARNING, "SNMP-%d-ZEROREQID: Received snmp pdu with request id 0n", LOG_WARNING);
  857.         reqid = 1;
  858.     }
  859.     return reqid;
  860. }
  861. int
  862. snmp_sess_async_send(void *sessp,
  863.      struct snmp_pdu *pdu,
  864.      snmp_callback callback,
  865.      void *cb_data)
  866. {
  867.     int rc;
  868.     if (sessp == NULL){
  869. snmp_errno = SNMPERR_BAD_SESSION; /*MTCRITICAL_RESOURCE*/
  870. return(0);
  871.     }
  872.     rc = _sess_async_send(sessp,pdu,callback,cb_data);
  873.     if (rc == 0) {
  874.         struct session_list *psl;
  875.         struct snmp_session *pss;
  876.         psl = (struct session_list *)sessp;
  877.         pss = psl->session;
  878.         SET_SNMP_ERROR(pss->s_snmp_errno);
  879.     }
  880.     return rc;
  881. }
  882. /*
  883.  * Frees the variable and any malloc'd data associated with it.
  884.  */
  885. void
  886. snmp_free_var(struct variable_list *var)
  887. {
  888.     if (!var) return;
  889.     if (var->name != var->name_loc)
  890.         SNMP_FREE(var->name);
  891.     if (var->val.string != var->buf)
  892.         SNMP_FREE(var->val.string);
  893.     free(var);
  894. }
  895. void snmp_free_varbind(struct variable_list *var)
  896. {
  897.   struct variable_list *ptr;
  898.   while(var) {
  899.     ptr = var->next_variable;
  900.     snmp_free_var(var);
  901.     var = ptr;
  902.   }
  903. }
  904. /*
  905.  * Frees the pdu and any malloc'd data associated with it.
  906.  */
  907. void
  908. snmp_free_pdu(struct snmp_pdu *pdu)
  909. {
  910.     if (!pdu) return;
  911.     snmp_free_varbind(pdu->variables);
  912.     SNMP_FREE(pdu->enterprise);
  913.     SNMP_FREE(pdu->community);
  914.     SNMP_FREE(pdu->contextEngineID);
  915.     SNMP_FREE(pdu->securityEngineID);
  916.     SNMP_FREE(pdu->contextName);
  917.     SNMP_FREE(pdu->securityName);
  918.     free(pdu);
  919. }
  920. /*
  921.  * Checks to see if any of the fd's set in the fdset belong to
  922.  * snmp.  Each socket with it's fd set has a packet read from it
  923.  * and snmp_parse is called on the packet received.  The resulting pdu
  924.  * is passed to the callback routine for that session.  If the callback
  925.  * routine returns successfully, the pdu and it's request are deleted.
  926.  */
  927. void
  928. snmp_read(fd_set *fdset)
  929. {
  930.     struct session_list *slp;
  931.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  932.     for(slp = Sessions; slp; slp = slp->next){
  933.         snmp_sess_read((void *)slp, fdset);
  934.     }
  935.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  936. }
  937. #ifdef INCLUDE_BCMP
  938. extern uint32 bcmp_snmp_check_packet(struct snmp_session *session, struct snmp_pdu *pdu);
  939. #endif
  940. /* Same as snmp_read, but works just one session. */
  941. /* returns 0 if success, -1 if fail */
  942. /* MTR: can't lock here and at snmp_read */
  943. /* Beware recursive send maybe inside snmp_read callback function. */
  944. int
  945. _sess_read(void *sessp,
  946.        fd_set *fdset)
  947. {
  948.     struct session_list *slp = (struct session_list *)sessp;
  949.     struct snmp_session *sp;
  950.     struct snmp_internal_session *isp;
  951.     u_char *packet, *packetptr ;
  952.    /* u_char *ucp = 0;*/
  953.     struct soaddr        from;
  954.     struct soaddr_in *fromIp = (struct soaddr_in *)&from;
  955.     int length = 0;
  956.     struct snmp_pdu *pdu;
  957.     struct request_list *rp, *orp = NULL;
  958.     int ret;
  959.    /* int addrlen;*/
  960.     int fromlength;
  961. packetptr = packet = packet_buffer_read;
  962.     sp = slp->session; isp = slp->internal;
  963.     if (!sp || !isp) {
  964.       DEBUGMSGTL(("sess_read","read fail: closing...n"));
  965.       return 0;
  966.     }
  967.     if ((!isp->newpkt && !(FD_ISSET(isp->sd, fdset)))) {
  968.       DEBUGMSGTL(("sess_read","not reading...n"));
  969.       return 0;
  970.     }
  971.     
  972.     sp->s_snmp_errno = 0;
  973.     sp->s_errno = 0;
  974.     memset(&from, 0, sizeof(from));
  975.     fromlength = sizeof(from);
  976. {
  977.         length = so_recvfrom(isp->sd, (char *)packet, PACKET_LENGTH, 0,
  978.       (struct soaddr *)&from, &fromlength);
  979.         if (from.sa_family == AF_UNSPEC)
  980.             from.sa_family = AF_INET; /* bad bad bad OS, no bone! */
  981.         /*fanghao(A):2005-06-17*/
  982.         if( -1 != length )
  983.         {
  984.             struct soaddr_intf *pf;
  985.             pf = (struct soaddr_intf *)&from;
  986.             sp->vrfid = (uint32 )pf->sin_vrfid;
  987.         }
  988.     }
  989.     if (length == -1) {
  990. sp->s_snmp_errno = SNMPERR_BAD_RECVFROM;
  991. sp->s_errno = errno;
  992. snmp_set_detail(strerror(errno));
  993. return -1;
  994.     }
  995. if (length > snmp_para.packetsize)
  996. {
  997. sp->s_snmp_errno = SNMPERR_BAD_RECVFROM;
  998. snmp_increment_statistic (STAT_SNMPINTOOBIGS);
  999. snmp_log (LOG_ERR, "In packet to bign");
  1000. return -1;
  1001. }
  1002. /* Remote end closed connection */
  1003.     if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET)){
  1004.       snmp_log(LOG_DEBUG, "nReceived %d bytes from %s:%hun", length,
  1005.                inet_ntoa(fromIp->sin_addr), ntohs(fromIp->sin_port));
  1006.       xdump(packetptr, length, "");
  1007.     }
  1008.     if ( isp->hook_pre ) {
  1009.       if ( isp->hook_pre( sp, from ) == 0 )
  1010.   {
  1011.   
  1012.         return -1;
  1013.   }
  1014.     }
  1015.     pdu = (struct snmp_pdu *)malloc(sizeof(struct snmp_pdu));
  1016. if (pdu == NULL)
  1017. return -1;
  1018.     memset (pdu, 0, sizeof(*pdu));
  1019.     pdu->address = from;
  1020.     pdu->available_community = 0;
  1021.     if ( isp->hook_parse )
  1022.       ret = isp->hook_parse(sp, pdu, packetptr, length);
  1023.     else
  1024.       ret = snmp_parse(sessp, sp, pdu, packetptr, length);
  1025.     if ( isp->hook_post ) {
  1026.       if ( isp->hook_post( sp, pdu, ret ) == 0 ) {
  1027.         snmp_free_pdu(pdu);
  1028.         return -1;
  1029.       }
  1030.     }
  1031.     if (ret != SNMP_ERR_NOERROR) {
  1032.       snmp_free_pdu(pdu);
  1033.   
  1034.       return -1;
  1035.     }
  1036. #ifdef INCLUDE_BCMP
  1037.     if (bcmp_snmp_check_packet(sp, pdu) == SYS_ERROR)
  1038.     /*packet has been forwarded*/
  1039.     {
  1040.         return 0;
  1041.     }
  1042. #endif
  1043.     if (pdu->flags & UCD_MSG_FLAG_RESPONSE_PDU) {
  1044.       /* call USM to free any securityStateRef supplied with the message */
  1045.       if (pdu->securityStateRef) {
  1046.         usm_free_usmStateReference(pdu->securityStateRef);
  1047.         pdu->securityStateRef = NULL;
  1048.       }
  1049.       for(rp = isp->requests; rp; orp = rp, rp = rp->next_request) {
  1050.         snmp_callback callback;
  1051.         void *magic;
  1052.         if (pdu->version == SNMP_VERSION_3) {
  1053.           /* msgId must match for V3 messages */
  1054.           if (rp->message_id != pdu->msgid) continue;
  1055.           /* check that message fields match original,
  1056.            * if not, no further processing */
  1057.           if (!snmpv3_verify_msg(rp,pdu)) break;
  1058.         } else {
  1059.           if (rp->request_id != pdu->reqid) continue;
  1060.         }
  1061.         if (rp->callback) {
  1062.           callback = rp->callback;
  1063.           magic = rp->cb_data;
  1064.         } else {
  1065.           callback = sp->callback;
  1066.           magic = sp->callback_magic;
  1067.         }
  1068.         /* MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);  ?* XX lock should be per session ! */
  1069.         if (callback == NULL || 
  1070.             callback(RECEIVED_MESSAGE,sp,pdu->reqid,pdu,magic) == 1){
  1071.           if (pdu->command == SNMP_MSG_REPORT) {
  1072.             if (sp->s_snmp_errno == SNMPERR_NOT_IN_TIME_WINDOW) {
  1073.               /* trigger immediate retry on recoverable Reports 
  1074.                * (notInTimeWindow), incr_retries == TRUE to prevent
  1075.                * inifinite resend         */
  1076.               if (rp->retries <= sp->retries) {
  1077.                 snmp_resend_request(slp, rp, TRUE);
  1078.                 break;
  1079.               }
  1080.             } else {
  1081.               if (SNMPV3_IGNORE_UNAUTH_REPORTS) break;
  1082.             }
  1083.             /* handle engineID discovery - */
  1084.             if (!sp->securityEngineIDLen && pdu->securityEngineIDLen) {
  1085.               sp->securityEngineID = (u_char *)malloc(pdu->securityEngineIDLen);
  1086.   if (sp->securityEngineID == NULL)
  1087.   {
  1088.       snmp_free_pdu(pdu);
  1089.   return -1;
  1090.   }
  1091.               memcpy(sp->securityEngineID, pdu->securityEngineID,
  1092.                      pdu->securityEngineIDLen);
  1093.               sp->securityEngineIDLen = pdu->securityEngineIDLen;
  1094.               if (!sp->contextEngineIDLen) {
  1095.                 sp->contextEngineID = (u_char *)malloc(pdu->securityEngineIDLen);
  1096. if (sp->contextEngineID == NULL)
  1097. {
  1098.   snmp_free_pdu(pdu);
  1099.   return -1;
  1100. }
  1101.                 memcpy(sp->contextEngineID, pdu->securityEngineID,
  1102.                        pdu->securityEngineIDLen);
  1103.                 sp->contextEngineIDLen = pdu->securityEngineIDLen;
  1104.               }
  1105.             }
  1106.           }
  1107.           /* successful, so delete request */
  1108.           if (isp->requests == rp){
  1109.             /* first in list */
  1110.             isp->requests = rp->next_request;
  1111.             if (isp->requestsEnd == rp)
  1112.               isp->requestsEnd = NULL;
  1113.           } else {
  1114.             orp->next_request = rp->next_request;
  1115.             if (isp->requestsEnd == rp)
  1116.               isp->requestsEnd = orp;
  1117.           }
  1118.           snmp_free_pdu(rp->pdu);
  1119.           free(rp);
  1120.           /* there shouldn't be any more requests with the
  1121.              same reqid */
  1122.           break;
  1123.         }
  1124.         /* MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);  ?* XX lock should be per session ! */
  1125.       }
  1126.     } else {
  1127.       if (sp->callback)
  1128.         {
  1129.           /* MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION); */
  1130.           sp->callback(RECEIVED_MESSAGE, sp, pdu->reqid, pdu,
  1131.                        sp->callback_magic);
  1132.           /* MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION); */
  1133.         }
  1134.     }
  1135.     /* call USM to free any securityStateRef supplied with the message */
  1136.     if (pdu->securityStateRef && pdu->command == SNMP_MSG_TRAP2) {
  1137.       usm_free_usmStateReference(pdu->securityStateRef);
  1138.       pdu->securityStateRef = NULL;
  1139.     }
  1140. snmp_current_community = NULL;
  1141.     snmp_free_pdu(pdu);
  1142.     return 0;
  1143. }
  1144. /* returns 0 if success, -1 if fail */
  1145. int
  1146. snmp_sess_read(void *sessp,
  1147.        fd_set *fdset)
  1148.     {
  1149.     struct session_list *psl;
  1150.     struct snmp_session *pss;
  1151.     int rc;
  1152.     rc = _sess_read(sessp, fdset);
  1153.     psl = (struct session_list *)sessp;
  1154.     pss = psl->session;
  1155.     if (rc && pss->s_snmp_errno) {
  1156.         SET_SNMP_ERROR(pss->s_snmp_errno);
  1157.     }
  1158.     return rc;
  1159. }
  1160. /*
  1161. *Trap use the same session list, so record the session list that is 
  1162. *not created by trap. --sxf 2k-12-27
  1163. */
  1164. void set_trapd_session_ptr (void)
  1165. {
  1166. trapdSessionPtr = (void*)Sessions;
  1167. }
  1168. /*
  1169.  * Returns info about what snmp requires from a select statement.
  1170.  * numfds is the number of fds in the list that are significant.
  1171.  * All file descriptors opened for SNMP are OR'd into the fdset.
  1172.  * If activity occurs on any of these file descriptors, snmp_read
  1173.  * should be called with that file descriptor set
  1174.  *
  1175.  * The timeout is the latest time that SNMP can wait for a timeout.  The
  1176.  * select should be done with the minimum time between timeout and any other
  1177.  * timeouts necessary.  This should be checked upon each invocation of select.
  1178.  * If a timeout is received, snmp_timeout should be called to check if the
  1179.  * timeout was for SNMP.  (snmp_timeout is idempotent)
  1180.  *
  1181.  * The value of block indicates how the timeout value is interpreted.
  1182.  * If block is true on input, the timeout value will be treated as undefined,
  1183.  * but it must be available for setting in snmp_select_info.  On return,
  1184.  * block is set to true if the value returned for timeout is undefined;
  1185.  * when block is set to false, timeout may be used as a parmeter to 'select'.
  1186.  *
  1187.  * snmp_select_info returns the number of open sockets.  (i.e. The number of
  1188.  * sessions open)
  1189.  */
  1190. int
  1191. snmp_select_info(int *numfds,
  1192.  fd_set *fdset,
  1193.  struct timeval *timeout,
  1194.  int *block)
  1195.     /* input:  set to 1 if input timeout value is undefined  */
  1196.     /*         set to 0 if input timeout value is defined    */
  1197.     /* output: set to 1 if output timeout value is undefined */
  1198.     /*         set to 0 if output rimeout vlaue id defined   */
  1199. {
  1200.     return snmp_sess_select_info((void *)trapdSessionPtr, numfds, fdset, timeout, block);
  1201. }
  1202. #define timerisset(tvp)  ((tvp)->tv_sec || (tvp)->tv_usec)
  1203. /* Same as snmp_select_info, but works just one session. */
  1204. int
  1205. snmp_sess_select_info(void *sessp,
  1206.       int *numfds,
  1207.       fd_set *fdset,
  1208.       struct timeval *timeout,
  1209.       int *block)
  1210. {
  1211.     struct session_list *slptest = (struct session_list *)sessp;
  1212.     struct session_list *slp, *next=NULL, *prev=NULL;
  1213.     struct snmp_internal_session *isp;
  1214.     struct request_list *rp;
  1215.     struct timeval now, earliest;
  1216.     int timer_set = 0;
  1217.     int active = 0, requests = 0;
  1218.     int next_alarm = 0;
  1219.     timerclear(&earliest);
  1220.     /*
  1221.      * For each request outstanding, add it's socket to the fdset,
  1222.      * and if it is the earliest timeout to expire, mark it as lowest.
  1223.      * If a single session is specified, do just for that session.
  1224.      */
  1225.     if (sessp) slp = slptest; else slp = Sessions;
  1226.     for(; slp; slp = next){
  1227. isp = slp->internal;
  1228.         if (!isp) {
  1229.           DEBUGMSGTL(("sess_select","select fail: closing...n"));
  1230.           continue;  /* close in progress - skip this one */
  1231.         }
  1232. if (isp->sd == -1) {
  1233.     if (sessp == NULL) {
  1234. /* This session was marked for deletion */
  1235.     if ( prev == NULL )
  1236. Sessions = slp->next;
  1237.     else
  1238. prev->next = slp->next;
  1239.     next = slp->next;
  1240.     }
  1241.     snmp_sess_close( slp );
  1242.     continue;
  1243. }
  1244. if ((isp->sd + 1) > *numfds)
  1245.     *numfds = (isp->sd + 1);
  1246. FD_SET(isp->sd, fdset);
  1247. if (isp->requests){
  1248.     /* found another session with outstanding requests */
  1249.     requests++;
  1250.     for(rp = isp->requests; rp; rp = rp->next_request){
  1251. if ((!timerisset(&earliest)
  1252.     || (timercmp(&rp->expire, &earliest, <))))
  1253.     earliest = rp->expire;
  1254.     }
  1255. }
  1256.         if (isp->newpkt) {
  1257.           /* don't block at all, more data waiting to be processed */
  1258.           DEBUGMSGTL(("sess_select","more data in buffer, not blockingn"));
  1259.           requests++;
  1260.           timer_set = 1;
  1261.           *block = 0;
  1262.         }
  1263. active++;
  1264. if (slp == slptest) break;
  1265. prev = slp;
  1266. next = slp->next;
  1267.     }
  1268.     if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_ALARM_DONT_USE_SIG)) {
  1269.       next_alarm = get_next_alarm_delay_time();
  1270.     }
  1271.     if (next_alarm == 0 && requests == 0) { /* if none are active, skip arithmetic */
  1272.        *block = 1; /* can block - timeout value is undefined if no requests*/
  1273. return active;
  1274.     }
  1275.     /*
  1276.      * Now find out how much time until the earliest timeout.  This
  1277.      * transforms earliest from an absolute time into a delta time, the
  1278.      * time left until the select should timeout.
  1279.      */
  1280.     gettimeofday(&now,(struct timezone *)0);
  1281.     /*Now = now;*/
  1282.     if (next_alarm != 0 && earliest.tv_sec > next_alarm) {
  1283.       earliest.tv_sec = next_alarm;
  1284.       earliest.tv_usec = 0;
  1285.     }
  1286.     if (timer_set || earliest.tv_sec < now.tv_sec) {
  1287.        earliest.tv_sec  = 0;
  1288.        earliest.tv_usec = 100;
  1289.     }
  1290.     else if (earliest.tv_sec == now.tv_sec) {
  1291.        earliest.tv_sec  = 0;
  1292.        earliest.tv_usec = (earliest.tv_usec - now.tv_usec);
  1293.        if (earliest.tv_usec < 0) {
  1294.           earliest.tv_usec = 100;
  1295.        }
  1296.     }
  1297.     else {
  1298.        earliest.tv_sec  = (earliest.tv_sec  - now.tv_sec);
  1299.        earliest.tv_usec = (earliest.tv_usec - now.tv_usec);
  1300.        if (earliest.tv_usec < 0) {
  1301.           earliest.tv_sec --;
  1302.           earliest.tv_usec = (1000000L + earliest.tv_usec);
  1303.        }
  1304.     }
  1305.     /* if it was blocking before or our delta time is less, reset timeout */
  1306.     if ((*block || (timercmp(&earliest, timeout, <)))){
  1307. *timeout = earliest;
  1308. *block = 0;
  1309.     }
  1310.     return active;
  1311. }
  1312. /*
  1313.  * snmp_timeout should be called whenever the timeout from snmp_select_info
  1314.  * expires, but it is idempotent, so snmp_timeout can be polled (probably a
  1315.  * cpu expensive proposition).  snmp_timeout checks to see if any of the
  1316.  * sessions have an outstanding request that has timed out.  If it finds one
  1317.  * (or more), and that pdu has more retries available, a new packet is formed
  1318.  * from the pdu and is resent.  If there are no more retries available, the
  1319.  *  callback for the session is used to alert the user of the timeout.
  1320.  */
  1321. void
  1322. snmp_timeout (void)
  1323. {
  1324.     struct session_list *slp;
  1325.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1326.     for(slp = Sessions; slp; slp = slp->next){
  1327. snmp_sess_timeout((void *)slp);
  1328.     }
  1329.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1330. }
  1331. static int
  1332. snmp_resend_request(struct session_list *slp, struct request_list *rp, 
  1333.     int incr_retries)
  1334. {
  1335.   u_char  packet[PACKET_LENGTH];
  1336.   size_t length = PACKET_LENGTH;
  1337.   struct timeval tv;
  1338.   struct snmp_session *sp;
  1339.   struct snmp_internal_session *isp;
  1340.   struct timeval now;
  1341.   int result, addr_size;
  1342.   sp = slp->session; isp = slp->internal;
  1343.   if (!sp || !isp) {
  1344.       DEBUGMSGTL(("sess_read","resend fail: closing...n"));
  1345.       return 0;
  1346.   }
  1347.   if (incr_retries) rp->retries++;
  1348.   /* always increment msgId for resent messages */
  1349.   rp->pdu->msgid = rp->message_id = snmp_get_next_msgid();
  1350.   /* retransmit this pdu */
  1351.   if (snmp_build(sp, rp->pdu, packet, &length) < 0){
  1352.     /* this should never happen */
  1353.     return -1;
  1354.   }
  1355.   if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET)){
  1356.     struct soaddr_in *pduIp;
  1357.     pduIp = (struct soaddr_in *)&(rp->pdu->address);
  1358.     snmp_log(LOG_DEBUG, "nResending %d bytes to %s:%hun", length,
  1359.    inet_ntoa(pduIp->sin_addr), ntohs(pduIp->sin_port));
  1360.     xdump(packet, length, "");
  1361.   }
  1362.     addr_size = snmp_socket_length(rp->pdu->address.sa_family);
  1363.     /*fanghao(A):2005-06-17*/
  1364. #ifndef SWITCH
  1365. if(sp->vrfname[0]){
  1366. if(so_bind_udp_vrf_byname(isp->sd,sp->vrfname,0) < 0){
  1367. sp->s_snmp_errno = SNMPERR_BIND_VRF;
  1368. sp->s_errno = errno;
  1369. return 0;
  1370. }
  1371. }else if(sp->vrfid !=0){
  1372. if( so_bind_udp_vrf_byid(isp->sd, (unsigned long)sp->vrfid, 0) ){
  1373. sp->s_snmp_errno = SNMPERR_BIND_VRF;
  1374. sp->s_errno = errno;
  1375. return 0;
  1376. }
  1377. }
  1378. #endif
  1379.   result = so_sendto(isp->sd, (char *)packet, length, 0,
  1380.      (struct soaddr *)&rp->pdu->address, addr_size);
  1381.   
  1382.     /*fanghao(A):2005-06-17*/
  1383.    #ifndef SWITCH
  1384.     addr_size = snmp_socket_length(isp->me.sa_family);
  1385.     if (udp_bind_localaddr(isp->sd, (struct soaddr *)&isp->me, addr_size) != 0){
  1386.         sp->s_snmp_errno = SNMPERR_BAD_LOCPORT;
  1387.         sp->s_errno = errno;
  1388.         snmp_set_detail(strerror(errno));
  1389.         snmp_sess_close(slp);
  1390.         return 0;
  1391.     }
  1392.   #endif
  1393.   
  1394.   if ( result < 0){
  1395.     sp->s_snmp_errno = SNMPERR_BAD_SENDTO;
  1396.     sp->s_errno = errno;
  1397.     snmp_set_detail(strerror(errno));
  1398.     return -1;
  1399.   }
  1400.   else {
  1401.     gettimeofday(&now, (struct timezone *)0);
  1402.     tv = now;
  1403.     rp->time = tv;
  1404.     tv.tv_usec += rp->timeout;
  1405.     tv.tv_sec += tv.tv_usec / 1000000L;
  1406.     tv.tv_usec %= 1000000L;
  1407.     rp->expire = tv;
  1408.   }
  1409.   return 0;
  1410. }
  1411. void
  1412. snmp_sess_timeout(void *sessp)
  1413. {
  1414.     struct session_list *slp = (struct session_list*)sessp;
  1415.     struct snmp_session *sp;
  1416.     struct snmp_internal_session *isp;
  1417.     struct request_list *rp, *orp = NULL, *freeme = NULL;
  1418.     struct timeval now;
  1419.     snmp_callback callback;
  1420.     void *magic;
  1421.     sp = slp->session; isp = slp->internal;
  1422.     if (!sp || !isp) {
  1423.       DEBUGMSGTL(("sess_read","timeout fail: closing...n"));
  1424.       return;
  1425.     }
  1426.     gettimeofday(&now,(struct timezone *)0);
  1427.     /*
  1428.      * For each request outstanding, check to see if it has expired.
  1429.      */
  1430.     for(rp = isp->requests; rp; rp = rp->next_request){
  1431.         if (freeme != NULL){
  1432.      /* frees rp's after the for loop goes on to the next_request */
  1433.      free(freeme);
  1434.      freeme = NULL;
  1435.         }
  1436.         if ((timercmp(&rp->expire, &now, <))){
  1437.      /* this timer has expired */
  1438.      if (rp->retries >= sp->retries){
  1439.             if (rp->callback) {
  1440.               callback = rp->callback;
  1441.               magic = rp->cb_data;
  1442.             } else {
  1443.               callback = sp->callback;
  1444.               magic = sp->callback_magic;
  1445.             }
  1446.          /* No more chances, delete this entry */
  1447.          if (callback)
  1448. callback(TIMED_OUT, sp, rp->pdu->reqid, rp->pdu, magic);
  1449.          if (isp->requests == rp){
  1450.      isp->requests = rp->next_request;
  1451.      if (isp->requestsEnd == rp)
  1452.          isp->requestsEnd = NULL;
  1453.          } else {
  1454.      orp->next_request = rp->next_request;
  1455.      if (isp->requestsEnd == rp)
  1456.          isp->requestsEnd = orp;
  1457.          }
  1458.          snmp_free_pdu(rp->pdu); /* FIX  rp is already free'd! */
  1459.          freeme = rp;
  1460.          continue; /* don't update orp below */
  1461.      } else {
  1462.   if (snmp_resend_request(slp, rp, TRUE)) break;
  1463.      }
  1464.         }
  1465.         orp = rp;
  1466.     }
  1467.     if (freeme != NULL){
  1468.         free(freeme);
  1469.         freeme = NULL;
  1470.     }
  1471. }
  1472. /* lexicographical compare two object identifiers.
  1473.  * Returns -1 if name1 < name2,
  1474.  *          0 if name1 = name2,
  1475.  *          1 if name1 > name2
  1476.  *
  1477.  * Caution: this method is called often by
  1478.  *          command responder applications (ie, agent).
  1479.  */
  1480. int
  1481. snmp_oid_compare(const oid *in_name1, 
  1482.  size_t len1,
  1483.  const oid *in_name2, 
  1484.  size_t len2)
  1485. {
  1486.     register int len, res;
  1487.     register const oid * name1 = in_name1;
  1488.     register const oid * name2 = in_name2;
  1489.     /* len = minimum of len1 and len2 */
  1490.     if (len1 < len2)
  1491. len = len1;
  1492.     else
  1493. len = len2;
  1494.     /* find first non-matching OID */
  1495.     while(len-- > 0){
  1496. res = *(name1++) - *(name2++);
  1497. if (res < 0)
  1498.     return -1;
  1499. if (res > 0)
  1500.     return 1;
  1501.     }
  1502.     /* both OIDs equal up to length of shorter OID */
  1503.     if (len1 < len2)
  1504. return -1;
  1505.     if (len2 < len1)
  1506. return 1;
  1507.     return 0;
  1508. }
  1509. /*
  1510.  * Add a variable with the requested name to the end of the list of
  1511.  * variables for this pdu.
  1512.  */
  1513. struct variable_list *
  1514. snmp_pdu_add_variable(struct snmp_pdu *pdu,
  1515.       oid *name,
  1516.       size_t name_length,
  1517.       u_char type,
  1518.       u_char *value,
  1519.       size_t len)
  1520. {
  1521.   return snmp_varlist_add_variable(&pdu->variables, name, name_length, type,
  1522.                                    value, len);
  1523. }
  1524. /*
  1525.  * Add a variable with the requested name to the end of the list of
  1526.  * variables for this pdu.
  1527.  */
  1528. struct variable_list *
  1529. snmp_varlist_add_variable(struct variable_list **varlist,
  1530.       oid *name,
  1531.       size_t name_length,
  1532.       u_char type,
  1533.       u_char *value,
  1534.       size_t len)
  1535. {
  1536.     struct variable_list *vars, *vtmp;
  1537.     int largeval = 1;
  1538.     if (varlist == NULL)
  1539.       return NULL;
  1540.     vars = (struct variable_list *)malloc(sizeof(struct variable_list));
  1541.     if (vars == NULL)
  1542.       return NULL;
  1543.     vars->next_variable = 0; vars->name = 0; vars->val.string = 0;
  1544.     /* use built-in storage for smaller values */
  1545.     if (len <= sizeof(vars->buf)) {
  1546.         vars->val.string = (u_char *)vars->buf;
  1547.         largeval = 0;
  1548.     }
  1549.     vars->type = type;
  1550.     vars->val_len = len;
  1551.     switch(type){
  1552.       case ASN_INTEGER:
  1553.       case ASN_UNSIGNED:
  1554.       case ASN_TIMETICKS:
  1555.       case ASN_IPADDRESS:
  1556.       case ASN_COUNTER:
  1557.         memmove(vars->val.integer, value, vars->val_len);
  1558.         vars->val_len = sizeof(long);
  1559.         break;
  1560.       case ASN_OBJECT_ID:
  1561.       case ASN_PRIV_INCL_RANGE:
  1562.       case ASN_PRIV_EXCL_RANGE:
  1563.         if (largeval) {
  1564.             vars->val.objid = (oid *)malloc(vars->val_len);
  1565. if (vars->val.objid == NULL)
  1566. {
  1567. snmp_free_var (vars);
  1568. return NULL;
  1569. }
  1570.         }
  1571.         memmove(vars->val.objid, value, vars->val_len);
  1572.         break;
  1573.       case ASN_OCTET_STR:
  1574.       case ASN_OPAQUE:
  1575.       case ASN_NSAP:
  1576.         if (largeval) {
  1577.             vars->val.string = (u_char *)malloc(vars->val_len);
  1578. if (vars->val.string == NULL)
  1579. {
  1580. snmp_free_var(vars);
  1581. return NULL;
  1582. }
  1583.         }
  1584.         memmove(vars->val.string, value, vars->val_len);
  1585.         break;
  1586.       case SNMP_NOSUCHOBJECT:
  1587.       case SNMP_NOSUCHINSTANCE:
  1588.       case SNMP_ENDOFMIBVIEW:
  1589.       case ASN_NULL:
  1590.         vars->val_len = 0;
  1591.         vars->val.string = NULL;
  1592.         break;
  1593. #ifdef OPAQUE_SPECIAL_TYPES
  1594.       case ASN_OPAQUE_U64:
  1595.       case ASN_OPAQUE_I64:
  1596. #endif /* OPAQUE_SPECIAL_TYPES */
  1597.       case ASN_COUNTER64:
  1598.         vars->val_len = sizeof(struct counter64);
  1599.         memmove(vars->val.counter64, value, vars->val_len);
  1600.         break;
  1601. #ifdef OPAQUE_SPECIAL_TYPES
  1602.       case ASN_OPAQUE_FLOAT:
  1603.         vars->val_len = sizeof(float);
  1604.         memmove(vars->val.floatVal, value, vars->val_len);
  1605.         break;
  1606.       
  1607.       case ASN_OPAQUE_DOUBLE:
  1608.         vars->val_len = sizeof(double);
  1609.         memmove(vars->val.doubleVal, value, vars->val_len);
  1610. #endif /* OPAQUE_SPECIAL_TYPES */
  1611.       
  1612.       default:
  1613.         snmp_set_detail("Internal error in type switchingn");
  1614.         snmp_free_var(vars);
  1615.         return (0);
  1616.     }
  1617.     if (name != NULL && snmp_set_var_objid(vars, name, name_length)) {
  1618.         snmp_free_var(vars);
  1619.         return (0);
  1620.     }
  1621.     
  1622.     /* put only qualified variable onto varlist */
  1623.     if (*varlist == NULL){
  1624.       *varlist = vars;
  1625.     } else {
  1626.       for(vtmp = *varlist;
  1627.             vtmp->next_variable;
  1628.             vtmp = vtmp->next_variable)
  1629.         ;
  1630.       vtmp->next_variable = vars;
  1631.     }
  1632. return vars;
  1633. }
  1634. /*
  1635.  * Parses dotted notation object identifier
  1636.  * into unsigned character array.
  1637.  * Returns: SNMPERR_RANGE if any sub-identifier > 255.
  1638.  * Returns: SNMPERR_VALUE if input string is not octet string.
  1639.  * Returns: non-negative number of sub-identifiers parsed,
  1640.  */
  1641. int
  1642. ascii_to_binary(const char *cp,
  1643. u_char *bufp)
  1644. {
  1645.     int  subidentifier;
  1646.     u_char *bp = bufp;
  1647.     for(; *cp != ''; cp++){
  1648.       if (isspace(*cp) || *cp == '.')
  1649.         continue;
  1650.       if (!isdigit(*cp)){
  1651.         return SNMPERR_VALUE;
  1652.       }
  1653.       subidentifier = atoi(cp);
  1654.       if (subidentifier > 255){
  1655.         return SNMPERR_RANGE;
  1656.       }
  1657.       *bp++ = (u_char)subidentifier;
  1658.       while(isdigit(*cp))
  1659.         cp++;
  1660.       cp--;
  1661.     }
  1662.     return bp - bufp;
  1663. }
  1664. int
  1665. hex_to_binary(const char *str,
  1666.       u_char *bufp)
  1667. {
  1668.   int len, itmp;
  1669.   if (!bufp) return -1;
  1670.   if (*str && *str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) str += 2;
  1671.   for (len = 0; *str; str++) {
  1672.     if (isspace(*str)) continue;
  1673.     if (!isxdigit(*str)) return -1;
  1674.     len++;
  1675.     if (sscanf(str++, "%2x", &itmp) == 0) return -1;
  1676.     *bufp++ = (u_char)itmp;
  1677.     if (!*str) return -1; /* odd number of chars is an error */
  1678.   }
  1679.   return len;
  1680. }
  1681. /*
  1682.  * Add a variable with the requested name to the end of the list of
  1683.  * variables for this pdu.
  1684.  * Returns:
  1685.  * may set these error types :
  1686.  * SNMPERR_RANGE - type, value, or length not found or out of range
  1687.  * SNMPERR_VALUE - value is not correct
  1688.  * SNMPERR_BAD_NAME - name is not found
  1689.  *
  1690.  * returns 0 if success, error if failure.
  1691.  */
  1692. int
  1693. snmp_add_var(struct snmp_pdu *pdu,
  1694.      oid *name,
  1695.      size_t name_length,
  1696.      char type,
  1697.      const char *value)
  1698. {
  1699.     int result = 0;
  1700.     u_char buf[SPRINT_MAX_LEN];
  1701.     size_t tint;
  1702.     long ltmp;
  1703.     struct tree *tp;
  1704.     struct enum_list *ep;
  1705. #ifdef UCD_SNMP
  1706.     struct range_list *rp;
  1707. #endif
  1708. #ifdef OPAQUE_SPECIAL_TYPES
  1709.     double dtmp;
  1710.     float ftmp;
  1711.     struct counter64 c64tmp;
  1712. #endif /* OPAQUE_SPECIAL_TYPES */
  1713.     switch(type){
  1714.       case 'i':
  1715. tp = get_tree(name, name_length, get_tree_head());
  1716.         if (sscanf(value, "%ld", &ltmp) != 1) {
  1717.     ep = tp ? tp->enums : NULL;
  1718.     while (ep) {
  1719. if (strcmp(value, ep->label) == 0) {
  1720.     ltmp = ep->value;
  1721.     break;
  1722. }
  1723. ep = ep->next;
  1724.     }
  1725.     if (!ep) {
  1726. result = SNMPERR_BAD_NAME;
  1727. snmp_set_detail(value);
  1728. break;
  1729.     }
  1730. }
  1731. #ifdef UCD_SNMP
  1732. if (tp && tp->ranges && !ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DONT_CHECK_RANGE)) {
  1733.     rp = tp->ranges;
  1734.     while (rp) {
  1735. if (rp->low <= ltmp && ltmp <= rp->high) break;
  1736. rp = rp->next;
  1737.     }
  1738.     if (!rp) {
  1739. result = SNMPERR_RANGE;
  1740. snmp_set_detail("Value");
  1741. break;
  1742.     }
  1743. }
  1744. #endif
  1745. snmp_pdu_add_variable(pdu, name, name_length, ASN_INTEGER,
  1746.                               (u_char *) &ltmp, sizeof(ltmp));
  1747.         break;
  1748.       case 'u':
  1749.         if (sscanf(value, "%lu", &ltmp) == 1)
  1750.     snmp_pdu_add_variable(pdu, name, name_length, ASN_UNSIGNED,
  1751.   (u_char *) &ltmp, sizeof(ltmp));
  1752. else goto fail;
  1753.         break;
  1754.       case 'c':
  1755.         if (sscanf(value, "%lu", &ltmp) == 1)
  1756.     snmp_pdu_add_variable(pdu, name, name_length, ASN_COUNTER,
  1757.   (u_char *) &ltmp, sizeof(ltmp));
  1758. else goto fail;
  1759.         break;
  1760.       case 't':
  1761.         if (sscanf(value, "%lu", &ltmp) == 1)
  1762.     snmp_pdu_add_variable(pdu, name, name_length, ASN_TIMETICKS,
  1763.   (u_char *) &ltmp, sizeof(long));
  1764. else goto fail;
  1765.         break;
  1766.       case 'a':
  1767.         if ((ltmp = inet_addr(value)) != (long)-1)
  1768.     snmp_pdu_add_variable(pdu, name, name_length, ASN_IPADDRESS,
  1769.   (u_char *) &ltmp, sizeof(long));
  1770. else goto fail;
  1771.         break;
  1772.       case 'o':
  1773.         tint = sizeof(buf) / sizeof(oid);
  1774.         if (read_objid(value, (oid *)buf, &tint))
  1775.             snmp_pdu_add_variable(pdu, name, name_length, ASN_OBJECT_ID, buf,
  1776.                               sizeof(oid)*tint);
  1777. else result = snmp_errno;
  1778.         break;
  1779.       case 's':
  1780.       case 'x':
  1781.       case 'd':
  1782.         if (type == 'd'){
  1783.           ltmp = ascii_to_binary(value, buf);
  1784.         } else if (type == 's'){
  1785.           strcpy((char*)buf, value);
  1786.           ltmp = strlen((char*)buf);
  1787.         } else if (type == 'x'){
  1788.           ltmp = hex_to_binary(value, buf);
  1789.         }
  1790.         if (ltmp < 0) {
  1791.           result = SNMPERR_VALUE;
  1792.           snmp_set_detail(value);
  1793.           break;
  1794.         }
  1795. tp = get_tree(name, name_length, get_tree_head());
  1796. #ifdef UCD_SNMP
  1797. if (tp && tp->ranges && !ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DONT_CHECK_RANGE)) {
  1798.     rp = tp->ranges;
  1799.     while (rp) {
  1800. if (rp->low <= ltmp && ltmp <= rp->high) break;
  1801. rp = rp->next;
  1802.     }
  1803.     if (!rp) {
  1804. result = SNMPERR_RANGE;
  1805. snmp_set_detail("Length");
  1806. break;
  1807.     }
  1808. }
  1809. #endif
  1810.         snmp_pdu_add_variable(pdu, name, name_length, ASN_OCTET_STR, buf, ltmp);
  1811.         break;
  1812.       case 'n':
  1813.         snmp_pdu_add_variable(pdu, name, name_length, ASN_NULL, 0, 0);
  1814.         break;
  1815. #ifdef OPAQUE_SPECIAL_TYPES
  1816.       case 'U':
  1817.         if (read64(&c64tmp, value))
  1818.     snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_U64,
  1819.   (u_char *) &c64tmp, sizeof(c64tmp));
  1820. else goto fail;
  1821.         break;
  1822.       case 'I':
  1823.         if (read64(&c64tmp, value))
  1824.     snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_I64,
  1825.   (u_char *) &c64tmp, sizeof(c64tmp));
  1826. else goto fail;
  1827.         break;
  1828.       case 'F':
  1829. if (sscanf(value, "%f", &ftmp) == 1)
  1830.     snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_FLOAT, 
  1831.   (u_char *) &ftmp, sizeof(ftmp));
  1832. else goto fail;
  1833.         break;
  1834.       case 'D':
  1835. if (sscanf(value, "%lf", &dtmp) == 1)
  1836.     snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_DOUBLE,
  1837.   (u_char *) &dtmp, sizeof(dtmp));
  1838. else goto fail;
  1839.         break;
  1840. #endif /* OPAQUE_SPECIAL_TYPES */
  1841.       default:
  1842. result = SNMPERR_VAR_TYPE;
  1843. sprintf((char *)buf, "%c", type);
  1844. snmp_set_detail((const char *)buf);
  1845.         break;
  1846.     }
  1847.     SET_SNMP_ERROR(result);
  1848.     return result;
  1849. fail:
  1850.     result = SNMPERR_VALUE;
  1851.     snmp_set_detail(value);
  1852.     SET_SNMP_ERROR(result);
  1853.     return result;
  1854. }
  1855. /*
  1856.  * returns NULL or internal pointer to session
  1857.  * use this pointer for the other snmp_sess* routines,
  1858.  * which guarantee action will occur ONLY for this given session.
  1859.  */
  1860. void *
  1861. snmp_sess_pointer(struct snmp_session *session)
  1862. {
  1863.     struct session_list *slp;
  1864.     snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1865.     for(slp = Sessions; slp; slp = slp->next){
  1866. if (slp->session == session){
  1867.     break;
  1868. }
  1869.     }
  1870.     snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
  1871.     if (slp == NULL){
  1872. snmp_errno = SNMPERR_BAD_SESSION; /*MTCRITICAL_RESOURCE*/
  1873. return(NULL);
  1874.     }
  1875.     return((void *)slp);
  1876. }
  1877. /*
  1878.  * Input : an opaque pointer, returned by snmp_sess_open.
  1879.  * returns NULL or pointer to session.
  1880.  */
  1881. struct snmp_session *
  1882. snmp_sess_session(void *sessp)
  1883. {
  1884.     struct session_list *slp = (struct session_list *)sessp;
  1885.     if (slp == NULL) return(NULL);
  1886.     return (slp->session);
  1887. }
  1888. #ifdef CMU_COMPATIBLE
  1889. char *
  1890. snmp_pdu_type(struct snmp_pdu *PDU)
  1891. {
  1892.   switch(PDU->command) {
  1893.   case SNMP_MSG_GET:
  1894.     return("GET");
  1895.     break;
  1896.   case SNMP_MSG_GETNEXT:
  1897.     return("GETNEXT");
  1898.     break;
  1899.   case SNMP_MSG_RESPONSE:
  1900.     return("RESPONSE");
  1901.     break;
  1902.   case SNMP_MSG_SET:
  1903.     return("SET");
  1904.     break;
  1905.   case SNMP_MSG_GETBULK:
  1906.     return("GETBULK");
  1907.     break;
  1908.   case SNMP_MSG_INFORM:
  1909.     return("INFORM");
  1910.     break;
  1911.   case SNMP_MSG_TRAP2:
  1912.     return("V2TRAP");
  1913.     break;
  1914.   case SNMP_MSG_REPORT:
  1915.     return("REPORT");
  1916.     break;
  1917.     
  1918.   case SNMP_MSG_TRAP:
  1919.     return("V1TRAP");
  1920.     break;
  1921.   default:
  1922.     return("Unknown");
  1923.     break;
  1924.   }
  1925. }
  1926. /*
  1927.  * cmu_snmp_parse - emulate CMU library's snmp_parse.
  1928.  *
  1929.  * Parse packet, storing results into PDU.
  1930.  * Returns community string if success, NULL if fail.
  1931.  * WARNING: may return a zero length community string.
  1932.  *
  1933.  * Note:
  1934.  * Some CMU-aware apps call init_mib(), but do not
  1935.  * initialize a session.
  1936.  * Check Reqid to make sure that this module is initialized.
  1937.  */
  1938. u_char *
  1939. cmu_snmp_parse (struct snmp_session *session,
  1940.     struct snmp_pdu *pdu,
  1941.     u_char *data,
  1942.     size_t length)
  1943. {
  1944.     u_char *bufp = NULL;
  1945.     if (Reqid == 0) {
  1946. snmp_sess_init(session); /* gimme a break! */
  1947.     }
  1948.     switch(pdu->version) {
  1949.     case SNMP_VERSION_1:
  1950.     case SNMP_VERSION_2c:
  1951.     case SNMP_DEFAULT_VERSION:
  1952.     break;
  1953.     default:
  1954.     return NULL;
  1955.     }
  1956. #ifndef NO_INTERNAL_VARLIST
  1957.     if (snmp_parse( 0, session, pdu, data, length) != SNMP_ERR_NOERROR){
  1958. return NULL;
  1959.     }
  1960. #else
  1961. /*
  1962.  * while there are two versions of variable_list:
  1963.  * use an internal variable list for snmp_parse;
  1964.  * clone the result.
  1965.  */
  1966. if (1) {
  1967. struct snmp_pdu *snmp_clone_pdu (struct snmp_pdu *);
  1968. struct snmp_pdu *snmp_2clone_pdu(struct snmp_pdu *from_pdu, struct snmp_pdu *to_pdu);
  1969.     struct snmp_pdu *ipdu;
  1970.     ipdu = snmp_clone_pdu(pdu);
  1971.     if (snmp_parse( 0, session, ipdu, data, length) != SNMP_ERR_NOERROR){
  1972. snmp_free_internal_pdu(ipdu);
  1973. return NULL;
  1974.     }
  1975.     pdu = snmp_2clone_pdu(ipdu, pdu);
  1976.     snmp_free_internal_pdu(ipdu);
  1977. }
  1978. #endif /* NO_INTERNAL_VAR_LIST */
  1979.     /* Add a null to meet the caller's expectations. */
  1980.     bufp = (u_char *)malloc(1+pdu->community_len);
  1981.     if (bufp && pdu->community_len) {
  1982. memcpy(bufp, pdu->community, pdu->community_len);
  1983. bufp[pdu->community_len] = '';
  1984.     }
  1985.     return(bufp);
  1986. }
  1987. #endif /* CMU_COMPATIBLE */
  1988. /* snmp_duplicate_objid: duplicates (mallocs) an objid based on the
  1989.    input objid */
  1990. oid *
  1991. snmp_duplicate_objid(oid *objToCopy, size_t objToCopyLen)
  1992. {
  1993.   oid *returnOid;
  1994.   returnOid = (oid *) malloc(objToCopyLen*sizeof(oid));
  1995.   if (returnOid) {
  1996.     memmove(returnOid, objToCopy, objToCopyLen*sizeof(oid));
  1997.   }
  1998.   return returnOid;
  1999. }
  2000. /* generic statistics counter functions */
  2001. static u_int statistics[MAX_STATS];
  2002. u_int
  2003. snmp_increment_statistic(int which)
  2004. {
  2005.   if (which >= 0 && which < MAX_STATS) {
  2006.     statistics[which]++;
  2007.     return statistics[which];
  2008.   }
  2009.   return 0;
  2010. }
  2011. u_int
  2012. snmp_increment_statistic_by(int which, int count)
  2013. {
  2014.   if (which >= 0 && which < MAX_STATS) {
  2015.     statistics[which] += count;
  2016.     return statistics[which];
  2017.   }
  2018.   return 0;
  2019. }
  2020. u_int
  2021. snmp_get_statistic(int which)
  2022. {
  2023.   if (which >= 0 && which < MAX_STATS)
  2024.   {
  2025.    if (which == STAT_SNMPINTOTALREQVARS)
  2026.      return  (statistics[STAT_SNMPINGETREQUESTS] + statistics[STAT_SNMPINGETNEXTS]);
  2027.      if (which == STAT_SNMPINTOTALSETVARS)
  2028.      return statistics[STAT_SNMPINSETREQUESTS];
  2029.      return statistics[which];
  2030.   }
  2031.   return 0;
  2032. }
  2033. void
  2034. snmp_init_statistics(void)
  2035. {
  2036.   memset(statistics, 0, sizeof(statistics));
  2037. }
  2038. /* returns the length of a socket structure */
  2039. size_t snmp_socket_length( int family)
  2040. {
  2041.   size_t length;
  2042.   switch (family)
  2043.     {
  2044. #ifdef UCD_SNMP
  2045. #ifndef cygwin
  2046. #ifndef WIN32
  2047. #ifdef AF_UNIX
  2048.     case AF_UNIX:
  2049.       length = sizeof (struct sockaddr_un);
  2050.       break;
  2051. #endif /* AF_UNIX */
  2052. #endif
  2053. #endif
  2054. #ifndef aix3
  2055. #ifdef AF_LINK
  2056.     case AF_LINK:
  2057. #ifdef _MAX_SA_LEN
  2058.       length = _MAX_SA_LEN;
  2059. #elif SOCK_MAXADDRLEN
  2060.       length = SOCK_MAXADDRLEN;
  2061. #else
  2062.       length = sizeof (struct sockaddr_dl);
  2063. #endif
  2064.       break;
  2065. #endif /* AF_LINK */
  2066. #endif
  2067. #endif
  2068.     case AF_INET:
  2069.       length = sizeof (struct soaddr_in);
  2070.       break;
  2071.     default:
  2072.       length = sizeof (struct soaddr);
  2073.       break;
  2074.     }
  2075.     return length;
  2076. }
  2077. /*
  2078.  * For compatibility with applications built using
  2079.  * previous versions only.
  2080.  */
  2081. /* use <struct snmp_session *)->s_snmp_errno instead */
  2082. int  snmp_get_errno   (void)  { return SNMPERR_SUCCESS; }
  2083. /* synch_reset and synch_setup are no longer used. */
  2084. void snmp_synch_reset (struct snmp_session * notused) {}
  2085. void snmp_synch_setup (struct snmp_session * notused) {}
  2086. /* provide for backwards compatibility */
  2087. void
  2088. snmp_set_dump_packet(int x) {
  2089.     ds_set_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET, x);
  2090. }
  2091. int
  2092. snmp_get_dump_packet(void) {
  2093.     return ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET);
  2094. }
  2095. void
  2096. snmp_set_quick_print(int x) {
  2097.     ds_set_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT, x);
  2098. }
  2099.   
  2100. int
  2101. snmp_get_quick_print(void) {
  2102.     return ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT);
  2103. }
  2104.  
  2105. void
  2106. snmp_set_suffix_only(int x) {
  2107.     ds_set_int(DS_LIBRARY_ID, DS_LIB_PRINT_SUFFIX_ONLY, x);
  2108. }
  2109.   
  2110. int
  2111. snmp_get_suffix_only(void) {
  2112.     return ds_get_int(DS_LIBRARY_ID, DS_LIB_PRINT_SUFFIX_ONLY);
  2113. }
  2114.  
  2115. void
  2116. snmp_set_full_objid(int x) {
  2117.       ds_set_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_FULL_OID, x);
  2118. }
  2119. int
  2120. snmp_get_full_objid(void) {
  2121.     return ds_get_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_SUFFIX_ONLY);
  2122. }
  2123.  
  2124. void
  2125. snmp_set_random_access(int x) {
  2126.     ds_set_boolean(DS_LIBRARY_ID, DS_LIB_RANDOM_ACCESS, x);
  2127. }
  2128.  
  2129. int
  2130. snmp_get_random_access(void) {
  2131.     return ds_get_boolean(DS_LIBRARY_ID, DS_LIB_RANDOM_ACCESS);
  2132. }
  2133. int change_session_localaddr(struct snmp_session *session,DEVICE_ETERNAL_ID ID)
  2134. {
  2135.     struct session_list *slp;
  2136.     struct snmp_internal_session *isp = NULL;
  2137. struct soaddr_in locname;
  2138. int namelen=sizeof(struct soaddr_in);
  2139. /*** sun define 2000.03.21 ***/
  2140. /* struct soaddr_intf  sin;  */
  2141. int ret;
  2142. /*** sun define end ***/
  2143.     for(slp = Sessions; slp; slp = slp->next){
  2144. if (slp->session == session){
  2145. isp = slp->internal;
  2146. break;
  2147. }
  2148.     }
  2149.     if (isp == NULL){
  2150. snmp_errno = SNMPERR_BAD_SESSION;
  2151. snmp_trace("isp==nulln");
  2152. return snmp_errno;
  2153.     }
  2154. if(so_getsockname(isp->sd,(struct soaddr*)&locname,&namelen)){
  2155. snmp_errno = SNMPERR_BAD_SESSION;
  2156. snmp_trace("so_getsockname failn");
  2157. return snmp_errno;
  2158. }
  2159. if(namelen==0){/*not bind*/
  2160. snmp_trace("namelen==0n");
  2161. return -1;
  2162. }
  2163. if((ret =bind_intf(isp->sd, ID))!=0)
  2164. {
  2165. snmp_trace("bind_intf error %dn",ret);
  2166. return -1;
  2167. }
  2168. return 0;
  2169. }
  2170. int change_session_sourceaddr(uint32 source_ip_addr)
  2171. {
  2172.     struct session_list *slp;
  2173.     struct snmp_internal_session *isp = NULL;
  2174.     struct snmp_session *session;
  2175.     int len;
  2176.     int rc;
  2177.     int sd;
  2178.     fd_set fdset;
  2179.     struct soaddr_in snmp_sour_addr;
  2180.     for(slp = Sessions; slp; slp = slp->next){
  2181. if (slp==NULL) break;
  2182. isp     = slp->internal;
  2183.      session = slp->session;
  2184. if (so_getsockname(isp->sd, (struct soaddr *) &snmp_sour_addr, &len) < 0) {
  2185.      vty_output("Can not get source addrn");
  2186.  return -1;
  2187. }
  2188. if (isp->sd >=0 ) 
  2189. {
  2190. int numfds;
  2191. struct timeval timeout, *tvp;
  2192. int block;
  2193. tvp =  &timeout;
  2194. tvp->tv_sec = 0;
  2195. tvp->tv_usec = 0;
  2196. numfds = 0;
  2197. FD_ZERO(&fdset);
  2198. block = 0;
  2199. sd = so_socket(AF_INET, SOCK_DGRAM, 0);
  2200. if (sd < 0){
  2201. session->s_snmp_errno = SNMPERR_NO_SOCKET;
  2202. session->s_errno = errno;
  2203. snmp_set_detail(strerror(errno));
  2204. return -1;
  2205.      }
  2206. snmp_sess_select_info(NULL, &numfds, &fdset, tvp, &block);
  2207. if (FD_ISSET(isp->sd, &fdset)) 
  2208. {
  2209.    FD_CLR(isp->sd, &fdset);
  2210. so_close(isp->sd);
  2211. isp->sd =-1;
  2212. }
  2213. isp->sd = sd;
  2214. FD_SET(isp->sd, &fdset);
  2215. snmp_sour_addr.sin_addr.s_addr= htonl(source_ip_addr);
  2216. rc= so_bind(isp->sd, (struct soaddr *)&snmp_sour_addr, sizeof(struct soaddr_in));
  2217. if (rc!= 0)
  2218. {  
  2219. vty_output("bind source  ip fail!n");  
  2220. session->s_snmp_errno = SNMPERR_BAD_LOCPORT;
  2221. session->s_errno = errno;
  2222. snmp_set_detail(strerror(errno));
  2223. return -1;
  2224. }
  2225. }
  2226.     }
  2227. return 0;
  2228. }
  2229. /*
  2230.  * get the current communitiy, used only in SNMP task
  2231.  */
  2232. const char * snmp_get_current_community()
  2233. {
  2234. return snmp_current_community;
  2235. }
  2236. void SNMP_ENTERPRISE_MODIFY(oid * oid_array, size_t arr_len)  
  2237. {
  2238. assert(NULL != oid_array);
  2239. if ((arr_len >= 6) && (oid_array[0] == 1) && (oid_array[1] == 3) && (oid_array[2] == 6) && (oid_array[3] == 1)
  2240.    && (oid_array[4] == 4) && (oid_array[5] == 1) )
  2241.    {
  2242. if (eprom_extend() && eprom_oem())
  2243. {
  2244. if (ENTERPRISE_NUMBER == default_enterprise[6])  
  2245. oid_array[6] = eprom_vendor_id();
  2246. else
  2247. oid_array[6] = default_enterprise[6];
  2248. #if 0
  2249. Print("SNMP REGISTER OID = %d.%d.%d.%d.%d.%d.%d.%dn",oid_array[0],oid_array[1]
  2250. ,oid_array[2],oid_array[3],oid_array[4],oid_array[5],oid_array[6],oid_array[7]);
  2251. #endif
  2252. }
  2253. }