Exemplo n.º 1
0
void snmp_stacktrace_log(void) {
#if defined(HAVE_EXECINFO_H) && \
    defined(HAVE_BACKTRACE) && \
    defined(HAVE_BACKTRACE_SYMBOLS)
  void *trace[PR_TUNABLE_CALLER_DEPTH];
  char **strings;
  size_t tracesz;

  (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
    "-----BEGIN STACK TRACE-----");

  tracesz = backtrace(trace, PR_TUNABLE_CALLER_DEPTH);
  strings = backtrace_symbols(trace, tracesz);
  if (strings != NULL) {
    register unsigned int i;

    for (i = 1; i < tracesz; i++) {
      (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
        "[%u] %s", i-1, strings[i]);
    }

    /* Prevent memory leaks. */
    free(strings);

  } else {
    (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
      "error obtaining stacktrace symbols: %s", strerror(errno));
  }

  (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION,
    "-----END STACK TRACE-----");
#endif
}
Exemplo n.º 2
0
static int forward_handle_pass_passthru(cmd_rec *cmd,
    struct proxy_session *proxy_sess, int *successful) {
  int res, xerrno;
  pr_response_t *resp;
  unsigned int resp_nlines = 0;

  res = proxy_ftp_ctrl_send_cmd(cmd->tmp_pool, proxy_sess->backend_ctrl_conn,
    cmd);
  if (res < 0) {
    xerrno = errno;
    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "error sending %s to backend: %s", (char *) cmd->argv[0],
      strerror(xerrno));

    errno = xerrno;
    return -1;
  }

  resp = proxy_ftp_ctrl_recv_resp(cmd->tmp_pool, proxy_sess->backend_ctrl_conn,
    &resp_nlines);
  if (resp == NULL) {
    xerrno = errno;
    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "error receiving %s response from backend: %s", (char *) cmd->argv[0],
      strerror(xerrno));

    /* If we receive an EPERM here, it is probably because the backend
     * closed its control connection, yielding an EOF.  To better indicate
     * this situation, propagate the error using EPIPE.
     */
    if (xerrno == EPERM) {
      xerrno = EPIPE;
    }

    errno = xerrno;
    return -1;
  }

  /* XXX What about other response codes for PASS? */
  if (resp->num[0] == '2') {
    *successful = TRUE;

    proxy_sess_state |= PROXY_SESS_STATE_BACKEND_AUTHENTICATED;
  }

  res = proxy_ftp_ctrl_send_resp(cmd->tmp_pool, proxy_sess->frontend_ctrl_conn,
    resp, resp_nlines);
  if (res < 0) {
    xerrno = errno;

    pr_response_block(TRUE);
    errno = xerrno;
    return -1;
  }

  return 1;
}
Exemplo n.º 3
0
static int filestore_verify_host_key(sftp_keystore_t *store, pool *p,
    const char *user, const char *host_fqdn, const char *host_user,
    unsigned char *key_data, uint32_t key_len) {
  struct filestore_key *key = NULL;
  struct filestore_data *store_data = store->keystore_data;

  int res = -1;

  if (!store_data->path) {
    errno = EPERM;
    return -1;
  }

  /* XXX Note that this will scan the file from the beginning, each time.
   * There's room for improvement; perhaps mmap() the file into memory?
   */

  key = filestore_get_key(store, p);
  while (key) {
    int ok;

    pr_signals_handle();

    ok = sftp_keys_compare_keys(p, key_data, key_len, key->key_data,
      key->key_datalen);
    if (ok != TRUE) {
      if (ok == -1) {
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
          "error comparing keys from '%s': %s", store_data->path,
          strerror(errno));
      }

    } else {

      /* XXX Verify that the user and the host_user match?? */

      res = 0;
      break;
    }

    key = filestore_get_key(store, p);
  }

  if (res == 0) {
    pr_trace_msg(trace_channel, 10, "found matching public key for host '%s' "
      "in '%s'", host_fqdn, store_data->path);
  }

  if (pr_fsio_lseek(store_data->fh, 0, SEEK_SET) < 0) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error seeking to start of '%s': %s", store_data->path, strerror(errno));
    return -1;
  }

  store_data->lineno = 0;
  return res;
}
Exemplo n.º 4
0
static int counter_get_sem(pr_fh_t *fh, const char *path) {
  int semid;
  key_t key;

  /* Obtain a key for this path. */
  key = counter_get_key(path);
  if (key == (key_t) -1) {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "unable to get key for '%s': %s", path, strerror(errno));
    return -1;
  }

  /* Try first using IPC_CREAT|IPC_EXCL, to check if there is an existing
   * semaphore set for this key.  If there is, try again, using a flag of
   * zero.
   */
 
  semid = semget(key, COUNTER_NSEMS, IPC_CREAT|IPC_EXCL|0666);
  if (semid < 0) {
    if (errno == EEXIST) {
      semid = semget(key, 0, 0);

    } else {
      return -1;
    }

  } else {

    /* Set the values of the newly created semaphore to the configured
     * CounterMaxReaders and CounterMaxWriters.
     */
    if (counter_set_readers(semid) < 0) {
      (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
        "error setting readers (semaphore ID %d): %s", semid, strerror(errno));
    }

    if (counter_set_writers(semid) < 0) {
      (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
        "error setting writers (semaphore ID %d): %s", semid, strerror(errno));
    }

    if (counter_set_procs(semid) < 0) {
      (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
        "error setting procs (semaphore ID %d): %s", semid, strerror(errno));
    }

    /* Record the ID of the created semaphore in the CounterFile. */
    if (counter_file_add_id(fh, semid) < 0) {
      (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
        "error recording semaphore (semaphore ID %d) in CounterFile '%s': %s",
        semid, fh->fh_path, strerror(errno));
    }
  }

  return semid;
}
Exemplo n.º 5
0
int sftp_cipher_write_data(struct ssh2_packet *pkt, unsigned char *buf,
    size_t *buflen) {
  struct sftp_cipher *cipher;
  EVP_CIPHER_CTX *cipher_ctx;

  cipher = &(write_ciphers[write_cipher_idx]);
  cipher_ctx = write_ctxs[write_cipher_idx];

  if (cipher->key) {
    int res;
    unsigned char *data, *ptr;
    uint32_t datalen, datasz = sizeof(uint32_t) + pkt->packet_len;

    datalen = datasz;
    ptr = data = palloc(pkt->pool, datasz);

    sftp_msg_write_int(&data, &datalen, pkt->packet_len);
    sftp_msg_write_byte(&data, &datalen, pkt->padding_len);
    sftp_msg_write_data(&data, &datalen, pkt->payload, pkt->payload_len, FALSE);
    sftp_msg_write_data(&data, &datalen, pkt->padding, pkt->padding_len, FALSE);

    res = EVP_Cipher(cipher_ctx, buf, ptr, (datasz - datalen));
    if (res != 1) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error encrypting %s data for client: %s", cipher->algo,
        sftp_crypto_get_errors());
      errno = EIO;
      return -1;
    }

    *buflen = (datasz - datalen);

