예제 #1
0
int snmp_msg_write(pool *p, unsigned char **buf, size_t *buflen,
    char *community, unsigned int community_len, long snmp_version,
    struct snmp_pdu *pdu) {
  unsigned char asn1_type;
  unsigned int asn1_len;
  unsigned char *msg_ptr, *msg_hdr_start, *msg_hdr_end;
  size_t msg_hdr_startlen, msg_len;
  int res;

  if (p == NULL ||
      buf == NULL ||
      buflen == NULL ||
      community == NULL ||
      pdu == NULL) {
    errno = EINVAL;
    return -1;
  }

  msg_ptr = msg_hdr_start = *buf;
  msg_hdr_startlen = *buflen;

  asn1_type = (SNMP_ASN1_TYPE_SEQUENCE|SNMP_ASN1_CONSTRUCT);
  asn1_len = 0;

  res = snmp_asn1_write_header(p, buf, buflen, asn1_type, asn1_len, 0);
  if (res < 0) {
    return -1;
  }

  msg_hdr_end = *buf;

  asn1_type = (SNMP_ASN1_CLASS_UNIVERSAL|SNMP_ASN1_PRIMITIVE|SNMP_ASN1_TYPE_INTEGER);
  res = snmp_asn1_write_int(p, buf, buflen, asn1_type, snmp_version, 0);
  if (res < 0) {
    return -1;
  }

  asn1_type = (SNMP_ASN1_CLASS_UNIVERSAL|SNMP_ASN1_PRIMITIVE|SNMP_ASN1_TYPE_OCTETSTRING);
  res = snmp_asn1_write_string(p, buf, buflen, asn1_type, community,
    community_len);
  if (res < 0) {
    return -1;
  }

  if (pdu != NULL) {
    res = snmp_pdu_write(p, buf, buflen, pdu, snmp_version);
    if (res < 0) {
      return -1;
    }
  }

  /* Calculate the full message length, for use later. */
  msg_len = (*buf - msg_hdr_start);

  /* Having written out the entire message now, we can go back and fill
   * in the appropriate length in the header.
   */

  asn1_type = (SNMP_ASN1_TYPE_SEQUENCE|SNMP_ASN1_CONSTRUCT);
  asn1_len = (*buf - msg_hdr_end);
  
  pr_trace_msg(trace_channel, 18,
    "updating SNMP message header to have length %u", asn1_len);

  res = snmp_asn1_write_header(p, &msg_hdr_start, &msg_hdr_startlen,
    asn1_type, asn1_len, 0);
  if (res < 0) {
    return -1;
  }

  /* XXX This is a bit of a hack here.  We started with a buflen, and steadily
   * decremented that value as we wrote data into the buffer.
   *
   * However, buflen needs to the amount of data IN the buffer once we return
   * the caller, NOT the amount of data REMAINING in the buffer.  So we
   * cheat here.
   *
   * We also cheat by resetting buf to point to the start of the message.
   */

  *buflen = msg_len;
  *buf = msg_ptr;

  return 0;
}
예제 #2
0
파일: pdu.c 프로젝트: Nakor78/proftpd
int snmp_pdu_write(pool *p, unsigned char **buf, size_t *buflen,
    struct snmp_pdu *pdu, long snmp_version) {
  unsigned char asn1_type, *pdu_hdr_start, *pdu_hdr_end;
  size_t pdu_hdr_startlen;
  unsigned int asn1_len;
  int flags, res;

  pr_trace_msg(trace_channel, 19,
    "writing %s PDU (0x%02x)",
    snmp_pdu_get_request_type_desc(pdu->request_type), pdu->request_type);

  /* Since the "type" in this header is the PDU request type, the trace logging
   * of the ASN.1 type will be wrong.  That being the case, simply tell the
   * writers to not trace log that wrong invalid ASN.1 type.  Makes the
   * trace logging confusing and incorrect.
   */
  flags = SNMP_ASN1_FL_NO_TRACE_TYPESTR;

  asn1_type = pdu->request_type;
  asn1_len = 0;

  pdu_hdr_start = *buf;
  pdu_hdr_startlen = *buflen;

  res = snmp_asn1_write_header(p, buf, buflen, asn1_type, asn1_len, flags);
  if (res < 0) {
    return -1;
  }

  pdu_hdr_end = *buf;

  switch (pdu->request_type) {
    case SNMP_PDU_GETBULK:
      asn1_type = (SNMP_ASN1_CLASS_UNIVERSAL|SNMP_ASN1_PRIMITIVE|SNMP_ASN1_TYPE_INTEGER);

      /* Request ID */
      pr_trace_msg(trace_channel, 19,
        "writing PDU request ID: %ld", pdu->request_id);
      res = snmp_asn1_write_int(p, buf, buflen, asn1_type, pdu->request_id, 0);
      if (res < 0) {
        return -1;
      }

      /* Non-repeaters */
      pr_trace_msg(trace_channel, 19,
        "writing PDU non-repeaters: %ld", pdu->non_repeaters);
      res = snmp_asn1_write_int(p, buf, buflen, asn1_type,
        pdu->non_repeaters, 0);
      if (res < 0) {
        return -1;
      }

      /* Max-repetitions */
      pr_trace_msg(trace_channel, 19,
        "writing PDU max-repetitions: %ld", pdu->max_repetitions);
      res = snmp_asn1_write_int(p, buf, buflen, asn1_type,
        pdu->max_repetitions, 0);
      if (res < 0) {
        return -1;
      }

      /* XXX write varlist? */

      break;

    default:
      /* "Normal" PDU formatting. */

      asn1_type = (SNMP_ASN1_CLASS_UNIVERSAL|SNMP_ASN1_PRIMITIVE|SNMP_ASN1_TYPE_INTEGER);

      /* Request ID */
      pr_trace_msg(trace_channel, 19,
        "writing PDU request ID: %ld", pdu->request_id);
      res = snmp_asn1_write_int(p, buf, buflen, asn1_type, pdu->request_id, 0);
      if (res < 0) {
        return -1;
      }

      /* Error Status/Code */
      pr_trace_msg(trace_channel, 19,
        "writing PDU error status/code: %ld", pdu->err_code);
      res = snmp_asn1_write_int(p, buf, buflen, asn1_type, pdu->err_code, 0);
      if (res < 0) {
        return -1;
      }

      /* Error Index */
      pr_trace_msg(trace_channel, 19,
        "writing PDU error index: %ld", pdu->err_idx);
      res = snmp_asn1_write_int(p, buf, buflen, asn1_type, pdu->err_idx, 0);
      if (res < 0) {
        return -1;
      }

      /* Variable bindings list */
      pr_trace_msg(trace_channel, 19,
        "writing PDU variable binding list: (%u %s)", pdu->varlistlen,
        pdu->varlistlen != 1 ? "variables" : "variable");
      res = snmp_smi_write_vars(p, buf, buflen, pdu->varlist, snmp_version);
      if (res < 0) {
        return -1;
      }

      break;
  }

  /* Rewrite the PDU header, this time with the length of the entire PDU. */

  asn1_type = pdu->request_type;
  asn1_len = (*buf - pdu_hdr_end);

  pr_trace_msg(trace_channel, 18,
    "updating PDU header to have length %u", asn1_len);
  res = snmp_asn1_write_header(p, &pdu_hdr_start, &pdu_hdr_startlen, asn1_type,
    asn1_len, flags);
  if (res < 0) {
    return -1;
  }

  return 0;
}