Example #1
0
static void
maybe_log_ssl_error_state(struct vsf_session* p_sess, int ret)
{
  if (tunable_debug_ssl)
  {
    str_alloc_text(&debug_str, "SSL ret: ");
    str_append_ulong(&debug_str, ret);
    str_append_text(&debug_str, ", SSL error: ");
    str_append_text(&debug_str, get_ssl_error());
    str_append_text(&debug_str, ", errno: ");
    str_append_ulong(&debug_str, errno);
    vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
  }
}
Example #2
0
static int
ssl_cert_digest(SSL* p_ssl, struct vsf_session* p_sess, struct mystr* p_str)
{
  X509* p_cert = SSL_get_peer_certificate(p_ssl);
  unsigned int num_bytes = 0;
  if (p_cert == NULL)
  {
    return 0;
  }
  str_reserve(p_str, EVP_MAX_MD_SIZE);
  str_empty(p_str);
  str_rpad(p_str, EVP_MAX_MD_SIZE);
  if (!X509_digest(p_cert, EVP_sha256(), (unsigned char*) str_getbuf(p_str),
                   &num_bytes))
  {
    die("X509_digest failed");
  }
  X509_free(p_cert);
  if (tunable_debug_ssl)
  {
    unsigned int i;
    str_alloc_text(&debug_str, "Cert digest:");
    for (i = 0; i < num_bytes; ++i)
    { 
      str_append_char(&debug_str, ' ');
      str_append_ulong(
        &debug_str, (unsigned long) (unsigned char) str_get_char_at(p_str, i));
    }
    vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
  }
  str_trunc(p_str, num_bytes);
  return 1;
}
Example #3
0
static void
maybe_log_shutdown_state(struct vsf_session* p_sess)
{
  if (tunable_debug_ssl)
  {
    int ret = SSL_get_shutdown(p_sess->p_data_ssl);
    str_alloc_text(&debug_str, "SSL shutdown state is: ");
    if (ret == 0)
    {
      str_append_text(&debug_str, "NONE");
    }
    else if (ret == SSL_SENT_SHUTDOWN)
    {
      str_append_text(&debug_str, "SSL_SENT_SHUTDOWN");
    }
    else if (ret == SSL_RECEIVED_SHUTDOWN)
    {
      str_append_text(&debug_str, "SSL_RECEIVED_SHUTDOWN");
    }
    else
    {
      str_append_ulong(&debug_str, ret);
    }
    vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
  }
}
Example #4
0
void
ssl_add_entropy(struct vsf_session* p_sess)
{
  /* Although each child does seem to have its different pool of entropy, I
   * don't trust the interaction of OpenSSL's opaque RAND API and fork(). So
   * throw a bit more in (only works on systems with /dev/urandom for now).
   */
  int ret = RAND_load_file("/dev/urandom", 16);
  if (ret != 16)
  {
    str_alloc_text(&debug_str, "Couldn't add extra OpenSSL entropy: ");
    str_append_ulong(&debug_str, (unsigned long) ret);
    vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
  }
}
Example #5
0
static void
get_unique_filename(struct mystr* p_outstr, const struct mystr* p_base_str)
{
  /* Use silly wu-ftpd algorithm for compatibility */
  static struct vsf_sysutil_statbuf* s_p_statbuf;
  unsigned int suffix = 1;
  int retval;
  while (1)
  {
    str_copy(p_outstr, p_base_str);
    str_append_char(p_outstr, '.');
    str_append_ulong(p_outstr, suffix);
    retval = str_stat(p_outstr, &s_p_statbuf);
    if (vsf_sysutil_retval_is_error(retval))
    {
      return;
    }
    ++suffix;
  }
}
Example #6
0
void
vsf_insert_uwtmp(const struct mystr* p_user_str,
                 const struct mystr* p_host_str)
{
  if (sizeof(s_utent.ut_line) < 16)
  {
    return;
  }
  if (s_uwtmp_inserted)
  {
    bug("vsf_insert_uwtmp");
  }
  {
    struct mystr line_str = INIT_MYSTR;
    str_alloc_text(&line_str, VSF_PROJECT ":");
    str_append_ulong(&line_str, vsf_sysutil_getpid());
    if (str_getlen(&line_str) >= sizeof(s_utent.ut_line))
    {
      str_free(&line_str);
      return;
    }
    vsf_sysutil_strcpy(s_utent.ut_line, str_getbuf(&line_str),
                       sizeof(s_utent.ut_line));
    str_free(&line_str);
  }
  s_uwtmp_inserted = 1;
  s_utent.ut_type = USER_PROCESS;
  s_utent.ut_pid = vsf_sysutil_getpid();
  vsf_sysutil_strcpy(s_utent.ut_user, str_getbuf(p_user_str),
                     sizeof(s_utent.ut_user));
  vsf_sysutil_strcpy(s_utent.ut_host, str_getbuf(p_host_str),
                     sizeof(s_utent.ut_host));
  s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec();
  setutxent();
  (void) pututxline(&s_utent);
  endutxent();
#ifdef VSF_SYSDEP_HAVE_UPDWTMPX
  updwtmpx(WTMPX_FILE, &s_utent);
#endif
}
Example #7
0
static void
handle_pasv(struct vsf_session* p_sess)
{
  static struct mystr s_pasv_res_str;
  static struct vsf_sysutil_sockaddr* s_p_sockaddr;
  struct vsf_sysutil_ipv4port listen_port;
  struct vsf_sysutil_ipv4addr listen_ipaddr;
  int bind_retries = 10;
  pasv_cleanup(p_sess);
  port_cleanup(p_sess);
  p_sess->pasv_listen_fd = vsf_sysutil_get_ipv4_sock();
  while (--bind_retries)
  {
    int retval;
    unsigned short the_port;
    double scaled_port;
    /* IPPORT_RESERVED */
    unsigned short min_port = 1024;
    unsigned short max_port = 65535;
    if (tunable_pasv_min_port > min_port && tunable_pasv_min_port < max_port)
    {
      min_port = tunable_pasv_min_port;
    }
    if (tunable_pasv_max_port > min_port && tunable_pasv_max_port < max_port)
    {
      max_port = tunable_pasv_max_port;
    }
    the_port = vsf_sysutil_get_random_byte();
    the_port <<= 8;
    the_port |= vsf_sysutil_get_random_byte();
    scaled_port = (double) min_port;
    scaled_port += ((double) the_port / (double) 65535) *
                   ((double) max_port - min_port);
    the_port = (unsigned short) scaled_port;
    vsf_sysutil_sockaddr_alloc_ipv4(&s_p_sockaddr);
    vsf_sysutil_sockaddr_set_port(s_p_sockaddr,
                                  vsf_sysutil_ipv4port_from_int(the_port));
    /* Bind to same address we got the incoming connect on */
    vsf_sysutil_sockaddr_set_ipaddr(s_p_sockaddr,
      vsf_sysutil_sockaddr_get_ipaddr(p_sess->p_local_addr));
    retval = vsf_sysutil_bind(p_sess->pasv_listen_fd, s_p_sockaddr);
    if (!vsf_sysutil_retval_is_error(retval))
    {
      break;
    }
    if (vsf_sysutil_get_error() == kVSFSysUtilErrADDRINUSE)
    {
      continue;
    }
    die("vsf_sysutil_bind");
  }
  if (!bind_retries)
  {
    die("vsf_sysutil_bind");
  }
  vsf_sysutil_listen(p_sess->pasv_listen_fd, 1);
  /* Get the address of the bound socket, for the port */
  vsf_sysutil_getsockname(p_sess->pasv_listen_fd, &s_p_sockaddr);
  if (tunable_pasv_address != 0)
  {
    /* Report passive address as specified in configuration */
    if (vsf_sysutil_inet_aton(tunable_pasv_address, &listen_ipaddr) == 0)
    {
      die("invalid pasv_address");
    }
  }
  else
  {
    /* Use address of bound socket for passive address */
    listen_ipaddr = vsf_sysutil_sockaddr_get_ipaddr(s_p_sockaddr);
  }
  listen_port = vsf_sysutil_sockaddr_get_port(s_p_sockaddr);
  str_alloc_text(&s_pasv_res_str, "Entering Passive Mode (");
  str_append_ulong(&s_pasv_res_str, listen_ipaddr.data[0]);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, listen_ipaddr.data[1]);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, listen_ipaddr.data[2]);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, listen_ipaddr.data[3]);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, listen_port.data[0]);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, listen_port.data[1]);
  str_append_text(&s_pasv_res_str, ")");
  vsf_cmdio_write_str(p_sess, FTP_PASVOK, &s_pasv_res_str);
}
Example #8
0
static void
vsf_log_do_log_vsftpd_format(struct vsf_session* p_sess, struct mystr* p_str,
                             int succeeded, enum EVSFLogEntryType what,
                             const struct mystr* p_log_str)
{
  /* Date - vsf_sysutil_get_current_date updates cached time */
  str_alloc_text(p_str, vsf_sysutil_get_current_date());
  /* Pid */
  str_append_text(p_str, " [pid ");
  str_append_ulong(p_str, vsf_sysutil_getpid());
  str_append_text(p_str, "] ");
  /* User */
  if (!str_isempty(&p_sess->user_str))
  {
    str_append_char(p_str, '[');
    str_append_str(p_str, &p_sess->user_str);
    str_append_text(p_str, "] ");
  }
  /* And the action */
  if (what != kVSFLogEntryFTPInput && what != kVSFLogEntryFTPOutput &&
      what != kVSFLogEntryConnection)
  {
    if (succeeded)
    {
      str_append_text(p_str, "OK ");
    }
    else
    {
      str_append_text(p_str, "FAIL ");
    }
  }
  switch (what)
  {
    case kVSFLogEntryDownload:
      str_append_text(p_str, "DOWNLOAD");
      break;
    case kVSFLogEntryUpload:
      str_append_text(p_str, "UPLOAD");
      break;
    case kVSFLogEntryMkdir:
      str_append_text(p_str, "MKDIR");
      break;
    case kVSFLogEntryLogin:
      str_append_text(p_str, "LOGIN");
      break;
    case kVSFLogEntryFTPInput:
      str_append_text(p_str, "FTP command");
      break;
    case kVSFLogEntryFTPOutput:
      str_append_text(p_str, "FTP response");
      break;
    case kVSFLogEntryConnection:
      str_append_text(p_str, "CONNECT");
      break;
    case kVSFLogEntryDelete:
      str_append_text(p_str, "DELETE");
      break;
    case kVSFLogEntryRename:
      str_append_text(p_str, "RENAME");
      break;
    case kVSFLogEntryRmdir:
      str_append_text(p_str, "RMDIR");
      break;
    case kVSFLogEntryChmod:
      str_append_text(p_str, "CHMOD");
      break;
    default:
      bug("bad entry_type in vsf_log_do_log");
      break;
  }
  str_append_text(p_str, ": Client \"");
  str_append_str(p_str, &p_sess->remote_ip_str);
  str_append_char(p_str, '"');
  if (what == kVSFLogEntryLogin && !str_isempty(&p_sess->anon_pass_str))
  {
    str_append_text(p_str, ", anon password \"");
    str_append_str(p_str, &p_sess->anon_pass_str);
    str_append_char(p_str, '"');
  }
  if (!str_isempty(p_log_str))
  {
    str_append_text(p_str, ", \"");
    str_append_str(p_str, p_log_str);
    str_append_char(p_str, '"');
  }
  if (what != kVSFLogEntryFTPInput && what != kVSFLogEntryFTPOutput)
  {
    if (p_sess->transfer_size)
    {
      str_append_text(p_str, ", ");
      str_append_filesize_t(p_str, p_sess->transfer_size);
      str_append_text(p_str, " bytes");
    }
    if (vsf_log_type_is_transfer(what))
    {
      long delta_sec = vsf_sysutil_get_cached_time_sec() -
                       p_sess->log_start_sec;
      long delta_usec = vsf_sysutil_get_cached_time_usec() -
                        p_sess->log_start_usec;
      double time_delta = (double) delta_sec + ((double) delta_usec /
                                                (double) 1000000);
      double kbyte_rate =
        ((double) p_sess->transfer_size / time_delta) / (double) 1024;
      str_append_text(p_str, ", ");
      str_append_double(p_str, kbyte_rate);
      str_append_text(p_str, "Kbyte/sec");
    }
  }
}
Example #9
0
static void
vsf_log_do_log_wuftpd_format(struct vsf_session* p_sess, struct mystr* p_str,
                             int succeeded)
{
  long delta_sec;
  enum EVSFLogEntryType what = (enum EVSFLogEntryType) p_sess->log_type;
  /* Date - vsf_sysutil_get_current_date updates cached time */
  str_alloc_text(p_str, vsf_sysutil_get_current_date());
  str_append_char(p_str, ' ');
  /* Transfer time (in seconds) */
  delta_sec = vsf_sysutil_get_cached_time_sec() - p_sess->log_start_sec;
  if (delta_sec <= 0)
  {
    delta_sec = 1;
  }
  str_append_ulong(p_str, (unsigned long) delta_sec);
  str_append_char(p_str, ' ');
  /* Remote host name */
  str_append_str(p_str, &p_sess->remote_ip_str);
  str_append_char(p_str, ' ');
  /* Bytes transferred */
  str_append_filesize_t(p_str, p_sess->transfer_size);
  str_append_char(p_str, ' ');
  /* Filename */
  str_append_str(p_str, &p_sess->log_str);
  str_append_char(p_str, ' ');
  /* Transfer type (ascii/binary) */
  if (p_sess->is_ascii)
  {
    str_append_text(p_str, "a ");
  }
  else
  {
    str_append_text(p_str, "b ");
  }
  /* Special action flag - tar, gzip etc. */
  str_append_text(p_str, "_ ");
  /* Direction of transfer */
  if (what == kVSFLogEntryUpload)
  {
    str_append_text(p_str, "i ");
  }
  else
  {
    str_append_text(p_str, "o ");
  }
  /* Access mode: anonymous/real user, and identity */
  if (p_sess->is_anonymous)
  {
    str_append_text(p_str, "a ");
    str_append_str(p_str, &p_sess->anon_pass_str);
  }
  else
  {
    str_append_text(p_str, "r ");
    str_append_str(p_str, &p_sess->user_str);
  }
  str_append_char(p_str, ' ');
  /* Service name, authentication method, authentication user id */
  str_append_text(p_str, "ftp 0 * ");
  /* Completion status */
  if (succeeded)
  {
    str_append_char(p_str, 'c');
  }
  else
  {
    str_append_char(p_str, 'i');
  }
}
Example #10
0
static void
handle_pasv(struct vsf_session* p_sess, int is_epsv)
{
  static struct mystr s_pasv_res_str;
  static struct vsf_sysutil_sockaddr* s_p_sockaddr;
  int bind_retries = 10;
  unsigned short the_port = 0;
  int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);
  if (is_epsv && !str_isempty(&p_sess->ftp_arg_str))
  {
    int argval;
    str_upper(&p_sess->ftp_arg_str);
    if (str_equal_text(&p_sess->ftp_arg_str, "ALL"))
    {
      p_sess->epsv_all = 1;
      vsf_cmdio_write(p_sess, FTP_EPSVALLOK, "EPSV ALL ok.");
      return;
    }
    argval = vsf_sysutil_atoi(str_getbuf(&p_sess->ftp_arg_str));
    if (!is_ipv6 || argval != 2)
    {
      vsf_cmdio_write(p_sess, FTP_EPSVBAD, "Bad network protocol.");
      return;
    }
  }
  pasv_cleanup(p_sess);
  port_cleanup(p_sess);
  if (is_epsv && is_ipv6)
  {
    p_sess->pasv_listen_fd = vsf_sysutil_get_ipv6_sock();
  }
  else
  {
    p_sess->pasv_listen_fd = vsf_sysutil_get_ipv4_sock();
  }
  vsf_sysutil_activate_reuseaddr(p_sess->pasv_listen_fd);
  while (--bind_retries)
  {
    int retval;
    double scaled_port;
    /* IPPORT_RESERVED */
    unsigned short min_port = 1024;
    unsigned short max_port = 65535;
    if (tunable_pasv_min_port > min_port && tunable_pasv_min_port <= max_port)
    {
      min_port = tunable_pasv_min_port;
    }
    if (tunable_pasv_max_port >= min_port && tunable_pasv_max_port < max_port)
    {
      max_port = tunable_pasv_max_port;
    }
    the_port = vsf_sysutil_get_random_byte();
    the_port <<= 8;
    the_port |= vsf_sysutil_get_random_byte();
    scaled_port = (double) min_port;
    scaled_port += ((double) the_port / (double) 65536) *
                   ((double) max_port - min_port + 1);
    the_port = (unsigned short) scaled_port;
    vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr);
    vsf_sysutil_sockaddr_set_port(s_p_sockaddr, the_port);
    retval = vsf_sysutil_bind(p_sess->pasv_listen_fd, s_p_sockaddr);
    if (!vsf_sysutil_retval_is_error(retval))
    {
      break;
    }
    if (vsf_sysutil_get_error() == kVSFSysUtilErrADDRINUSE)
    {
      continue;
    }
    die("vsf_sysutil_bind");
  }
  if (!bind_retries)
  {
    die("vsf_sysutil_bind");
  }
  vsf_sysutil_listen(p_sess->pasv_listen_fd, 1);
  if (is_epsv)
  {
    str_alloc_text(&s_pasv_res_str, "Entering Extended Passive Mode (|||");
    str_append_ulong(&s_pasv_res_str, (unsigned long) the_port);
    str_append_text(&s_pasv_res_str, "|)");
    vsf_cmdio_write_str(p_sess, FTP_EPSVOK, &s_pasv_res_str);
    return;
  }
  if (tunable_pasv_address != 0)
  {
    /* Report passive address as specified in configuration */
    if (vsf_sysutil_inet_aton(tunable_pasv_address, s_p_sockaddr) == 0)
    {
      die("invalid pasv_address");
    }
  }
  str_alloc_text(&s_pasv_res_str, "Entering Passive Mode (");
  if (!is_ipv6)
  {
    str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntop(s_p_sockaddr));
  }
  else
  {
    const void* p_v4addr = vsf_sysutil_sockaddr_ipv6_v4(s_p_sockaddr);
    if (p_v4addr)
    {
      str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntoa(p_v4addr));
    }
  }
  str_replace_char(&s_pasv_res_str, '.', ',');
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, the_port >> 8);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, the_port & 255);
  str_append_text(&s_pasv_res_str, ")");
  vsf_cmdio_write_str(p_sess, FTP_PASVOK, &s_pasv_res_str);
}