#ifdef SFTP_DEBUG_PACKET
{
  unsigned int i;

  (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
    "encrypted packet data (len %lu):", (unsigned long) *buflen);
  for (i = 0; i < *buflen;) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "  %02x%02x %02x%02x %02x%02x %02x%02x",
      ((unsigned char *) buf)[i], ((unsigned char *) buf)[i+1],
      ((unsigned char *) buf)[i+2], ((unsigned char *) buf)[i+3],
      ((unsigned char *) buf)[i+4], ((unsigned char *) buf)[i+5],
      ((unsigned char *) buf)[i+6], ((unsigned char *) buf)[i+7]);
    i += 8;
  }
}
#endif

    return 0;
  }

  *buflen = 0;
  return 0;
}
Exemplo n.º 6
0
int proxy_forward_sess_init(pool *p, const char *tables_dir,
    struct proxy_session *proxy_sess) {
  config_rec *c;
  int allowed = FALSE;
  void *enabled = NULL;

  /* By default, only allow connections from RFC1918 addresses to use
   * forward proxying.  Otherwise, it must be from an explicitly allowed
   * connection class, via the class notes.
   */
  if (session.conn_class != NULL) {
    enabled = pr_table_get(session.conn_class->cls_notes,
      PROXY_FORWARD_ENABLED_NOTE, NULL);
  }

  if (enabled != NULL) {
    allowed = *((int *) enabled);
    if (allowed == FALSE) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "forward proxying not allowed from client address %s in <Class %s> "
        "(see ProxyForwardEnabled)",
        pr_netaddr_get_ipstr(session.c->remote_addr),
        session.conn_class->cls_name);
    }

  } else {
    if (pr_netaddr_is_rfc1918(session.c->remote_addr) == TRUE) {
      allowed = TRUE;

    } else {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "forward proxying not allowed from non-RFC1918 client address %s",
        pr_netaddr_get_ipstr(session.c->remote_addr));
    }
  }

  if (allowed == FALSE) {
    errno = EPERM;
    return -1;
  }

  c = find_config(main_server->conf, CONF_PARAM, "ProxyForwardMethod", FALSE);
  if (c != NULL) {
    proxy_method = *((int *) c->argv[0]);
  }

  c = find_config(main_server->conf, CONF_PARAM, "ProxyRetryCount", FALSE);
  if (c != NULL) {
    forward_retry_count = *((int *) c->argv[0]);
  }

  return 0;
}
Exemplo n.º 7
0
int sftp_cipher_read_data(pool *p, unsigned char *data, uint32_t data_len,
    unsigned char **buf, uint32_t *buflen) {
  struct sftp_cipher *cipher;
  EVP_CIPHER_CTX *cipher_ctx;
  size_t cipher_blocksz;

  cipher = &(read_ciphers[read_cipher_idx]);
  cipher_ctx = read_ctxs[read_cipher_idx];
  cipher_blocksz = cipher_blockszs[read_cipher_idx];

  if (cipher->key) {
    int res;
    unsigned char *ptr = NULL;
    size_t bufsz;

    if (*buflen % cipher_blocksz != 0) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "bad input length for decryption (%u bytes, %u block size)", *buflen,
        (unsigned int) cipher_blocksz);
      return -1;
    }

    if (*buf == NULL) {
      /* Allocate a buffer that's large enough. */
      bufsz = (data_len + cipher_blocksz - 1);
      ptr = palloc(p, bufsz);

    } else {
      ptr = *buf;
    }

    res = EVP_Cipher(cipher_ctx, ptr, data, data_len);
    if (res != 1) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error decrypting %s data from client: %s", cipher->algo,
        sftp_crypto_get_errors());
      return -1;
    }

    *buflen = data_len;
    *buf = ptr;

    return 0;
  }

  *buf = data;
  *buflen = data_len;
  return 0;
}
Exemplo n.º 8
0
MODRET counter_writer_done(cmd_rec *cmd) {
  pr_fh_t *fh;

  if (counter_engine == FALSE) {
    return PR_DECLINED(cmd);
  }

  if (!(counter_pending & COUNTER_HAVE_WRITER)) {
    return PR_DECLINED(cmd);
  }

  fh = counter_get_fh(cmd->tmp_pool, counter_curr_path);
  if (fh == NULL) {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "%s: no CounterFile found for path '%s'", (char *) cmd->argv[0],
      counter_curr_path);

    /* No CounterFile configured/available for this path. */
    return PR_DECLINED(cmd);
  }

  if (counter_curr_semid == -1) {
    counter_curr_semid = counter_get_sem(fh, counter_curr_path);
    if (counter_curr_semid < 0) {
      (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
        "unable to get semaphore for '%s': %s", counter_curr_path,
        strerror(errno));
      return PR_DECLINED(cmd);
    }
  }

  if (counter_remove_writer(fh, counter_curr_semid) < 0) {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "error removing writer for '%s': %s", counter_curr_path,
      strerror(errno));

  } else {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "removed writer counter for '%s' (semaphore ID %d)", counter_curr_path,
      counter_curr_semid);

    counter_curr_path = NULL;
    counter_curr_semid = -1;
    counter_pending &= ~COUNTER_HAVE_WRITER;
  }

  return PR_DECLINED(cmd);
}
Exemplo n.º 9
0
int proxy_session_check_password(pool *p, const char *user,
    const char *passwd) {
  int res;

  res = pr_auth_authenticate(p, user, passwd);
  switch (res) {
    case PR_AUTH_OK:
      break;

    case PR_AUTH_NOPWD:
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "password authentication for user '%s' failed: No such user", user);
      pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): No such user found",
        user);
      return -1;

    case PR_AUTH_BADPWD:
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "password authentication for user '%s' failed: Incorrect password",
        user);
      pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Incorrect password",
        user);
      return -1;

    case PR_AUTH_AGEPWD:
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "password authentication for user '%s' failed: Password expired",
        user);
      pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Password expired",
        user);
      return -1;

    case PR_AUTH_DISABLEDPWD:
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "password authentication for user '%s' failed: Account disabled",
        user);
      pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Account disabled",
        user);
      return -1;

    default:
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "unknown authentication value (%d), returning error", res);
      return -1;
  }

  return 0;
}
Exemplo n.º 10
0
int sftp_compress_init_read(int flags) {
  struct sftp_compress *comp;
  z_stream *stream;

  switch_read_compress(flags);

  comp = &(read_compresses[read_comp_idx]);
  stream = &(read_streams[read_comp_idx]);

  if (comp->use_zlib == flags &&
      !comp->stream_ready) {
    int zres;

    zres = inflateInit(stream);
    if (zres != Z_OK) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error preparing decompression stream (%d)", zres);
    }

    pr_event_generate("mod_sftp.ssh.client-compression", NULL);
    comp->stream_ready = TRUE;
  }

  return 0;
}
Exemplo n.º 11
0
static int read_service_req(struct ssh2_packet *pkt, char **service) {
  unsigned char *buf;
  char *service_name;
  uint32_t buflen;
  cmd_rec *cmd;

  buf = pkt->payload;
  buflen = pkt->payload_len;

  service_name = sftp_msg_read_string(pkt->pool, &buf, &buflen);
  pr_trace_msg(trace_channel, 10, "'%s' service requested", service_name);

  cmd = pr_cmd_alloc(pkt->pool, 1, pstrdup(pkt->pool, "SERVICE_REQUEST"));
  cmd->arg = service_name;
  cmd->cmd_class = CL_MISC|CL_SSH;

  if (strncmp(service_name, "ssh-userauth", 13) == 0 ||
      strncmp(service_name, "ssh-connection", 14) == 0) {
    if (service)
      *service = pstrdup(service_pool, service_name);

    pr_cmd_dispatch_phase(cmd, LOG_CMD, 0);
    return 0;
  }

  (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
    "client requested unsupported '%s' service", service_name);

  pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0);
  return -1;
}
Exemplo n.º 12
0
int vroot_fsio_rmdir(pr_fs_t *fs, const char *path) {
  char vpath[PR_TUNABLE_PATH_MAX + 1];

  if (session.curr_phase == LOG_CMD ||
      session.curr_phase == LOG_CMD_ERR ||
      (session.sf_flags & SF_ABORT) ||
      vroot_path_have_base() == FALSE) {
    /* NOTE: once stackable FS modules are supported, have this fall through
     * to the next module in the stack.
     */
    return rmdir(path);
  }

  /* Do not allow deleting of aliased files/directories; the aliases may only
   * exist for this user/group.
   */
  if (vroot_path_lookup(NULL, vpath, sizeof(vpath)-1, path,
      VROOT_LOOKUP_FL_NO_ALIAS, NULL) < 0) {
    return -1;
  }

  if (vroot_alias_exists(vpath) == TRUE) {
    (void) pr_log_writefile(vroot_logfd, MOD_VROOT_VERSION,
      "denying delete of '%s' because it is a VRootAlias", vpath);
    errno = EACCES;
    return -1;
  }

  if (vroot_path_lookup(NULL, vpath, sizeof(vpath)-1, path, 0, NULL) < 0) {
    return -1;
  }

  return rmdir(vpath);
}
Exemplo n.º 13
0
static int send_pubkey_ok(const char *algo, const char *pubkey_data,
    uint32_t pubkey_len) {
  struct ssh2_packet *pkt;
  char *buf, *ptr;
  uint32_t buflen, bufsz;
  int res;

  /* Make sure to allocate a buffer large enough to hold the publickey
   * data we're sending back.
   */
  bufsz = buflen = pubkey_len + 1024;

  pkt = sftp_ssh2_packet_create(sftp_pool);

  buflen = bufsz;
  ptr = buf = palloc(pkt->pool, bufsz);

  sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_USER_AUTH_PK_OK);
  sftp_msg_write_string(&buf, &buflen, algo);
  sftp_msg_write_data(&buf, &buflen, pubkey_data, pubkey_len, TRUE);

  pkt->payload = ptr;
  pkt->payload_len = (bufsz - buflen);

  (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "sending publickey OK");

  res = sftp_ssh2_packet_write(sftp_conn->wfd, pkt);
  if (res < 0) {
    destroy_pool(pkt->pool);
    return -1;
  }

  destroy_pool(pkt->pool);
  return 0;
}
static void log_failure_mkjson(void *json, const char *field_name,
    size_t field_namelen, unsigned int field_type, const void *field_value) {
  JsonNode *field = NULL;

  switch (field_type) {
    case LOG_FAILURE_FIELD_TYPE_STRING:
      field = json_mkstring((const char *) field_value);
      break;

    case LOG_FAILURE_FIELD_TYPE_NUMBER:
      field = json_mknumber(*((double *) field_value));
      break;

    case LOG_FAILURE_FIELD_TYPE_BOOLEAN:
      field = json_mkbool(*((bool *) field_value));
      break;

    default:
      (void) pr_log_writefile(log_failure_logfd, MOD_LOG_FAILURE_VERSION,
        "unsupported field type: %u", field_type);
  }

  if (field != NULL) {
    json_append_member(json, field_name, field);
  }
}
Exemplo n.º 15
0
int proxy_db_init(pool *p) {
  const char *version;

  if (p == NULL) {
    errno = EINVAL;
    return -1;
  }

  if (db_pool != NULL) {
    return 0;
  }

  /* Check that the SQLite headers used match the version of the SQLite
   * library used.
   *
   * For now, we only log if there is a difference.
   */
  version = sqlite3_libversion();
  if (strcmp(version, SQLITE_VERSION) != 0) {
    (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
      "compiled using SQLite version '%s' headers, but linked to "
      "SQLite version '%s' library", SQLITE_VERSION, version);
  }

  pr_trace_msg(trace_channel, 9, "using SQLite %s", version);

  db_pool = make_sub_pool(p);
  pr_pool_tag(db_pool, "Proxy Database Pool");
  
  return 0;
}
Exemplo n.º 16
0
static void switch_read_compress(int flags) {
  struct sftp_compress *comp;
  z_stream *stream;

  comp = &(read_compresses[read_comp_idx]);
  stream = &(read_streams[read_comp_idx]);

  /* First we can free up the read stream, kept from rekeying. */
  if (comp->use_zlib == flags &&
      comp->stream_ready) {
  
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "done decompressing data: decompressed %" PR_LU " bytes to %" PR_LU
      " bytes of data (%.2f)", (pr_off_t) stream->total_in,
      (pr_off_t) stream->total_out,
      stream->total_in == 0 ? 0.0 :
        (float) stream->total_out / stream->total_in);

    inflateEnd(stream);
    comp->use_zlib = FALSE;
    comp->stream_ready = FALSE;

    /* Now we can switch the index. */
    if (read_comp_idx == 1) {
      read_comp_idx = 0;
      return;
    }

    read_comp_idx = 1;
  }
}
Exemplo n.º 17
0
int sftp_compress_init_write(int flags) {
  struct sftp_compress *comp;
  z_stream *stream;

  switch_write_compress(flags);

  comp = &(write_compresses[write_comp_idx]);
  stream = &(write_streams[write_comp_idx]);

  if (comp->use_zlib == flags &&
      !comp->stream_ready) {
    int zres;

    zres = deflateInit(stream, Z_DEFAULT_COMPRESSION);
    if (zres != Z_OK) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error preparing compression stream (%d)", zres);
    }

    pr_event_generate("mod_sftp.ssh.server-compression", NULL);
    comp->stream_ready = TRUE;
  }

  return 0;
}
Exemplo n.º 18
0
int sftp_mac_set_read_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
    const char *h, uint32_t hlen) {
  const unsigned char *id = NULL;
  char *buf, *ptr;
  uint32_t buflen, bufsz, id_len;
  char letter;
  size_t blocksz;
  struct sftp_mac *mac;
  HMAC_CTX *mac_ctx;

  switch_read_mac();

  mac = &(read_macs[read_mac_idx]);
  mac_ctx = &(read_ctxs[read_mac_idx]);

  bufsz = buflen = 1024;
  ptr = buf = sftp_msg_getbuf(p, bufsz);

  /* Need to use SSH2-style format of K for the key. */
  sftp_msg_write_mpint(&buf, &buflen, k);

  id_len = sftp_session_get_id(&id);

  /* HASH(K || H || "E" || session_id) */
  letter = 'E';
  set_mac_key(mac, hash, ptr, (bufsz - buflen), h, hlen, &letter, id, id_len);

#if OPENSSL_VERSION_NUMBER > 0x000907000L
  HMAC_CTX_init(mac_ctx);

# if OPENSSL_VERSION_NUMBER >= 0x10000001L
  if (HMAC_Init_ex(mac_ctx, mac->key, mac->key_len, mac->digest, NULL) != 1) {
    pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error initializing HMAC: %s", sftp_crypto_get_errors());
    errno = EPERM;
    return -1;
  }

# else
  HMAC_Init_ex(mac_ctx, mac->key, mac->key_len, mac->digest, NULL);
# endif /* OpenSSL-1.0.0 and later */

#else
  /* Reset the HMAC context. */
  HMAC_Init(mac_ctx, NULL, 0, NULL);
  HMAC_Init(mac_ctx, mac->key, mac->key_len, mac->digest);
#endif

  if (mac->mac_len == 0) {
    blocksz = EVP_MD_size(mac->digest);

  } else {
    blocksz = mac->mac_len;
  }

  pr_memscrub(ptr, bufsz);
  sftp_mac_set_block_size(blocksz);
  return 0;
}
Exemplo n.º 19
0
struct dirent *vroot_fsio_readdir(pr_fs_t *fs, void *dirh) {
  struct dirent *dent = NULL;

next_dent:
  dent = readdir((DIR *) dirh);

