Ejemplo n.º 1
0
/** Wait for all headers to be received, return its length and content-length (if available) */
static err_t
http_wait_headers(struct pbuf *p, u32_t *content_length, u16_t *total_header_len)
{
  u16_t end1 = pbuf_memfind(p, "\r\n\r\n", 4, 0);
  if (end1 < (0xFFFF - 2)) {
    /* all headers received */
    /* check if we have a content length (@todo: case insensitive?) */
    u16_t content_len_hdr;
    *content_length = HTTPC_CONTENT_LEN_INVALID;
    *total_header_len = end1 + 4;

    content_len_hdr = pbuf_memfind(p, "Content-Length: ", 16, 0);
    if (content_len_hdr != 0xFFFF) {
      u16_t content_len_line_end = pbuf_memfind(p, "\r\n", 2, content_len_hdr);
      if (content_len_line_end != 0xFFFF) {
        char content_len_num[16];
        u16_t content_len_num_len = (u16_t)(content_len_line_end - content_len_hdr - 16);
        memset(content_len_num, 0, sizeof(content_len_num));
        if (pbuf_copy_partial(p, content_len_num, content_len_num_len, content_len_hdr + 16) == content_len_num_len) {
          int len = atoi(content_len_num);
          if ((len >= 0) && ((u32_t)len < HTTPC_CONTENT_LEN_INVALID)) {
            *content_length = (u32_t)len;
          }
        }
      }
    }
    return ERR_OK;
  }
  return ERR_VAL;
}
Ejemplo n.º 2
0
/** Parse pbuf to see if it contains a fully received answer.
 * If one is found, ERR_OK is returned.
 * If none is found, ERR_VAL is returned.
 *
 * A fully received answer is a 3-digit number followed by a space,
 * some string and a CRLF as line ending.
 *
 * @param s smtp session struct
 */
static err_t
smtp_is_response_finished(struct smtp_session *s)
{
  u8_t sp;
  u16_t crlf;
  u16_t offset;

  if (s->p == NULL) {
    return ERR_VAL;
  }
  offset = 0;
again:
  /* We could check the response number here, but we trust the
   * protocol definition which says the client can rely on it being
   * the same on every line. */

  /* find CRLF */
  crlf = pbuf_memfind(s->p, SMTP_CRLF, SMTP_CRLF_LEN, offset + 4);
  if (crlf == 0xFFFF) {
    /* no CRLF found */
    return ERR_VAL;
  }
  sp = pbuf_get_at(s->p, offset + 3);
  if (sp == '-') {
    /* no space after response code -> try next line */
    offset = crlf + 2;
    goto again;
  } else if (sp == ' ') {
    /* CRLF found after response code + space -> valid response */
    return ERR_OK;
  }
  /* sp contains invalid character */
  return ERR_VAL;
}
Ejemplo n.º 3
0
/** Parse http header response line 1 */
static err_t
http_parse_response_status(struct pbuf *p, u16_t *http_version, u16_t *http_status, u16_t *http_status_str_offset)
{
  u16_t end1 = pbuf_memfind(p, "\r\n", 2, 0);
  if (end1 != 0xFFFF) {
    /* get parts of first line */
    u16_t space1, space2;
    space1 = pbuf_memfind(p, " ", 1, 0);
    if (space1 != 0xFFFF) {
      if ((pbuf_memcmp(p, 0, "HTTP/", 5) == 0)  && (pbuf_get_at(p, 6) == '.')) {
        char status_num[10];
        size_t status_num_len;
        /* parse http version */
        u16_t version = pbuf_get_at(p, 5) - '0';
        version <<= 8;
        version |= pbuf_get_at(p, 7) - '0';
        *http_version = version;

        /* parse http status number */
        space2 = pbuf_memfind(p, " ", 1, space1 + 1);
        if (space2 != 0xFFFF) {
          *http_status_str_offset = space2 + 1;
          status_num_len = space2 - space1 - 1;
        } else {
          status_num_len = end1 - space1 - 1;
        }
        memset(status_num, 0, sizeof(status_num));
        if (pbuf_copy_partial(p, status_num, (u16_t)status_num_len, space1 + 1) == status_num_len) {
          int status = atoi(status_num);
          if ((status > 0) && (status <= 0xFFFF)) {
            *http_status = (u16_t)status;
            return ERR_OK;
          }
        }
      }
    }
  }
  return ERR_VAL;
}
Ejemplo n.º 4
0
/** Parse last server response (in rx_buf) for supported authentication method,
 * create data to send out (to tx_buf), set tx_data_len correctly
 * and return the next state.
 */
