Esempio n. 1
0
/* Interpolates a pathname, expanding ~ notation if necessary
 */
char *dir_interpolate(pool *p, const char *path) {
  struct passwd *pw;
  char *user,*tmp;
  char *ret = (char *)path;

  if (!ret)
    return NULL;

  if (*ret == '~') {
    user = pstrdup(p, ret+1);
    tmp = strchr(user, '/');

    if (tmp)
      *tmp++ = '\0';

    if (!*user)
      user = session.user;

    pw = pr_auth_getpwnam(p, user);

    if (!pw) {
      errno = ENOENT;
      return NULL;
    }

    ret = pdircat(p, pw->pw_dir, tmp, NULL);
  }

  return ret;
}
Esempio n. 2
0
/* Determine logging-in user's access table locations.  This function was
 * "borrowed" (ie plagiarized/copied/whatever) liberally from modules/
 * mod_auth.c -- the _true_ author is MacGuyver <*****@*****.**>.
 */
static char *wrap_get_user_table(cmd_rec *cmd, char *user,
    char *path) {

  char *real_path = NULL;
  struct passwd *pw = NULL;

  pw = pr_auth_getpwnam(cmd->pool, user);

  /* Handle the case where the given user does not exist. */
  if (pw == NULL) {
    return NULL;
  }

  /* For the dir_realpath() function to work, some session members need to
   * be set.
   */
  session.user = pstrdup(cmd->pool, pw->pw_name);
  session.login_uid = pw->pw_uid;

  PRIVS_USER
  real_path = dir_realpath(cmd->pool, path);
  PRIVS_RELINQUISH

  if (real_path)
    path = real_path;

  return path;
}
Esempio n. 3
0
END_TEST

START_TEST (auth_getpwnam_test) {
    int res;
    struct passwd *pw;
    authtable authtab;
    char *sym_name = "getpwnam";

    pw = pr_auth_getpwnam(NULL, NULL);
    fail_unless(pw == NULL, "Found pwnam unexpectedly");
    fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %d (%s)",
                errno, strerror(errno));

    pw = pr_auth_getpwnam(p, PR_TEST_AUTH_NAME);
    fail_unless(pw == NULL, "Found pwnam unexpectedly");
    fail_unless(getpwnam_count == 0, "Expected call count 0, got %u",
                getpwnam_count);
    mark_point();

    /* Load the appropriate AUTH symbol, and call it. */

    memset(&authtab, 0, sizeof(authtab));
    authtab.name = sym_name;
    authtab.handler = handle_getpwnam;
    authtab.m = &unit_tests_module;
    res = pr_stash_add_symbol(PR_SYM_AUTH, &authtab);
    fail_unless(res == 0, "Failed to add '%s' AUTH symbol: %s", sym_name,
                strerror(errno));

    mark_point();

    pw = pr_auth_getpwnam(p, PR_TEST_AUTH_NAME);
    fail_unless(pw != NULL, "Failed to find pwnam: %s", strerror(errno));
    fail_unless(getpwnam_count == 1, "Expected call count 1, got %u",
                getpwnam_count);

    mark_point();

    pw = pr_auth_getpwnam(p, "other");
    fail_unless(pw == NULL, "Found pwnam for user 'other' unexpectedly");
    fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
                errno, strerror(errno));
    fail_unless(getpwnam_count == 2, "Expected call count 2, got %u",
                getpwnam_count);

    pr_stash_remove_symbol(PR_SYM_AUTH, sym_name, &unit_tests_module);
}
Esempio n. 4
0
/* Interpolates a pathname, expanding ~ notation if necessary
 */