  if (vroot_dir_aliases != NULL) {
    char **elts;

    elts = vroot_dir_aliases->elts;

    if (dent != NULL) {
      register unsigned int i;

      /* If this dent has the same name as an alias, the alias wins.
       * This is similar to a mounted filesystem, which hides any directories
       * underneath the mount point for the duration of the mount.
       */

      /* Yes, this is a linear scan; it assumes that the number of configured
       * aliases for a site will be relatively few.  Should this assumption
       * not be borne out by reality, then we should switch to using a
       * table, not an array_header, for storing the aliased paths.
       */

      for (i = 0; i < vroot_dir_aliases->nelts; i++) {
        if (strcmp(dent->d_name, elts[i]) == 0) {
          (void) pr_log_writefile(vroot_logfd, MOD_VROOT_VERSION,
            "skipping directory entry '%s', as it is aliased", dent->d_name);
          goto next_dent;
        }
      }

    } else {
      if (vroot_dir_idx < 0 ||
          vroot_dir_idx >= vroot_dir_aliases->nelts) {
        return NULL;
      }

      memset(vroot_dent, 0, vroot_dentsz);

      if (vroot_dent_namesz == 0) {
        sstrncpy(vroot_dent->d_name, elts[vroot_dir_idx++],
          sizeof(vroot_dent->d_name));

      } else {
        sstrncpy(vroot_dent->d_name, elts[vroot_dir_idx++],
          vroot_dent_namesz);
      }

      return vroot_dent;
    }
  }

