예제 #1
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_log_auth(PR_LOG_NOTICE,
                    "USER %s (Login failed): 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);

        pr_log_auth(PR_LOG_NOTICE,
                    "USER %s (Login failed): unsupported host key algorithm '%s' requested",
                    user, 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)) {
        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): requested host "
                    "key is blacklisted", user);

        *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) {
        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): authentication "
                    "via '%s' host key failed", user, hostkey_algo);

        *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);

        pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): signature "
                    "verification of '%s' host key failed", user, hostkey_algo);

        *send_userauth_fail = TRUE;
        errno = EACCES;
        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;
}
예제 #2
0
int proxy_session_setup_env(pool *p, const char *user, int flags) {
  struct passwd *pw;
  config_rec *c;
  int i, res = 0, xerrno = 0;
  const char *xferlog = NULL;

  session.hide_password = TRUE;

  /* Note: the given user name may not be known locally on the proxy; thus
   * having pr_auth_getpwnam() returning NULL here is not an unexpected
   * use case.
   */

  pw = pr_auth_getpwnam(p, user);
  if (pw != NULL) {
    if (pw->pw_uid == PR_ROOT_UID) {
      int root_login = FALSE;

      pr_event_generate("mod_auth.root-login", NULL);

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

      if (root_login == FALSE) {
        (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
          "root login attempted, denied by RootLogin configuration");
        pr_log_auth(PR_LOG_NOTICE, "SECURITY VIOLATION: Root login attempted.");
        return -1;
      }

      pr_log_auth(PR_LOG_WARNING, "ROOT proxy login successful");
    }

    res = pr_auth_is_valid_shell(main_server->conf, pw->pw_shell);
    if (res == FALSE) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "authentication for user '%s' failed: Invalid shell", user);
      pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Invalid shell: '%s'",
        user, pw->pw_shell);
      errno = EPERM;
      return -1;
    }

    res = pr_auth_banned_by_ftpusers(main_server->conf, pw->pw_name);
    if (res == TRUE) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "authentication for user '%s' failed: User in " PR_FTPUSERS_PATH, user);
      pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): User in "
        PR_FTPUSERS_PATH, pw->pw_name);
      errno = EPERM;
      return -1;
    }
  
    session.user = pstrdup(p, pw->pw_name);
    session.group = pstrdup(p, pr_auth_gid2name(p, pw->pw_gid));

    session.login_uid = pw->pw_uid;
    session.login_gid = pw->pw_gid;

  } else {
    session.user = pstrdup(session.pool, user);

    /* XXX What should session.group, session.login_uid, session.login_gid
     * be?  Kept as is?
     */
  }
 
  if (session.gids == NULL &&
      session.groups == NULL) {
    res = pr_auth_getgroups(p, session.user, &session.gids, &session.groups);
    if (res < 1 &&
        errno != ENOENT) {
      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
        "no supplemental groups found for user '%s'", session.user);
    }
  }

  if (flags & PROXY_SESSION_FL_CHECK_LOGIN_ACL) {
    int login_acl;

    login_acl = login_check_limits(main_server->conf, FALSE, TRUE, &i);
    if (!login_acl) {
      pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Limit configuration "
        "denies login", user);
      return -1;
    }
  }

  /* XXX Will users want wtmp logging for a proxy login? */
  session.wtmp_log = FALSE;

  c = find_config(main_server->conf, CONF_PARAM, "TransferLog", FALSE);
  if (c == NULL) {
    xferlog = PR_XFERLOG_PATH;

  } else {
    xferlog = c->argv[0];
  }

  PRIVS_ROOT

  if (strncasecmp(xferlog, "none", 5) == 0) {
    xferlog_open(NULL);

  } else {
    xferlog_open(xferlog);
  }

  res = xerrno = 0;

  if (pw != NULL) {
    res = set_groups(p, pw->pw_gid, session.gids);
    xerrno = errno;
  }

  PRIVS_RELINQUISH

  if (res < 0) {
    pr_log_pri(PR_LOG_WARNING, "unable to set process groups: %s",
      strerror(xerrno));
  }

  session.disable_id_switching = TRUE;

  session.proc_prefix = pstrdup(session.pool, session.c->remote_name);
  session.sf_flags = 0;

  pr_scoreboard_entry_update(session.pid,
    PR_SCORE_USER, session.user,
    PR_SCORE_CWD, pr_fs_getcwd(),
    NULL);

  if (session.group != NULL) {
    session.group = pstrdup(session.pool, session.group);
  }

  if (session.groups != NULL) {
    session.groups = copy_array_str(session.pool, session.groups);
  }

  proxy_sess_state |= PROXY_SESS_STATE_PROXY_AUTHENTICATED;
  pr_timer_remove(PR_TIMER_LOGIN, ANY_MODULE);
  return 0;
}