static enum smtp_session_state
smtp_prepare_auth_or_mail(struct smtp_session *s, u16_t *tx_buf_len)
{
  /* check response for supported authentication method */
  u16_t auth = pbuf_strstr(s->p, SMTP_KEYWORD_AUTH_SP);
  if (auth == 0xFFFF) {
    auth = pbuf_strstr(s->p, SMTP_KEYWORD_AUTH_EQ);
  }
  if (auth != 0xFFFF) {
    u16_t crlf = pbuf_memfind(s->p, SMTP_CRLF, SMTP_CRLF_LEN, auth);
    if ((crlf != 0xFFFF) && (crlf > auth)) {
      /* use tx_buf temporarily */
      u16_t copied = pbuf_copy_partial(s->p, s->tx_buf, crlf - auth, auth);
      if (copied != 0) {
        char *sep = s->tx_buf + SMTP_KEYWORD_AUTH_LEN;
        s->tx_buf[copied] = 0;
#if SMTP_SUPPORT_AUTH_PLAIN
        /* favour PLAIN over LOGIN since it involves less requests */
        if (strstr(sep, SMTP_AUTH_PARAM_PLAIN) != NULL) {
          size_t auth_len;
          /* server supports AUTH PLAIN */
          SMEMCPY(s->tx_buf, SMTP_CMD_AUTHPLAIN_1, SMTP_CMD_AUTHPLAIN_1_LEN);

          /* add base64-encoded string "\0username\0password" */
          auth_len = smtp_base64_encode(&s->tx_buf[SMTP_CMD_AUTHPLAIN_1_LEN],
            SMTP_TX_BUF_LEN - SMTP_CMD_AUTHPLAIN_1_LEN, SMTP_AUTH_PLAIN_DATA(s),
            SMTP_AUTH_PLAIN_LEN(s));
          LWIP_ASSERT("string too long", auth_len <= 0xffff);
         *tx_buf_len = SMTP_CMD_AUTHPLAIN_1_LEN + SMTP_CMD_AUTHPLAIN_2_LEN + (u16_t)auth_len;
          LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN);
          SMEMCPY(&s->tx_buf[SMTP_CMD_AUTHPLAIN_1_LEN + auth_len], SMTP_CMD_AUTHPLAIN_2,
            SMTP_CMD_AUTHPLAIN_2_LEN);
          return SMTP_AUTH_PLAIN;
        } else
#endif /* SMTP_SUPPORT_AUTH_PLAIN */
        {
#if SMTP_SUPPORT_AUTH_LOGIN
          if (strstr(sep, SMTP_AUTH_PARAM_LOGIN) != NULL) {
            /* server supports AUTH LOGIN */
            *tx_buf_len = SMTP_CMD_AUTHLOGIN_LEN;
            SMEMCPY(s->tx_buf, SMTP_CMD_AUTHLOGIN, SMTP_CMD_AUTHLOGIN_LEN);
            return SMTP_AUTH_LOGIN_UNAME;
          }
#endif /* SMTP_SUPPORT_AUTH_LOGIN */
        }
      }
    }
  }
  /* server didnt's send correct keywords for AUTH, try sending directly */
  return smtp_prepare_mail(s, tx_buf_len);
}
Ejemplo n.º 5
0
static void
recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
  u16_t *sbuf = (u16_t *) p->payload;
  int opcode;

  LWIP_UNUSED_ARG(arg);
  LWIP_UNUSED_ARG(upcb);
  
  if (((tftp_state.port != 0) && (port != tftp_state.port)) ||
      (!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) {
    send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
    pbuf_free(p);
    return;
  }

  opcode = sbuf[0];

  tftp_state.last_pkt = tftp_state.timer;
  tftp_state.retries = 0;

  switch (opcode) {
    case PP_HTONS(TFTP_RRQ): /* fall through */
    case PP_HTONS(TFTP_WRQ):
    {
      const char tftp_null = 0;
      char filename[TFTP_MAX_FILENAME_LEN];
      char mode[TFTP_MAX_MODE_LEN];
      u16_t filename_end_offset;
      u16_t mode_end_offset;

      if(tftp_state.handle != NULL) {
        send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
        break;
      }
      
      sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);

      /* find \0 in pbuf -> end of filename string */
      filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2);
      if((u16_t)(filename_end_offset-2) > sizeof(filename)) {
        send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated");
        break;
      }
      pbuf_copy_partial(p, filename, filename_end_offset-2, 2);

      /* find \0 in pbuf -> end of mode string */
      mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset+1);
      if((u16_t)(mode_end_offset-filename_end_offset) > sizeof(mode)) {
        send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated");
        break;
      }
      pbuf_copy_partial(p, mode, mode_end_offset-filename_end_offset, filename_end_offset+1);
 
      tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ));
      tftp_state.blknum = 1;

      if (!tftp_state.handle) {
        send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file.");
        break;
      }

      LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read"));
      ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr);
      LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode));

      ip_addr_copy(tftp_state.addr, *addr);
      tftp_state.port = port;

      if (opcode == PP_HTONS(TFTP_WRQ)) {
        tftp_state.mode_write = 1;
        send_ack(0);
      } else {
        tftp_state.mode_write = 0;
        send_data();
      }

      break;
    }
    
    case PP_HTONS(TFTP_DATA):
    {
      int ret;
      u16_t blknum;
      
      if (tftp_state.handle == NULL) {
        send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
        break;
      }

      if (tftp_state.mode_write != 1) {
        send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection");
        break;
      }

      blknum = lwip_ntohs(sbuf[1]);
      pbuf_header(p, -TFTP_HEADER_LENGTH);

      ret = tftp_state.ctx->write(tftp_state.handle, p);
      if (ret < 0) {
        send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file");
        close_handle();
      } else {
        send_ack(blknum);
      }

      if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) {
        close_handle();
      }
      break;
    }

    case PP_HTONS(TFTP_ACK):
    {
      u16_t blknum;
      int lastpkt;

      if (tftp_state.handle == NULL) {
        send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
        break;
      }

      if (tftp_state.mode_write != 0) {
        send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection");
        break;
      }

      blknum = lwip_ntohs(sbuf[1]);
      if (blknum != tftp_state.blknum) {
        send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
        break;
      }

      lastpkt = 0;

      if (tftp_state.last_data != NULL) {
        lastpkt = tftp_state.last_data->tot_len != (TFTP_MAX_PAYLOAD_SIZE + TFTP_HEADER_LENGTH);
      }

      if (!lastpkt) {
        tftp_state.blknum++;
        send_data();
      } else {
        close_handle();
      }

      break;
    }
    
    default:
      send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation");
      break;
  }

  pbuf_free(p);
}