  return dent;
}
Exemplo n.º 20
0
static int sftppam_sess_init(void) {
  config_rec *c;

  c = find_config(main_server->conf, CONF_PARAM, "SFTPPAMEngine", FALSE);
  if (c != NULL) {
    int engine;

    engine = *((int *) c->argv[0]);
    if (engine == FALSE) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_PAM_VERSION,
        "disabled by SFTPPAMEngine setting, unregistered 'pam' driver");
      sftp_kbdint_unregister_driver("pam");
      return 0;
    }
  }

  /* To preserve the principle of least surprise, also check for the AuthPAM
   * directive.
   */
  c = find_config(main_server->conf, CONF_PARAM, "AuthPAM", FALSE);
  if (c != NULL) {
    unsigned char auth_pam;

    auth_pam = *((unsigned char *) c->argv[0]);
    if (auth_pam == FALSE) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_PAM_VERSION,
        "disabled by AuthPAM setting, unregistered 'pam' driver");
      sftp_kbdint_unregister_driver("pam");
      return 0;
    }
  }

  c = find_config(main_server->conf, CONF_PARAM, "SFTPPAMServiceName", FALSE);
  if (c != NULL) {
    sftppam_service = c->argv[0];
  }

  pr_trace_msg(trace_channel, 8, "using PAM service name '%s'",
    sftppam_service);

  return 0;
}
Exemplo n.º 21
0
static array_header *counter_file_read(pr_fh_t *fh) {
  char buf[PR_TUNABLE_BUFFER_SIZE];
  array_header *ids = make_array(counter_pool, 0, sizeof(int));

  /* Read the list of IDs in the CounterFile into an array. */

  if (counter_file_lock(fh, LOCK_SH) < 0) {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "error read-locking CounterFile '%s': %s", fh->fh_path, strerror(errno));
  }

  if (pr_fsio_lseek(fh, 0, SEEK_SET) < 0) {
    int xerrno = errno;

    counter_file_lock(fh, LOCK_UN);
    errno = xerrno;

    return NULL;
  }

  memset(buf, '\0', sizeof(buf));
  while (pr_fsio_gets(buf, sizeof(buf), fh) != NULL) {
    int id;

    pr_signals_handle();

    id = atoi(buf);
    if (id < 0) {
      continue;
    }

    *((int *) push_array(ids)) = id;
  }

  if (counter_file_lock(fh, LOCK_UN) < 0) {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "error unlocking CounterFile '%s': %s", fh->fh_path, strerror(errno));
  }

  return ids;
}
Exemplo n.º 22
0
static int forward_dst_filter(pool *p, const char *hostport) {
#ifdef PR_USE_REGEX
  config_rec *c;
  pr_regex_t *pre;
  int negated = FALSE, res;

  c = find_config(main_server->conf, CONF_PARAM, "ProxyForwardTo", FALSE);
  if (c == NULL) {
    return 0;
  }

  pre = c->argv[0];
  negated = *((int *) c->argv[1]);

  res = pr_regexp_exec(pre, hostport, 0, NULL, 0, 0, 0);
  if (res == 0) {
    /* Pattern matched */
    if (negated == TRUE) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "host/port '%.100s' matched ProxyForwardTo !%s, rejecting",
        hostport, pr_regexp_get_pattern(pre));

      errno = EPERM;
      return -1;
    }

  } else {
    /* Pattern NOT matched */
    if (negated == FALSE) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "host/port '%.100s' did not match ProxyForwardTo %s, rejecting",
        hostport, pr_regexp_get_pattern(pre));
      errno = EPERM;
      return -1;
    }
  }
