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