char *dir_interpolate(pool *p, const char *path) {
  struct passwd *pw;
  char *res = NULL;

  if (p == NULL ||
      path == NULL) {
    errno = EINVAL;
    return NULL;
  }

  if (*path == '~') {
    char *ptr, *user;

    user = pstrdup(p, path + 1);
    ptr = strchr(user, '/');
    if (ptr) {
      *ptr++ = '\0';
    }

    if (!*user) {
      user = session.user;
    }

    pw = pr_auth_getpwnam(p, user);
    if (pw == NULL) {
      errno = ENOENT;
      return NULL;
    }

    res = pdircat(p, pw->pw_dir, ptr, NULL);

  } else {
    res = pstrdup(p, path);
  }

  return res;
}
Esempio n. 5
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;
}
Esempio n. 6
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;
}
Esempio n. 7
0
int sftp_auth_publickey(struct ssh2_packet *pkt, cmd_rec *pass_cmd,
    const char *orig_user, const char *user, const char *service, char **buf,
    uint32_t *buflen, int *send_userauth_fail) {
  int have_signature, pubkey_type;
  char *pubkey_algo = NULL, *pubkey_data;
  const char *fp = NULL;
  uint32_t pubkey_len;
  struct passwd *pw;

  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, 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;
  }

  have_signature = sftp_msg_read_bool(pkt->pool, buf, buflen);

  if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_HAVE_PUBKEY_ALGO)) {
    pubkey_algo = sftp_msg_read_string(pkt->pool, buf, buflen);
  }
  pubkey_len = sftp_msg_read_int(pkt->pool, buf, buflen);
  pubkey_data = sftp_msg_read_data(pkt->pool, buf, buflen, pubkey_len);

  if (pubkey_algo == NULL) {
    /* The client did not send the string identifying the public key algorithm.
     * Thus we need to extract the algorithm string from the public key data.
     */
    pubkey_algo = sftp_msg_read_string(pkt->pool, &pubkey_data, &pubkey_len);
  }

  pr_trace_msg(trace_channel, 9, "client sent '%s' public key %s",
    pubkey_algo, have_signature ? "with signature" : "without signature");

  if (strncmp(pubkey_algo, "ssh-rsa", 8) == 0) {
    pubkey_type = EVP_PKEY_RSA;

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

  /* XXX This is where we would add support for X509 public keys, e.g.:
   *
   *  x509v3-ssh-dss
   *  x509v3-ssh-rsa
   *  x509v3-sign (older)
   *
   */

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

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

  if (sftp_keys_verify_pubkey_type(pkt->pool, pubkey_data, pubkey_len,
      pubkey_type) != TRUE) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "unable to verify that given public key matches given '%s' algorithm",
      pubkey_algo);

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