#endif /* PR_USE_REGEX */
  return 0;
}
Exemplo n.º 23
0
int sftp_tap_set_policy(const char *policy) {
  register unsigned int i;

  if (tap_pool) {

    /* Special case: IFF the existing policy is 'none' AND the given
     * policy is 'rogaway', just return.  The 'none' policy must have been
     * explicitly configured, and it should override the automatic use of
     * the 'rogaway' policy.
     */
    if (strncmp(curr_policy.policy, "none", 5) == 0 &&
        strncasecmp(policy, "rogaway", 8) == 0) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "'none' traffic policy explicitly configured, ignoring '%s' policy",
        policy);
      return 0;
    }

    destroy_pool(tap_pool);

    if (tap_timerno > 0) {
      pr_timer_remove(tap_timerno, &sftp_module);
      tap_timerno = -1;
    }
  }

  tap_pool = make_sub_pool(sftp_pool);
  pr_pool_tag(tap_pool, "SFTP TAP Pool");

  memset(&curr_policy, 0, sizeof(struct sftp_tap_policy));

  for (i = 0; tap_policies[i].policy; i++) {
    if (strcasecmp(tap_policies[i].policy, policy) == 0) {
      copy_policy(&curr_policy, &(tap_policies[i]));
      set_policy_chance(&curr_policy);
      set_policy_timer(&curr_policy);
      return 0;
    }
  }

  errno = ENOENT;
  return -1;
}
Exemplo n.º 24
0
static void switch_read_cipher(void) {
  /* First, clear the context of the existing read cipher, if any. */
  if (read_ciphers[read_cipher_idx].key) {
    clear_cipher(&(read_ciphers[read_cipher_idx]));
    if (EVP_CIPHER_CTX_cleanup(read_ctxs[read_cipher_idx]) != 1) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error clearing cipher context: %s", sftp_crypto_get_errors());
    }
 
    cipher_blockszs[read_cipher_idx] = SFTP_CIPHER_DEFAULT_BLOCK_SZ; 

    /* Now we can switch the index. */
    if (read_cipher_idx == 1) {
      read_cipher_idx = 0;
      return;
    }

    read_cipher_idx = 1;
  }
}
Exemplo n.º 25
0
/* If the chosen cipher requires that we discard some of the initial bytes of
 * the cipher stream, then do so.  (This is mostly for any RC4 ciphers.)
 */
static int set_cipher_discarded(struct sftp_cipher *cipher,
    EVP_CIPHER_CTX *cipher_ctx) {
  unsigned char *garbage_in, *garbage_out;

  if (cipher->discard_len == 0) {
    return 0;
  }

  garbage_in = malloc(cipher->discard_len);
  if (garbage_in == NULL) {
    pr_log_pri(PR_LOG_ALERT, MOD_SFTP_VERSION ": Out of memory!");
    _exit(1);
  }

  garbage_out = malloc(cipher->discard_len);
  if (garbage_out == NULL) {
    pr_log_pri(PR_LOG_ALERT, MOD_SFTP_VERSION ": Out of memory!");
    free(garbage_in);
    _exit(1);
  }

  if (EVP_Cipher(cipher_ctx, garbage_out, garbage_in,
      cipher->discard_len) != 1) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error ciphering discard data: %s", sftp_crypto_get_errors());
    free(garbage_in);
    pr_memscrub(garbage_out, cipher->discard_len);
    free(garbage_out);

    return -1;
  }

  free(garbage_in);
  pr_memscrub(garbage_out, cipher->discard_len);
  free(garbage_out);

  return 0;
}
Exemplo n.º 26
0
int proxy_conn_connect_timeout_cb(CALLBACK_FRAME) {
  struct proxy_session *proxy_sess;
  pr_netaddr_t *server_addr;

  proxy_sess = pr_table_get(session.notes, "mod_proxy.proxy-session", NULL);
  server_addr = pr_table_get(session.notes, "mod_proxy.proxy-connect-address",
    NULL);

  (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
    "timed out connecting to %s:%d after %d %s",
    pr_netaddr_get_ipstr(server_addr), ntohs(pr_netaddr_get_port(server_addr)),
    proxy_sess->connect_timeout,
    proxy_sess->connect_timeout != 1 ? "seconds" : "second");

  pr_event_generate("mod_proxy.timeout-connect", NULL);

  pr_log_pri(PR_LOG_NOTICE, "%s", "Connect timed out, disconnected");
  pr_session_disconnect(&proxy_module, PR_SESS_DISCONNECT_TIMEOUT,
    "ProxyTimeoutConnect");

  /* Do not restart the timer (should never be reached). */
  return 0;
}
Exemplo n.º 27
0
int sftp_auth_password(struct ssh2_packet *pkt, cmd_rec *pass_cmd,
                       const char *orig_user, const char *user, const char *service,
                       unsigned char **buf, uint32_t *buflen, int *send_userauth_fail) {
    const char *cipher_algo, *mac_algo;
    char *passwd;
    int have_new_passwd, res;
    struct passwd *pw;

    cipher_algo = sftp_cipher_get_read_algo();
    mac_algo = sftp_mac_get_read_algo();

    if (strncmp(cipher_algo, "none", 5) == 0 ||
            strncmp(mac_algo, "none", 5) == 0) {

        if (sftp_opts & SFTP_OPT_ALLOW_INSECURE_LOGIN) {
            (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                    "WARNING: cipher algorithm '%s' or MAC algorithm '%s' INSECURE for "
                                    "password authentication (SFTPOption AllowInsecureLogin in effect)",
                                    cipher_algo, mac_algo);

        } else {
            (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                    "cipher algorithm '%s' or MAC algorithm '%s' unacceptable for "
                                    "password authentication, denying password authentication request",
                                    cipher_algo, mac_algo);
            *send_userauth_fail = TRUE;
            errno = EPERM;
            return 0;
        }
    }

    /* XXX We currently don't do anything with this. */
    have_new_passwd = sftp_msg_read_bool(pkt->pool, buf, buflen);
    if (have_new_passwd) {
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "%s",
                                "client says they have provided a new password; this functionality "
                                "is not currently supported");
    }

    passwd = sftp_msg_read_string(pkt->pool, buf, buflen);
    passwd = sftp_utf8_decode_str(pkt->pool, passwd);

    pass_cmd->arg = passwd;

    if (pr_cmd_dispatch_phase(pass_cmd, PRE_CMD, 0) < 0) {
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "authentication request for user '%s' blocked by '%s' handler",
                                orig_user, (char *) pass_cmd->argv[0]);

        pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
        pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);

        pr_memscrub(passwd, strlen(passwd));

        *send_userauth_fail = TRUE;
        errno = EPERM;
        return 0;
    }

    pw = pr_auth_getpwnam(pkt->pool, user);
    if (pw == NULL) {
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "no account for user '%s' found", user);

        pr_log_auth(PR_LOG_NOTICE,
                    "USER %s: no such user found from %s [%s] to %s:%d", user,
                    session.c->remote_name, pr_netaddr_get_ipstr(session.c->remote_addr),
                    pr_netaddr_get_ipstr(session.c->local_addr), session.c->local_port);

        pr_memscrub(passwd, strlen(passwd));

        *send_userauth_fail = TRUE;
        errno = ENOENT;
        return 0;
    }

    res = pr_auth_authenticate(pkt->pool, user, passwd);
    pr_memscrub(passwd, strlen(passwd));

    switch (res) {
    case PR_AUTH_OK:
        break;

    case PR_AUTH_NOPWD:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "password authentication for user '%s' failed: No such user", user);
        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): No such user found",
                    user);
        *send_userauth_fail = TRUE;
        errno = ENOENT;
        return 0;

    case PR_AUTH_BADPWD:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "password authentication for user '%s' failed: Incorrect password",
                                user);
        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Incorrect password",
                    user);
        *send_userauth_fail = TRUE;
        errno = EINVAL;
        return 0;

    case PR_AUTH_AGEPWD:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "password authentication for user '%s' failed: Password expired",
                                user);
        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Password expired",
                    user);
        *send_userauth_fail = TRUE;
        errno = EINVAL;
        return 0;

    case PR_AUTH_DISABLEDPWD:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "password authentication for user '%s' failed: Account disabled",
                                user);
        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Account disabled",
                    user);
        *send_userauth_fail = TRUE;
        errno = EINVAL;
        return 0;

    default:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
                                "unknown authentication value (%d), returning error", res);
        *send_userauth_fail = TRUE;
        errno = EINVAL;
        return 0;
    }

    return 1;
}
Exemplo n.º 28
0
/* This getline() function is quite similar to pr_fsio_getline(), except
 * that it a) enforces the 72-byte max line length from RFC4716, and b)
 * properly handles lines ending with CR, LF, or CRLF.
 *
 * Technically it allows one more byte than necessary, since the worst case
 * is 74 bytes (72 + CRLF); this also means 73 + CR or 73 + LF.  The extra
 * byte is for the terminating NUL.
 */