#ifdef OPENSSL_FIPS
  if (FIPS_mode()) {
    fp = sftp_keys_get_fingerprint(pkt->pool, pubkey_data, pubkey_len,
      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, pubkey_data, pubkey_len,
      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;
  }

  if (!have_signature) {
    /* We don't perform the actual authentication just yet; we need to
     * let the client know that the pubkey algorithms are acceptable.
     */
    if (send_pubkey_ok(pubkey_algo, pubkey_data, pubkey_len) < 0) {
      return -1;
    }

    return 0;

  } else {
    const unsigned char *id;
    char *buf2, *ptr2, *signature_data;
    uint32_t buflen2, bufsz2, id_len, signature_len;

    /* XXX This should become a more generic "is this key data
     * usable/acceptable?" check (and take the pubkey_type parameter), so that
     * that is where we would check the validity/usability of an X509v3 cert
     * (if a cert), or if the key is on the blacklist (if a key).
     */

    if (sftp_blacklist_reject_key(pkt->pool, pubkey_data, pubkey_len)) {
      *send_userauth_fail = TRUE;
      errno = EPERM;
      return 0;
    }

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

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

    /* XXX Need to pass the pubkey_type here as well, so that the
     * verification routines can handle different databases of keys/certs.
     * 
     * For X509v3 certs, we will want a way to enforce/restrict which
     * user names can be used with the provided cert.  Perhaps a database
     * mapping cert fingerprints to user names/UIDs?  Configurable callback
     * check (HOOK?), for modules to enforce.
     */

    if (sftp_keystore_verify_user_key(pkt->pool, user, pubkey_data,
        pubkey_len) < 0) {
      *send_userauth_fail = TRUE;
      return 0;
    }

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

    id_len = sftp_session_get_id(&id);

    /* Make sure to allocate a buffer large enough to hold the publickey
     * signature and data we want to send back.
     */
    bufsz2 = buflen2 = pubkey_len + 1024;
    ptr2 = buf2 = sftp_msg_getbuf(pkt->pool, bufsz2);

    sftp_msg_write_data(&buf2, &buflen2, (char *) 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_PUBKEY_SIG)) {
      sftp_msg_write_string(&buf2, &buflen2, service);

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

    if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_HAVE_PUBKEY_ALGO)) {
      sftp_msg_write_string(&buf2, &buflen2, "publickey");
      sftp_msg_write_bool(&buf2, &buflen2, TRUE);
      sftp_msg_write_string(&buf2, &buflen2, pubkey_algo);

    } else {
      sftp_msg_write_bool(&buf2, &buflen2, TRUE);
    }

    sftp_msg_write_data(&buf2, &buflen2, pubkey_data, pubkey_len, TRUE);

    if (sftp_keys_verify_signed_data(pkt->pool, pubkey_algo, pubkey_data,
        pubkey_len, 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 public key auth request for "
        "user '%s'", pubkey_algo, orig_user);
      *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
   * publickey 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;
}
Esempio n. 8
0
int sftp_auth_kbdint(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;
  struct passwd *pw;
  char *submethods;
  sftp_kbdint_driver_t *driver;
  int res = -1;

  if (sftp_kbdint_have_drivers() == 0) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "no 'keyboard-interactive' drivers currently registered, unable to "
      "authenticate user '%s' via 'keyboard-interactive' method", user);

    pr_log_auth(PR_LOG_NOTICE,
      "USER %s (Login failed): keyboard-interactive authentication disabled",
      user);

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

  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;
  }

  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;
  }

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

  /* XXX Is this too strict?  For PAM authentication, no -- but for S/Key or
   * one-time password authencation, maybe yes.
   */
  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 "
        "keyboard-interactive 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 "
        "keyboard-interactive authentication, denying authentication request",
        cipher_algo, mac_algo);

      pr_log_auth(PR_LOG_NOTICE,
        "USER %s (Login failed): cipher algorithm '%s' or MAC algorithm '%s' "
        "unsupported for keyboard-interactive authentication", user,
        cipher_algo, mac_algo);

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

  /* XXX Read off the deprecated language string. */
  sftp_msg_read_string(pkt->pool, buf, buflen);

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

  if (strlen(submethods) > 0) {
    pr_trace_msg(trace_channel, 8, "client suggested 'keyboard-interactive' "
      "methods: %s", submethods);
  }

  /* XXX get our own get_shared_name() function (see kex.c), to see if
   * any of the "hints" sent by the client match any of the registered
   * kbdint drivers.
   */

  driver = sftp_kbdint_first_driver();
  while (driver != NULL) {
    register unsigned int i;
    int skip_driver = FALSE;

    pr_signals_handle();

    /* If this driver has already successfully handled this user, skip it. */
    for (i = 0; i < kbdint_drivers->nelts; i++) {
      char *dri;

      dri = ((char **) kbdint_drivers->elts)[i];
      if (strcmp(driver->driver_name, dri) == 0) {
        skip_driver = TRUE;
        break;
      }
    }

    if (skip_driver) {
      pr_trace_msg(trace_channel, 9,
        "skipping already-used kbdint driver '%s' for user '%s'",
        driver->driver_name, user);
      driver = sftp_kbdint_next_driver();
      continue;
    }

    pr_trace_msg(trace_channel, 3, "trying kbdint driver '%s' for user '%s'",
      driver->driver_name, user);

    res = driver->open(driver, user);
    if (res < 0) {
      driver = sftp_kbdint_next_driver();
      continue;
    }

    res = driver->authenticate(driver, user);
    driver->close(driver);

    if (res == 0) {
      /* Store the driver name for future checking. */
      *((char **) push_array(kbdint_drivers)) = pstrdup(sftp_pool,
        driver->driver_name);
      break; 
    }

    driver = sftp_kbdint_next_driver();
  }

  if (res < 0) {
    *send_userauth_fail = TRUE;

    /* We explicitly want to use an errno value other than EPERM here, so
     * that the calling code allows the connecting client to make other
     * login attempts, rather than failing this authentication method
     * after a single failure (Bug#3921).
     */
    errno = EACCES;
    return 0;
  }

  return 1;
}
Esempio n. 9
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;
}