static char *filestore_getline(sftp_keystore_t *store, pool *p) {
  char linebuf[75], *line = "", *res;
  struct filestore_data *store_data = store->keystore_data;

  while (TRUE) {
    size_t linelen;

    pr_signals_handle();

    memset(&linebuf, '\0', sizeof(linebuf));
    res = pr_fsio_gets(linebuf, sizeof(linebuf) - 1, store_data->fh);

    if (res == NULL) {
      if (errno == EINTR) {
        continue;
      }

      pr_trace_msg(trace_channel, 10, "reached end of '%s', no matching "
        "key found", store_data->path);
      errno = EOF;
      return NULL;
    }

    linelen = strlen(linebuf);
    if (linelen >= 1) {
      if (linebuf[linelen - 1] == '\r' ||
          linebuf[linelen - 1] == '\n') {
        char *tmp;
        unsigned int header_taglen, header_valuelen;
        int have_line_continuation = FALSE;

        store_data->lineno++;

        linebuf[linelen - 1] = '\0';
        line = pstrcat(p, line, linebuf, NULL);

        if (line[strlen(line) - 1] == '\\') {
          have_line_continuation = TRUE;
          line[strlen(line) - 1] = '\0';
        }

        tmp = strchr(line, ':');
        if (tmp == NULL) {
          return line;
        } 

        /* We have a header.  Make sure the header tag is not longer than
         * the specified length of 64 bytes, and that the header value is
         * not longer than 1024 bytes.
         */
        header_taglen = tmp - line;
        if (header_taglen > 64) {
          (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
            "header tag too long (%u) on line %u of '%s'", header_taglen,
            store_data->lineno, store_data->path);
          errno = EINVAL;
          return NULL;
        }

        /* Header value starts at 2 after the ':' (one for the mandatory
         * space character.
         */
        header_valuelen = strlen(line) - (header_taglen + 2);
        if (header_valuelen > 1024) {
          (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
            "header value too long (%u) on line %u of '%s'", header_valuelen,
            store_data->lineno, store_data->path);
          errno = EINVAL;
          return NULL;
        }

        if (!have_line_continuation) {
          return line;
        }

        continue;

      } else if (linelen >= 2 &&
          linebuf[linelen - 2] == '\r' &&
          linebuf[linelen - 1] == '\n') {
        char *tmp;
        unsigned int header_taglen, header_valuelen;
        int have_line_continuation = FALSE;

        store_data->lineno++;

        linebuf[linelen - 2] = '\0';
        linebuf[linelen - 1] = '\0';
        line = pstrcat(p, line, linebuf, NULL);

        if (line[strlen(line) - 1] == '\\') {
          have_line_continuation = TRUE;
          line[strlen(line) - 1] = '\0';
        }

        tmp = strchr(line, ':');
        if (tmp == NULL) {
          return line;
        } 

        /* We have a header.  Make sure the header tag is not longer than
         * the specified length of 64 bytes, and that the header value is
         * not longer than 1024 bytes.
         */
        header_taglen = tmp - line;
        if (header_taglen > 64) {
          (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
            "header tag too long (%u) on line %u of '%s'", header_taglen,
            store_data->lineno, store_data->path);
          errno = EINVAL;
          return NULL;
        }

        /* Header value starts at 2 after the ':' (one for the mandatory
         * space character.
         */
        header_valuelen = strlen(line) - (header_taglen + 2);
        if (header_valuelen > 1024) {
          (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
            "header value too long (%u) on line %u of '%s'", header_valuelen,
            store_data->lineno, store_data->path);
          errno = EINVAL;
          return NULL;
        }

        if (!have_line_continuation) {
          return line;
        }

        continue;

      } else {
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
          "line too long (%lu) on line %u of '%s'", (unsigned long) linelen,
          store_data->lineno, store_data->path);
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
          "Make sure that '%s' is a RFC4716 formatted key", store_data->path);
        errno = EINVAL;
        break;
      }
    }
  }

  return NULL;
}
Exemplo n.º 29
0
int sftp_auth_hostbased(struct ssh2_packet *pkt, cmd_rec *pass_cmd,
    const char *orig_user, const char *user, const char *service,
    unsigned char **buf, uint32_t *buflen, int *send_userauth_fail) {
  struct passwd *pw;
  char *hostkey_algo, *host_fqdn, *host_user, *host_user_utf8;
  const char *fp = NULL;
  unsigned char *hostkey_data, *signature_data;
  unsigned char *buf2, *ptr2;
  const unsigned char *id;
  uint32_t buflen2, bufsz2, hostkey_datalen, id_len, signature_len;
  enum sftp_key_type_e pubkey_type;

  if (pr_cmd_dispatch_phase(pass_cmd, PRE_CMD, 0) < 0) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "authentication request for user '%s' blocked by '%s' handler",
      orig_user, (char *) pass_cmd->argv[0]);

    pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0);
    pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0);

    *send_userauth_fail = TRUE;
    errno = EPERM;
    return 0;
  }

  hostkey_algo = sftp_msg_read_string(pkt->pool, buf, buflen);
  if (hostkey_algo == NULL) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "missing required host key algorithm, rejecting request");

    *send_userauth_fail = TRUE;
    errno = EINVAL;
    return 0;
  }

  hostkey_datalen = sftp_msg_read_int(pkt->pool, buf, buflen);
  hostkey_data = sftp_msg_read_data(pkt->pool, buf, buflen, hostkey_datalen);

  host_fqdn = sftp_msg_read_string(pkt->pool, buf, buflen);

  host_user_utf8 = sftp_msg_read_string(pkt->pool, buf, buflen);
  host_user = sftp_utf8_decode_str(pkt->pool, host_user_utf8);

  signature_len = sftp_msg_read_int(pkt->pool, buf, buflen);
  signature_data = sftp_msg_read_data(pkt->pool, buf, buflen, signature_len);

  pr_trace_msg(trace_channel, 9,
    "client sent '%s' host key, FQDN %s, and remote user '%s'",
    hostkey_algo, host_fqdn, host_user);

  if (strncmp(hostkey_algo, "ssh-rsa", 8) == 0) {
    pubkey_type = SFTP_KEY_RSA;

  } else if (strncmp(hostkey_algo, "ssh-dss", 8) == 0) {
    pubkey_type = SFTP_KEY_DSA;

#ifdef PR_USE_OPENSSL_ECC
  } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) {
    pubkey_type = SFTP_KEY_ECDSA_256;

  } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) {
    pubkey_type = SFTP_KEY_ECDSA_384;

  } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) {
    pubkey_type = SFTP_KEY_ECDSA_521;
#endif /* PR_USE_OPENSSL_ECC */

  /* XXX Need to support X509v3 certs here */

  } else {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "unsupported host key algorithm '%s' requested, rejecting request",
      hostkey_algo);

    *send_userauth_fail = TRUE;
    errno = EINVAL;
    return 0;
  }

  if (sftp_keys_verify_pubkey_type(pkt->pool, hostkey_data, hostkey_datalen,
      pubkey_type) != TRUE) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "unable to verify that given host key matches given '%s' algorithm",
      hostkey_algo);

    *send_userauth_fail = TRUE;
    errno = EINVAL;
    return 0;
  }

#ifdef OPENSSL_FIPS
  if (FIPS_mode()) {
    fp = sftp_keys_get_fingerprint(pkt->pool, hostkey_data, hostkey_datalen,
      SFTP_KEYS_FP_DIGEST_SHA1);
    if (fp != NULL) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "public key SHA1 fingerprint: %s", fp);

    } else {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error obtaining public key SHA1 fingerprint: %s", strerror(errno));
    }

  } else {
#endif /* OPENSSL_FIPS */
    fp = sftp_keys_get_fingerprint(pkt->pool, hostkey_data, hostkey_datalen,
      SFTP_KEYS_FP_DIGEST_MD5);
    if (fp != NULL) {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "public key MD5 fingerprint: %s", fp);

    } else {
      (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
        "error obtaining public key MD5 fingerprint: %s", strerror(errno));
    }
#ifdef OPENSSL_FIPS
  }
#endif /* OPENSSL_FIPS */

  pw = pr_auth_getpwnam(pkt->pool, user);
  if (pw == NULL) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "no account for user '%s' found", user);

    pr_log_auth(PR_LOG_NOTICE,
      "USER %s: no such user found from %s [%s] to %s:%d", user,
      session.c->remote_name, pr_netaddr_get_ipstr(session.c->remote_addr),
      pr_netaddr_get_ipstr(session.c->local_addr), session.c->local_port);

    *send_userauth_fail = TRUE;
    errno = ENOENT;
    return 0;
  }

  /* XXX Should we check the given FQDN here against the client's actual
   * DNS name and/or IP address?  Or leave that up to the keystore's
   * verify_host_key() function?
   */

  if (sftp_blacklist_reject_key(pkt->pool, hostkey_data, hostkey_datalen)) {
    *send_userauth_fail = TRUE;
    errno = EACCES;
    return 0;
  }

  /* The client signed the request as well; we need to authenticate the
   * host with the given key now.  If that succeeds, we use the signature to
   * verify the request.  And if that succeeds, then we're done authenticating.
   */

  if (sftp_keystore_verify_host_key(pkt->pool, user, host_fqdn, host_user,
      hostkey_data, hostkey_datalen) < 0) {
    *send_userauth_fail = TRUE;
    errno = EACCES;
    return 0;
  }

  /* Make sure the signature matches as well. */

  id_len = sftp_session_get_id(&id);

  /* XXX Is this buffer large enough?  Too large? */
  bufsz2 = buflen2 = 2048;
  ptr2 = buf2 = sftp_msg_getbuf(pkt->pool, bufsz2);

  sftp_msg_write_data(&buf2, &buflen2, id, id_len, TRUE);
  sftp_msg_write_byte(&buf2, &buflen2, SFTP_SSH2_MSG_USER_AUTH_REQUEST);
  sftp_msg_write_string(&buf2, &buflen2, orig_user);

  if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_SERVICE_IN_HOST_SIG)) {
    sftp_msg_write_string(&buf2, &buflen2, service);

  } else {
    sftp_msg_write_string(&buf2, &buflen2, "ssh-userauth");
  }

  sftp_msg_write_string(&buf2, &buflen2, "hostbased");
  sftp_msg_write_string(&buf2, &buflen2, hostkey_algo);
  sftp_msg_write_data(&buf2, &buflen2, hostkey_data, hostkey_datalen, TRUE);
  sftp_msg_write_string(&buf2, &buflen2, host_fqdn);
  sftp_msg_write_string(&buf2, &buflen2, host_user_utf8);

  if (sftp_keys_verify_signed_data(pkt->pool, hostkey_algo, hostkey_data,
      hostkey_datalen, signature_data, signature_len, (unsigned char *) ptr2,
      (bufsz2 - buflen2)) < 0) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "failed to verify '%s' signature on hostbased auth request for "
      "user '%s', host %s", hostkey_algo, orig_user, host_fqdn);
    *send_userauth_fail = TRUE;
    return 0;
  }

  /* Make sure the user is authorized to login.  Normally this is checked
   * as part of the password verification process, but in the case of
   * hostbased authentication, there is no password to verify.
   */

  if (pr_auth_authorize(pkt->pool, user) != PR_AUTH_OK) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "authentication for user '%s' failed: User not authorized", user);
    pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): User not authorized "
      "for login", user);
    *send_userauth_fail = TRUE;
    errno = EACCES;
    return 0;
  }

  return 1;
}
Exemplo n.º 30
0
int sftp_kbdint_recv_response(pool *p, unsigned int expected_count,
    unsigned int *rcvd_count, const char ***responses) {
  register unsigned int i;
  unsigned char *buf;
  cmd_rec *cmd;
  array_header *list;
  uint32_t buflen, resp_count;
  struct ssh2_packet *pkt;
  char mesg_type;
  int res;

  if (p == NULL ||
      rcvd_count == NULL ||
      responses == NULL) {
    errno = EINVAL;
    return -1;
  }

  pkt = sftp_ssh2_packet_create(kbdint_pool);

  res = sftp_ssh2_packet_read(sftp_conn->rfd, pkt);
  if (res < 0) {
    destroy_pool(pkt->pool);
    return res;
  }

  mesg_type = sftp_ssh2_packet_get_mesg_type(pkt);
  if (mesg_type != SFTP_SSH2_MSG_USER_AUTH_INFO_RESP) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "expecting USER_AUTH_INFO_RESP message, received %s (%d)",
      sftp_ssh2_packet_get_mesg_type_desc(mesg_type), mesg_type);
    destroy_pool(pkt->pool);
    errno = EPERM;
    return -1;
  }

  cmd = pr_cmd_alloc(pkt->pool, 2, pstrdup(pkt->pool, "USER_AUTH_INFO_RESP"));
  cmd->arg = "(data)";

  pr_trace_msg(trace_channel, 9,
    "reading USER_AUTH_INFO_RESP message from client");

  buf = pkt->payload;
  buflen = pkt->payload_len;

  resp_count = sftp_msg_read_int(pkt->pool, &buf, &buflen);

  /* Ensure that the number of responses sent by the client is the same
   * as the number of challenges sent, lest a malicious client attempt to
   * trick us into allocating too much memory (Bug#3973).
   */
  if (resp_count != expected_count) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "sent %lu %s, but received %lu %s", (unsigned long) expected_count,
      expected_count != 1 ? "challenges" : "challenge",
      (unsigned long) resp_count, resp_count != 1 ? "responses" : "response");
    destroy_pool(pkt->pool);
    errno = EPERM;
    return -1;
  }

  if (resp_count > SFTP_KBDINT_MAX_RESPONSES) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "received too many responses (%lu > max %lu), rejecting",
      (unsigned long) resp_count, (unsigned long) SFTP_KBDINT_MAX_RESPONSES);
    destroy_pool(pkt->pool);
    errno = EPERM;
    return -1;
  }

  list = make_array(p, resp_count, sizeof(char *));
  for (i = 0; i < resp_count; i++) {
    char *resp;

    resp = sftp_msg_read_string(pkt->pool, &buf, &buflen);
    *((char **) push_array(list)) = pstrdup(p, sftp_utf8_decode_str(p, resp));
  }

  *rcvd_count = (unsigned int) resp_count;
  *responses = ((const char **) list->elts);
  return 0;
}