Index: crypto/openssh/INSTALL =================================================================== --- crypto/openssh/INSTALL +++ crypto/openssh/INSTALL @@ -66,6 +66,15 @@ http://www.jmknoble.net/software/x11-ssh-askpass/ +TCP Wrappers: + +If you wish to use the TCP wrappers functionality you will need at least +tcpd.h and libwrap.a, either in the standard include and library paths, +or in the directory specified by --with-tcp-wrappers. Version 7.6 is +known to work. + +http://ftp.porcupine.org/pub/security/index.html + LibEdit: sftp supports command-line editing via NetBSD's libedit. If your platform @@ -176,6 +185,9 @@ --with-osfsia, --without-osfsia will enable or disable OSF1's Security Integration Architecture. The default for OSF1 machines is enable. + +--with-tcp-wrappers will enable TCP Wrappers (/etc/hosts.allow|deny) +support. --with-md5-passwords will enable the use of MD5 passwords. Enable this if your operating system uses MD5 passwords and the system crypt() does Index: crypto/openssh/auth-pam.c =================================================================== --- crypto/openssh/auth-pam.c +++ crypto/openssh/auth-pam.c @@ -103,6 +103,7 @@ #include "ssh-gss.h" #endif #include "monitor_wrap.h" +#include "blacklist_client.h" extern ServerOptions options; extern struct sshbuf *loginmsg; @@ -875,6 +876,8 @@ free(msg); return (0); } + BLACKLIST_NOTIFY(BLACKLIST_BAD_USER, + sshpam_authctxt->user); error("PAM: %s for %s%.100s from %.100s", msg, sshpam_authctxt->valid ? "" : "illegal user ", sshpam_authctxt->user, Index: crypto/openssh/auth.c =================================================================== --- crypto/openssh/auth.c +++ crypto/openssh/auth.c @@ -24,6 +24,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include @@ -75,6 +76,7 @@ #include "ssherr.h" #include "compat.h" #include "channels.h" +#include "blacklist_client.h" /* import */ extern ServerOptions options; @@ -330,8 +332,11 @@ authmsg = "Postponed"; else if (partial) authmsg = "Partial"; - else + else { authmsg = authenticated ? "Accepted" : "Failed"; + if (authenticated) + BLACKLIST_NOTIFY(BLACKLIST_AUTH_OK, "ssh"); + } if ((extra = format_method_key(authctxt)) == NULL) { if (authctxt->auth_method_info != NULL) @@ -563,6 +568,9 @@ struct ssh *ssh = active_state; /* XXX */ #ifdef HAVE_LOGIN_CAP extern login_cap_t *lc; +#ifdef HAVE_AUTH_HOSTOK + const char *from_host, *from_ip; +#endif #ifdef BSD_AUTH auth_session_t *as; #endif @@ -598,6 +606,7 @@ } #endif if (pw == NULL) { + BLACKLIST_NOTIFY(BLACKLIST_BAD_USER, user); logit("Invalid user %.100s from %.100s port %d", user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); #ifdef CUSTOM_FAILED_LOGIN @@ -612,10 +621,25 @@ if (!allowed_user(pw)) return (NULL); #ifdef HAVE_LOGIN_CAP - if ((lc = login_getclass(pw->pw_class)) == NULL) { + if ((lc = login_getpwclass(pw)) == NULL) { debug("unable to get login class: %s", user); return (NULL); } +#ifdef HAVE_AUTH_HOSTOK + from_host = auth_get_canonical_hostname(ssh, options.use_dns); + from_ip = ssh_remote_ipaddr(ssh); + if (!auth_hostok(lc, from_host, from_ip)) { + debug("Denied connection for %.200s from %.200s [%.200s].", + pw->pw_name, from_host, from_ip); + return (NULL); + } +#endif /* HAVE_AUTH_HOSTOK */ +#ifdef HAVE_AUTH_TIMEOK + if (!auth_timeok(lc, time(NULL))) { + debug("LOGIN %.200s REFUSED (TIME)", pw->pw_name); + return (NULL); + } +#endif /* HAVE_AUTH_TIMEOK */ #ifdef BSD_AUTH if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 || auth_approval(as, lc, pw->pw_name, "ssh") <= 0) { Index: crypto/openssh/auth2.c =================================================================== --- crypto/openssh/auth2.c +++ crypto/openssh/auth2.c @@ -24,6 +24,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include @@ -52,6 +53,7 @@ #include "pathnames.h" #include "sshbuf.h" #include "ssherr.h" +#include "blacklist_client.h" #ifdef GSSAPI #include "ssh-gss.h" @@ -258,6 +260,10 @@ char *user, *service, *method, *style = NULL; int authenticated = 0; double tstart = monotime_double(); +#ifdef HAVE_LOGIN_CAP + login_cap_t *lc; + const char *from_host, *from_ip; +#endif if (authctxt == NULL) fatal("input_userauth_request: no authctxt"); @@ -408,8 +414,10 @@ } else { /* Allow initial try of "none" auth without failure penalty */ if (!partial && !authctxt->server_caused_failure && - (authctxt->attempt > 1 || strcmp(method, "none") != 0)) + (authctxt->attempt > 1 || strcmp(method, "none") != 0)) { authctxt->failures++; + BLACKLIST_NOTIFY(BLACKLIST_AUTH_FAIL, "ssh"); + } if (authctxt->failures >= options.max_authtries) { #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); Index: crypto/openssh/configure.ac =================================================================== --- crypto/openssh/configure.ac +++ crypto/openssh/configure.ac @@ -1493,6 +1493,61 @@ AC_MSG_RESULT([no]) fi +# Check whether user wants TCP wrappers support +TCPW_MSG="no" +AC_ARG_WITH([tcp-wrappers], + [ --with-tcp-wrappers[[=PATH]] Enable tcpwrappers support (optionally in PATH)], + [ + if test "x$withval" != "xno" ; then + saved_LIBS="$LIBS" + saved_LDFLAGS="$LDFLAGS" + saved_CPPFLAGS="$CPPFLAGS" + if test -n "${withval}" && \ + test "x${withval}" != "xyes"; then + if test -d "${withval}/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + fi + if test -d "${withval}/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + fi + LIBS="-lwrap $LIBS" + AC_MSG_CHECKING([for libwrap]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +#include +int deny_severity = 0, allow_severity = 0; + ]], [[ + hosts_access(0); + ]])], [ + AC_MSG_RESULT([yes]) + AC_DEFINE([LIBWRAP], [1], + [Define if you want + TCP Wrappers support]) + SSHDLIBS="$SSHDLIBS -lwrap" + TCPW_MSG="yes" + ], [ + AC_MSG_ERROR([*** libwrap missing]) + ]) + LIBS="$saved_LIBS" + fi + ] +) + # Check whether user wants to use ldns LDNS_MSG="no" AC_ARG_WITH(ldns, @@ -1696,6 +1751,8 @@ dnl Checks for library functions. Please keep in alphabetical order AC_CHECK_FUNCS([ \ + auth_hostok \ + auth_timeok \ Blowfish_initstate \ Blowfish_expandstate \ Blowfish_expand0state \ @@ -5305,6 +5362,7 @@ echo " OSF SIA support: $SIA_MSG" echo " KerberosV support: $KRB5_MSG" echo " SELinux support: $SELINUX_MSG" +echo " TCP Wrappers support: $TCPW_MSG" echo " MD5 password support: $MD5_MSG" echo " libedit support: $LIBEDIT_MSG" echo " libldns support: $LDNS_MSG" Index: crypto/openssh/mux.c =================================================================== --- crypto/openssh/mux.c +++ crypto/openssh/mux.c @@ -18,6 +18,7 @@ /* ssh session multiplexing support */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include Index: crypto/openssh/packet.c =================================================================== --- crypto/openssh/packet.c +++ crypto/openssh/packet.c @@ -38,6 +38,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include "openbsd-compat/sys-queue.h" @@ -92,6 +93,7 @@ #include "packet.h" #include "ssherr.h" #include "sshbuf.h" +#include "blacklist_client.h" #ifdef PACKET_DEBUG #define DBG(x) x @@ -1835,6 +1837,7 @@ case SSH_ERR_NO_KEX_ALG_MATCH: case SSH_ERR_NO_HOSTKEY_ALG_MATCH: if (ssh && ssh->kex && ssh->kex->failed_choice) { + BLACKLIST_NOTIFY(BLACKLIST_AUTH_FAIL, "ssh"); ssh_packet_clear_keys(ssh); logdie("Unable to negotiate with %s: %s. " "Their offer: %s", remote_id, ssh_err(r), Index: crypto/openssh/pathnames.h =================================================================== --- crypto/openssh/pathnames.h +++ crypto/openssh/pathnames.h @@ -1,4 +1,5 @@ /* $OpenBSD: pathnames.h,v 1.28 2018/02/23 15:58:37 markus Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen @@ -119,7 +120,7 @@ * Default location of askpass */ #ifndef _PATH_SSH_ASKPASS_DEFAULT -#define _PATH_SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass" +#define _PATH_SSH_ASKPASS_DEFAULT "/usr/local/bin/ssh-askpass" #endif /* Location of ssh-keysign for hostbased authentication */ @@ -134,7 +135,7 @@ /* xauth for X11 forwarding */ #ifndef _PATH_XAUTH -#define _PATH_XAUTH "/usr/X11R6/bin/xauth" +#define _PATH_XAUTH "/usr/local/bin/xauth" #endif /* UNIX domain socket for X11 server; displaynum will replace %u */ Index: crypto/openssh/readconf.h =================================================================== --- crypto/openssh/readconf.h +++ crypto/openssh/readconf.h @@ -1,4 +1,5 @@ /* $OpenBSD: readconf.h,v 1.128 2018/09/20 03:30:44 djm Exp $ */ +/* $FreeBSD$ */ /* * Author: Tatu Ylonen @@ -159,6 +160,8 @@ char *hostbased_key_types; char *pubkey_key_types; + + char *version_addendum; /* Appended to SSH banner */ char *jump_user; char *jump_host; Index: crypto/openssh/readconf.c =================================================================== --- crypto/openssh/readconf.c +++ crypto/openssh/readconf.c @@ -13,6 +13,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include @@ -67,6 +68,7 @@ #include "uidswap.h" #include "myproposal.h" #include "digest.h" +#include "version.h" /* Format of the configuration file: @@ -142,6 +144,7 @@ typedef enum { oBadOption, + oVersionAddendum, oHost, oMatch, oInclude, oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, oGatewayPorts, oExitOnForwardFailure, @@ -310,6 +313,14 @@ { "ignoreunknown", oIgnoreUnknown }, { "proxyjump", oProxyJump }, + { "hpndisabled", oDeprecated }, + { "hpnbuffersize", oDeprecated }, + { "tcprcvbufpoll", oDeprecated }, + { "tcprcvbuf", oDeprecated }, + { "noneenabled", oUnsupported }, + { "noneswitch", oUnsupported }, + { "versionaddendum", oVersionAddendum }, + { NULL, oBadOption } }; @@ -1590,6 +1601,22 @@ multistate_ptr = multistate_requesttty; goto parse_multistate; + case oVersionAddendum: + if (s == NULL) + fatal("%.200s line %d: Missing argument.", filename, + linenum); + len = strspn(s, WHITESPACE); + if (*activep && options->version_addendum == NULL) { + if (strcasecmp(s + len, "none") == 0) + options->version_addendum = xstrdup(""); + else if (strchr(s + len, '\r') != NULL) + fatal("%.200s line %d: Invalid argument", + filename, linenum); + else + options->version_addendum = xstrdup(s + len); + } + return 0; + case oIgnoreUnknown: charptr = &options->ignored_unknown; goto parse_string; @@ -1827,6 +1854,7 @@ initialize_options(Options * options) { memset(options, 'X', sizeof(*options)); + options->version_addendum = NULL; options->forward_agent = -1; options->forward_x11 = -1; options->forward_x11_trusted = -1; @@ -1999,7 +2027,7 @@ if (options->batch_mode == -1) options->batch_mode = 0; if (options->check_host_ip == -1) - options->check_host_ip = 1; + options->check_host_ip = 0; if (options->strict_host_key_checking == -1) options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK; if (options->compression == -1) @@ -2055,8 +2083,14 @@ options->rekey_limit = 0; if (options->rekey_interval == -1) options->rekey_interval = 0; +#if HAVE_LDNS if (options->verify_host_key_dns == -1) + /* automatically trust a verified SSHFP record */ + options->verify_host_key_dns = 1; +#else + if (options->verify_host_key_dns == -1) options->verify_host_key_dns = 0; +#endif if (options->server_alive_interval == -1) options->server_alive_interval = 0; if (options->server_alive_count_max == -1) @@ -2146,6 +2180,8 @@ /* options->hostname will be set in the main program if appropriate */ /* options->host_key_alias should not be set by default */ /* options->preferred_authentications will be set in ssh */ + if (options->version_addendum == NULL) + options->version_addendum = xstrdup(SSH_VERSION_FREEBSD); } struct fwdarg { Index: crypto/openssh/regress/unittests/sshkey/test_sshkey.c =================================================================== --- crypto/openssh/regress/unittests/sshkey/test_sshkey.c +++ crypto/openssh/regress/unittests/sshkey/test_sshkey.c @@ -9,6 +9,7 @@ #include #include +#include #include #ifdef HAVE_STDINT_H #include @@ -79,7 +80,7 @@ critopts = sshbuf_new(); ASSERT_PTR_NE(critopts, NULL); - put_opt(critopts, "force-command", "/usr/local/bin/nethack"); + put_opt(critopts, "force-command", _PATH_LOCALBASE "/bin/nethack"); put_opt(critopts, "source-address", "192.168.0.0/24,127.0.0.1,::1"); exts = sshbuf_new(); Index: crypto/openssh/sandbox-capsicum.c =================================================================== --- crypto/openssh/sandbox-capsicum.c +++ crypto/openssh/sandbox-capsicum.c @@ -15,6 +15,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #ifdef SANDBOX_CAPSICUM @@ -30,6 +31,7 @@ #include #include #include +#include #include "log.h" #include "monitor.h" @@ -69,6 +71,8 @@ { struct rlimit rl_zero; cap_rights_t rights; + + caph_cache_tzdata(); rl_zero.rlim_cur = rl_zero.rlim_max = 0; Index: crypto/openssh/scp.1 =================================================================== --- crypto/openssh/scp.1 +++ crypto/openssh/scp.1 @@ -18,7 +18,7 @@ .Nd secure copy (remote file copy program) .Sh SYNOPSIS .Nm scp -.Op Fl 346BCpqrv +.Op Fl 346BCpqrTv .Op Fl c Ar cipher .Op Fl F Ar ssh_config .Op Fl i Ar identity_file @@ -208,6 +208,16 @@ The program must understand .Xr ssh 1 options. +.It Fl T +Disable strict filename checking. +By default when copying files from a remote host to a local directory +.Nm +checks that the received filenames match those requested on the command-line +to prevent the remote end from sending unexpected or unwanted files. +Because of differences in how various operating systems and shells interpret +filename wildcards, these checks may cause wanted files to be rejected. +This option disables these checks at the expense of fully trusting that +the server will not send unexpected filenames. .It Fl v Verbose mode. Causes Index: crypto/openssh/scp.c =================================================================== --- crypto/openssh/scp.c +++ crypto/openssh/scp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scp.c,v 1.197 2018/06/01 04:31:48 dtucker Exp $ */ +/* $OpenBSD: scp.c,v 1.204 2019/02/10 11:15:52 djm Exp $ */ /* * scp - secure remote copy. This is basically patched BSD rcp which * uses ssh to do the data transfer (instead of using rcmd). @@ -94,6 +94,7 @@ #include #include #include +#include #include #include #include @@ -375,14 +376,14 @@ struct passwd *pwd; uid_t userid; int errs, remin, remout; -int pflag, iamremote, iamrecursive, targetshouldbedirectory; +int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory; #define CMDNEEDS 64 char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ int response(void); void rsource(char *, struct stat *); -void sink(int, char *[]); +void sink(int, char *[], const char *); void source(int, char *[]); void tolocal(int, char *[]); void toremote(int, char *[]); @@ -421,8 +422,9 @@ addargs(&args, "-oRemoteCommand=none"); addargs(&args, "-oRequestTTY=no"); - fflag = tflag = 0; - while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1) + fflag = Tflag = tflag = 0; + while ((ch = getopt(argc, argv, + "dfl:prtTvBCc:i:P:q12346S:o:F:")) != -1) { switch (ch) { /* User-visible flags. */ case '1': @@ -501,9 +503,13 @@ setmode(0, O_BINARY); #endif break; + case 'T': + Tflag = 1; + break; default: usage(); } + } argc -= optind; argv += optind; @@ -534,7 +540,7 @@ } if (tflag) { /* Receive data. */ - sink(argc, argv); + sink(argc, argv, NULL); exit(errs != 0); } if (argc < 2) @@ -620,6 +626,253 @@ return r; } +/* Appends a string to an array; returns 0 on success, -1 on alloc failure */ +static int +append(char *cp, char ***ap, size_t *np) +{ + char **tmp; + + if ((tmp = reallocarray(*ap, *np + 1, sizeof(*tmp))) == NULL) + return -1; + tmp[(*np)] = cp; + (*np)++; + *ap = tmp; + return 0; +} + +/* + * Finds the start and end of the first brace pair in the pattern. + * returns 0 on success or -1 for invalid patterns. + */ +static int +find_brace(const char *pattern, int *startp, int *endp) +{ + int i; + int in_bracket, brace_level; + + *startp = *endp = -1; + in_bracket = brace_level = 0; + for (i = 0; i < INT_MAX && *endp < 0 && pattern[i] != '\0'; i++) { + switch (pattern[i]) { + case '\\': + /* skip next character */ + if (pattern[i + 1] != '\0') + i++; + break; + case '[': + in_bracket = 1; + break; + case ']': + in_bracket = 0; + break; + case '{': + if (in_bracket) + break; + if (pattern[i + 1] == '}') { + /* Protect a single {}, for find(1), like csh */ + i++; /* skip */ + break; + } + if (*startp == -1) + *startp = i; + brace_level++; + break; + case '}': + if (in_bracket) + break; + if (*startp < 0) { + /* Unbalanced brace */ + return -1; + } + if (--brace_level <= 0) + *endp = i; + break; + } + } + /* unbalanced brackets/braces */ + if (*endp < 0 && (*startp >= 0 || in_bracket)) + return -1; + return 0; +} + +/* + * Assembles and records a successfully-expanded pattern, returns -1 on + * alloc failure. + */ +static int +emit_expansion(const char *pattern, int brace_start, int brace_end, + int sel_start, int sel_end, char ***patternsp, size_t *npatternsp) +{ + char *cp; + int o = 0, tail_len = strlen(pattern + brace_end + 1); + + if ((cp = malloc(brace_start + (sel_end - sel_start) + + tail_len + 1)) == NULL) + return -1; + + /* Pattern before initial brace */ + if (brace_start > 0) { + memcpy(cp, pattern, brace_start); + o = brace_start; + } + /* Current braced selection */ + if (sel_end - sel_start > 0) { + memcpy(cp + o, pattern + sel_start, + sel_end - sel_start); + o += sel_end - sel_start; + } + /* Remainder of pattern after closing brace */ + if (tail_len > 0) { + memcpy(cp + o, pattern + brace_end + 1, tail_len); + o += tail_len; + } + cp[o] = '\0'; + if (append(cp, patternsp, npatternsp) != 0) { + free(cp); + return -1; + } + return 0; +} + +/* + * Expand the first encountered brace in pattern, appending the expanded + * patterns it yielded to the *patternsp array. + * + * Returns 0 on success or -1 on allocation failure. + * + * Signals whether expansion was performed via *expanded and whether + * pattern was invalid via *invalid. + */ +static int +brace_expand_one(const char *pattern, char ***patternsp, size_t *npatternsp, + int *expanded, int *invalid) +{ + int i; + int in_bracket, brace_start, brace_end, brace_level; + int sel_start, sel_end; + + *invalid = *expanded = 0; + + if (find_brace(pattern, &brace_start, &brace_end) != 0) { + *invalid = 1; + return 0; + } else if (brace_start == -1) + return 0; + + in_bracket = brace_level = 0; + for (i = sel_start = brace_start + 1; i < brace_end; i++) { + switch (pattern[i]) { + case '{': + if (in_bracket) + break; + brace_level++; + break; + case '}': + if (in_bracket) + break; + brace_level--; + break; + case '[': + in_bracket = 1; + break; + case ']': + in_bracket = 0; + break; + case '\\': + if (i < brace_end - 1) + i++; /* skip */ + break; + } + if (pattern[i] == ',' || i == brace_end - 1) { + if (in_bracket || brace_level > 0) + continue; + /* End of a selection, emit an expanded pattern */ + + /* Adjust end index for last selection */ + sel_end = (i == brace_end - 1) ? brace_end : i; + if (emit_expansion(pattern, brace_start, brace_end, + sel_start, sel_end, patternsp, npatternsp) != 0) + return -1; + /* move on to the next selection */ + sel_start = i + 1; + continue; + } + } + if (in_bracket || brace_level > 0) { + *invalid = 1; + return 0; + } + /* success */ + *expanded = 1; + return 0; +} + +/* Expand braces from pattern. Returns 0 on success, -1 on failure */ +static int +brace_expand(const char *pattern, char ***patternsp, size_t *npatternsp) +{ + char *cp, *cp2, **active = NULL, **done = NULL; + size_t i, nactive = 0, ndone = 0; + int ret = -1, invalid = 0, expanded = 0; + + *patternsp = NULL; + *npatternsp = 0; + + /* Start the worklist with the original pattern */ + if ((cp = strdup(pattern)) == NULL) + return -1; + if (append(cp, &active, &nactive) != 0) { + free(cp); + return -1; + } + while (nactive > 0) { + cp = active[nactive - 1]; + nactive--; + if (brace_expand_one(cp, &active, &nactive, + &expanded, &invalid) == -1) { + free(cp); + goto fail; + } + if (invalid) + fatal("%s: invalid brace pattern \"%s\"", __func__, cp); + if (expanded) { + /* + * Current entry expanded to new entries on the + * active list; discard the progenitor pattern. + */ + free(cp); + continue; + } + /* + * Pattern did not expand; append the finename component to + * the completed list + */ + if ((cp2 = strrchr(cp, '/')) != NULL) + *cp2++ = '\0'; + else + cp2 = cp; + if (append(xstrdup(cp2), &done, &ndone) != 0) { + free(cp); + goto fail; + } + free(cp); + } + /* success */ + *patternsp = done; + *npatternsp = ndone; + done = NULL; + ndone = 0; + ret = 0; + fail: + for (i = 0; i < nactive; i++) + free(active[i]); + free(active); + for (i = 0; i < ndone; i++) + free(done[i]); + free(done); + return ret; +} + void toremote(int argc, char **argv) { @@ -791,7 +1044,7 @@ continue; } free(bp); - sink(1, argv + argc - 1); + sink(1, argv + argc - 1, src); (void) close(remin); remin = remout = -1; } @@ -967,7 +1220,7 @@ (sizeof(type) != 4 && sizeof(type) != 8)) void -sink(int argc, char **argv) +sink(int argc, char **argv, const char *src) { static BUF buffer; struct stat stb; @@ -983,6 +1236,8 @@ unsigned long long ull; int setimes, targisdir, wrerrno = 0; char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048]; + char **patterns = NULL; + size_t n, npatterns = 0; struct timeval tv[2]; #define atime tv[0] @@ -1007,10 +1262,18 @@ (void) atomicio(vwrite, remout, "", 1); if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) targisdir = 1; + if (src != NULL && !iamrecursive && !Tflag) { + /* + * Prepare to try to restrict incoming filenames to match + * the requested destination file glob. + */ + if (brace_expand(src, &patterns, &npatterns) != 0) + fatal("%s: could not expand pattern", __func__); + } for (first = 1;; first = 0) { cp = buf; if (atomicio(read, remin, cp, 1) != 1) - return; + goto done; if (*cp++ == '\n') SCREWUP("unexpected "); do { @@ -1036,7 +1299,7 @@ } if (buf[0] == 'E') { (void) atomicio(vwrite, remout, "", 1); - return; + goto done; } if (ch == '\n') *--cp = 0; @@ -1106,10 +1369,19 @@ SCREWUP("size out of range"); size = (off_t)ull; - if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) { + if (*cp == '\0' || strchr(cp, '/') != NULL || + strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0) { run_err("error: unexpected filename: %s", cp); exit(1); } + if (npatterns > 0) { + for (n = 0; n < npatterns; n++) { + if (fnmatch(patterns[n], cp, 0) == 0) + break; + } + if (n >= npatterns) + SCREWUP("filename does not match request"); + } if (targisdir) { static char *namebuf; static size_t cursize; @@ -1147,7 +1419,7 @@ goto bad; } vect[0] = xstrdup(np); - sink(1, vect); + sink(1, vect, src); if (setimes) { setimes = 0; if (utimes(vect[0], tv) < 0) @@ -1268,7 +1540,15 @@ break; } } +done: + for (n = 0; n < npatterns; n++) + free(patterns[n]); + free(patterns); + return; screwup: + for (n = 0; n < npatterns; n++) + free(patterns[n]); + free(patterns); run_err("protocol error: %s", why); exit(1); } @@ -1315,7 +1595,7 @@ usage(void) { (void) fprintf(stderr, - "usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" + "usage: scp [-346BCpqrTv] [-c cipher] [-F ssh_config] [-i identity_file]\n" " [-l limit] [-o ssh_option] [-P port] [-S program] source ... target\n"); exit(1); } Index: crypto/openssh/servconf.h =================================================================== --- crypto/openssh/servconf.h +++ crypto/openssh/servconf.h @@ -210,6 +210,7 @@ int fingerprint_hash; int expose_userauth_info; u_int64_t timing_secret; + int use_blacklist; } ServerOptions; /* Information about the incoming connection as used by Match */ Index: crypto/openssh/servconf.c =================================================================== --- crypto/openssh/servconf.c +++ crypto/openssh/servconf.c @@ -12,6 +12,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include @@ -64,6 +65,7 @@ #include "auth.h" #include "myproposal.h" #include "digest.h" +#include "version.h" static void add_listen_addr(ServerOptions *, const char *, const char *, int); @@ -180,6 +182,7 @@ options->fingerprint_hash = -1; options->disable_forwarding = -1; options->expose_userauth_info = -1; + options->use_blacklist = -1; } /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ @@ -233,12 +236,16 @@ (*lp)++; } +static const char *defaultkey = "[default]"; + void servconf_add_hostkey(const char *file, const int line, ServerOptions *options, const char *path) { char *apath = derelativise_path(path); + if (file == defaultkey && access(path, R_OK) != 0) + return; array_append(file, line, "HostKey", &options->host_key_files, &options->num_host_key_files, apath); free(apath); @@ -262,24 +269,28 @@ /* Portable-specific options */ if (options->use_pam == -1) - options->use_pam = 0; + options->use_pam = 1; /* Standard Options */ if (options->num_host_key_files == 0) { /* fill default hostkeys for protocols */ - servconf_add_hostkey("[default]", 0, options, + servconf_add_hostkey(defaultkey, 0, options, _PATH_HOST_RSA_KEY_FILE); + servconf_add_hostkey(defaultkey, 0, options, + _PATH_HOST_DSA_KEY_FILE); #ifdef OPENSSL_HAS_ECC - servconf_add_hostkey("[default]", 0, options, + servconf_add_hostkey(defaultkey, 0, options, _PATH_HOST_ECDSA_KEY_FILE); #endif - servconf_add_hostkey("[default]", 0, options, + servconf_add_hostkey(defaultkey, 0, options, _PATH_HOST_ED25519_KEY_FILE); #ifdef WITH_XMSS - servconf_add_hostkey("[default]", 0, options, + servconf_add_hostkey(defaultkey, 0, options, _PATH_HOST_XMSS_KEY_FILE); #endif /* WITH_XMSS */ } + if (options->num_host_key_files == 0) + fatal("No host key files found"); /* No certificates by default */ if (options->num_ports == 0) options->ports[options->num_ports++] = SSH_DEFAULT_PORT; @@ -292,7 +303,7 @@ if (options->login_grace_time == -1) options->login_grace_time = 120; if (options->permit_root_login == PERMIT_NOT_SET) - options->permit_root_login = PERMIT_NO_PASSWD; + options->permit_root_login = PERMIT_NO; if (options->ignore_rhosts == -1) options->ignore_rhosts = 1; if (options->ignore_user_known_hosts == -1) @@ -302,7 +313,7 @@ if (options->print_lastlog == -1) options->print_lastlog = 1; if (options->x11_forwarding == -1) - options->x11_forwarding = 0; + options->x11_forwarding = 1; if (options->x11_display_offset == -1) options->x11_display_offset = 10; if (options->x11_use_localhost == -1) @@ -342,7 +353,7 @@ if (options->gss_strict_acceptor == -1) options->gss_strict_acceptor = 1; if (options->password_authentication == -1) - options->password_authentication = 1; + options->password_authentication = 0; if (options->kbd_interactive_authentication == -1) options->kbd_interactive_authentication = 0; if (options->challenge_response_authentication == -1) @@ -378,17 +389,17 @@ if (options->max_sessions == -1) options->max_sessions = DEFAULT_SESSIONS_MAX; if (options->use_dns == -1) - options->use_dns = 0; + options->use_dns = 1; if (options->client_alive_interval == -1) options->client_alive_interval = 0; if (options->client_alive_count_max == -1) options->client_alive_count_max = 3; if (options->num_authkeys_files == 0) { - array_append("[default]", 0, "AuthorizedKeysFiles", + array_append(defaultkey, 0, "AuthorizedKeysFiles", &options->authorized_keys_files, &options->num_authkeys_files, _PATH_SSH_USER_PERMITTED_KEYS); - array_append("[default]", 0, "AuthorizedKeysFiles", + array_append(defaultkey, 0, "AuthorizedKeysFiles", &options->authorized_keys_files, &options->num_authkeys_files, _PATH_SSH_USER_PERMITTED_KEYS2); @@ -400,7 +411,7 @@ if (options->ip_qos_bulk == -1) options->ip_qos_bulk = IPTOS_DSCP_CS1; if (options->version_addendum == NULL) - options->version_addendum = xstrdup(""); + options->version_addendum = xstrdup(SSH_VERSION_FREEBSD); if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) options->fwd_opts.streamlocal_bind_mask = 0177; if (options->fwd_opts.streamlocal_bind_unlink == -1) @@ -411,6 +422,8 @@ options->disable_forwarding = 0; if (options->expose_userauth_info == -1) options->expose_userauth_info = 0; + if (options->use_blacklist == -1) + options->use_blacklist = 0; assemble_algorithms(options); @@ -497,6 +510,7 @@ sStreamLocalBindMask, sStreamLocalBindUnlink, sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, sExposeAuthInfo, sRDomain, + sUseBlacklist, sDeprecated, sIgnore, sUnsupported } ServerOpCodes; @@ -645,6 +659,12 @@ { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL }, { "rdomain", sRDomain, SSHCFG_ALL }, { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, + { "useblacklist", sUseBlacklist, SSHCFG_GLOBAL }, + { "useblocklist", sUseBlacklist, SSHCFG_GLOBAL }, /* alias */ + { "noneenabled", sUnsupported, SSHCFG_ALL }, + { "hpndisabled", sDeprecated, SSHCFG_ALL }, + { "hpnbuffersize", sDeprecated, SSHCFG_ALL }, + { "tcprcvbufpoll", sDeprecated, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; @@ -2149,6 +2169,10 @@ *charptr = xstrdup(arg); break; + case sUseBlacklist: + intptr = &options->use_blacklist; + goto parse_flag; + case sDeprecated: case sIgnore: case sUnsupported: @@ -2588,6 +2612,7 @@ dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info); + dump_cfg_fmtint(sUseBlacklist, o->use_blacklist); /* string arguments */ dump_cfg_string(sPidFile, o->pid_file); Index: crypto/openssh/session.c =================================================================== --- crypto/openssh/session.c +++ crypto/openssh/session.c @@ -34,6 +34,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include @@ -142,7 +143,7 @@ extern void destroy_sensitive_data(void); extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; -char *tun_fwd_ifnames; /* serverloop.c */ +extern char *tun_fwd_ifnames; /* serverloop.c */ /* original command from peer. */ const char *original_command = NULL; @@ -1020,6 +1021,9 @@ struct passwd *pw = s->pw; #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN) char *path = NULL; +#else + extern char **environ; + char **senv, **var, *val; #endif /* Initialize the environment. */ @@ -1041,6 +1045,9 @@ } #endif + if (getenv("TZ")) + child_set_env(&env, &envsize, "TZ", getenv("TZ")); + #ifdef GSSAPI /* Allow any GSSAPI methods that we've used to alter * the childs environment as they see fit @@ -1058,11 +1065,30 @@ child_set_env(&env, &envsize, "LOGIN", pw->pw_name); #endif child_set_env(&env, &envsize, "HOME", pw->pw_dir); + snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name); + child_set_env(&env, &envsize, "MAIL", buf); #ifdef HAVE_LOGIN_CAP - if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0) child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); - else - child_set_env(&env, &envsize, "PATH", getenv("PATH")); + child_set_env(&env, &envsize, "TERM", "su"); + /* + * Temporarily swap out our real environment with an empty one, + * let setusercontext() apply any environment variables defined + * for the user's login class, copy those variables to the child, + * free the temporary environment, and restore the original. + */ + senv = environ; + environ = xmalloc(sizeof(*environ)); + *environ = NULL; + (void)setusercontext(lc, pw, pw->pw_uid, LOGIN_SETENV|LOGIN_SETPATH); + for (var = environ; *var != NULL; ++var) { + if ((val = strchr(*var, '=')) != NULL) { + *val++ = '\0'; + child_set_env(&env, &envsize, *var, val); + } + free(*var); + } + free(environ); + environ = senv; #else /* HAVE_LOGIN_CAP */ # ifndef HAVE_CYGWIN /* @@ -1082,14 +1108,9 @@ # endif /* HAVE_CYGWIN */ #endif /* HAVE_LOGIN_CAP */ - snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name); - child_set_env(&env, &envsize, "MAIL", buf); - /* Normal systems set SHELL by default. */ child_set_env(&env, &envsize, "SHELL", shell); - if (getenv("TZ")) - child_set_env(&env, &envsize, "TZ", getenv("TZ")); if (s->term) child_set_env(&env, &envsize, "TERM", s->term); if (s->display) @@ -1295,7 +1316,8 @@ do_nologin(struct passwd *pw) { FILE *f = NULL; - char buf[1024], *nl, *def_nl = _PATH_NOLOGIN; + const char *nl; + char buf[1024], *def_nl = _PATH_NOLOGIN; struct stat sb; #ifdef HAVE_LOGIN_CAP @@ -1307,11 +1329,8 @@ return; nl = def_nl; #endif - if (stat(nl, &sb) == -1) { - if (nl != def_nl) - free(nl); + if (stat(nl, &sb) == -1) return; - } /* /etc/nologin exists. Print its contents if we can and exit. */ logit("User %.100s not allowed because %s exists", pw->pw_name, nl); @@ -1389,7 +1408,7 @@ if (platform_privileged_uidswap()) { #ifdef HAVE_LOGIN_CAP if (setusercontext(lc, pw, pw->pw_uid, - (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { + (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { perror("unable to set user context"); exit(1); } Index: crypto/openssh/sftp-common.c =================================================================== --- crypto/openssh/sftp-common.c +++ crypto/openssh/sftp-common.c @@ -25,6 +25,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include Index: crypto/openssh/ssh-agent.1 =================================================================== --- crypto/openssh/ssh-agent.1 +++ crypto/openssh/ssh-agent.1 @@ -1,4 +1,5 @@ .\" $OpenBSD: ssh-agent.1,v 1.64 2016/11/30 06:54:26 jmc Exp $ +.\" $FreeBSD$ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -43,7 +44,7 @@ .Sh SYNOPSIS .Nm ssh-agent .Op Fl c | s -.Op Fl \&Dd +.Op Fl \&Ddx .Op Fl a Ar bind_address .Op Fl E Ar fingerprint_hash .Op Fl P Ar pkcs11_whitelist @@ -148,6 +149,8 @@ .Xr ssh-add 1 overrides this value. Without this option the default maximum lifetime is forever. +.It Fl x +Exit after the last client has disconnected. .El .Pp If a command line is given, this is executed as a subprocess of the agent. Index: crypto/openssh/ssh-agent.c =================================================================== --- crypto/openssh/ssh-agent.c +++ crypto/openssh/ssh-agent.c @@ -35,6 +35,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include @@ -162,15 +163,34 @@ static int fingerprint_hash = SSH_FP_HASH_DEFAULT; +/* + * Client connection count; incremented in new_socket() and decremented in + * close_socket(). When it reaches 0, ssh-agent will exit. Since it is + * normally initialized to 1, it will never reach 0. However, if the -x + * option is specified, it is initialized to 0 in main(); in that case, + * ssh-agent will exit as soon as it has had at least one client but no + * longer has any. + */ +static int xcount = 1; + static void close_socket(SocketEntry *e) { + int last = 0; + + if (e->type == AUTH_CONNECTION) { + debug("xcount %d -> %d", xcount, xcount - 1); + if (--xcount == 0) + last = 1; + } close(e->fd); e->fd = -1; e->type = AUTH_UNUSED; sshbuf_free(e->input); sshbuf_free(e->output); sshbuf_free(e->request); + if (last) + cleanup_exit(0); } static void @@ -773,6 +793,10 @@ { u_int i, old_alloc, new_alloc; + if (type == AUTH_CONNECTION) { + debug("xcount %d -> %d", xcount, xcount + 1); + ++xcount; + } set_nonblock(fd); if (fd > max_fd) @@ -1056,7 +1080,7 @@ usage(void) { fprintf(stderr, - "usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n" + "usage: ssh-agent [-c | -s] [-Ddx] [-a bind_address] [-E fingerprint_hash]\n" " [-P pkcs11_whitelist] [-t life] [command [arg ...]]\n" " ssh-agent [-c | -s] -k\n"); exit(1); @@ -1089,6 +1113,7 @@ /* drop */ setegid(getgid()); setgid(getgid()); + setuid(geteuid()); platform_disable_tracing(0); /* strict=no */ @@ -1102,7 +1127,7 @@ __progname = ssh_get_progname(av[0]); seed_rng(); - while ((ch = getopt(ac, av, "cDdksE:a:P:t:")) != -1) { + while ((ch = getopt(ac, av, "cDdksE:a:P:t:x")) != -1) { switch (ch) { case 'E': fingerprint_hash = ssh_digest_alg_by_name(optarg); @@ -1145,6 +1170,9 @@ fprintf(stderr, "Invalid lifetime\n"); usage(); } + break; + case 'x': + xcount = 0; break; default: usage(); Index: crypto/openssh/ssh-gss.h =================================================================== --- crypto/openssh/ssh-gss.h +++ crypto/openssh/ssh-gss.h @@ -1,4 +1,5 @@ /* $OpenBSD: ssh-gss.h,v 1.14 2018/07/10 09:13:30 djm Exp $ */ +/* $FreeBSD$ */ /* * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. * Index: crypto/openssh/ssh.1 =================================================================== --- crypto/openssh/ssh.1 +++ crypto/openssh/ssh.1 @@ -34,6 +34,7 @@ .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $OpenBSD: ssh.1,v 1.399 2018/09/20 06:58:48 jmc Exp $ +.\" $FreeBSD$ .Dd $Mdocdate: September 20 2018 $ .Dt SSH 1 .Os @@ -542,6 +543,7 @@ .It User .It UserKnownHostsFile .It VerifyHostKeyDNS +.It VersionAddendum .It VisualHostKey .It XAuthLocation .El Index: crypto/openssh/ssh.c =================================================================== --- crypto/openssh/ssh.c +++ crypto/openssh/ssh.c @@ -41,6 +41,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #ifdef HAVE_SYS_STAT_H @@ -813,14 +814,14 @@ } break; case 'V': - fprintf(stderr, "%s, %s\n", - SSH_RELEASE, -#ifdef WITH_OPENSSL - SSLeay_version(SSLEAY_VERSION) -#else - "without OpenSSL" -#endif - ); + if (options.version_addendum && + *options.version_addendum != '\0') + fprintf(stderr, "%s %s, %s\n", SSH_RELEASE, + options.version_addendum, + OPENSSL_VERSION_STRING); + else + fprintf(stderr, "%s, %s\n", SSH_RELEASE, + OPENSSL_VERSION_STRING); if (opt == 'V') exit(0); break; @@ -1083,13 +1084,8 @@ !use_syslog); if (debug_flag) - logit("%s, %s", SSH_RELEASE, -#ifdef WITH_OPENSSL - SSLeay_version(SSLEAY_VERSION) -#else - "without OpenSSL" -#endif - ); + /* version_addendum is always NULL at this point */ + logit("%s, %s", SSH_RELEASE, OPENSSL_VERSION_STRING); /* Parse the configuration files */ process_config_files(host_arg, pw, 0); @@ -1277,6 +1273,23 @@ snprintf(portstr, sizeof(portstr), "%d", options.port); snprintf(uidstr, sizeof(uidstr), "%llu", (unsigned long long)pw->pw_uid); + + /* Find canonic host name. */ + if (strchr(host, '.') == 0) { + struct addrinfo hints; + struct addrinfo *ai = NULL; + int errgai; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = options.address_family; + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + errgai = getaddrinfo(host, NULL, &hints, &ai); + if (errgai == 0) { + if (ai->ai_canonname != NULL) + host = xstrdup(ai->ai_canonname); + freeaddrinfo(ai); + } + } if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL || ssh_digest_update(md, thishost, strlen(thishost)) < 0 || Index: crypto/openssh/ssh_config =================================================================== --- crypto/openssh/ssh_config +++ crypto/openssh/ssh_config @@ -1,4 +1,5 @@ # $OpenBSD: ssh_config,v 1.33 2017/05/07 23:12:57 djm Exp $ +# $FreeBSD$ # This is the ssh client system-wide configuration file. See # ssh_config(5) for more information. This file provides defaults for @@ -25,7 +26,7 @@ # GSSAPIAuthentication no # GSSAPIDelegateCredentials no # BatchMode no -# CheckHostIP yes +# CheckHostIP no # AddressFamily any # ConnectTimeout 0 # StrictHostKeyChecking ask @@ -44,3 +45,5 @@ # VisualHostKey no # ProxyCommand ssh -q -W %h:%p gateway.example.com # RekeyLimit 1G 1h +# VerifyHostKeyDNS yes +# VersionAddendum FreeBSD-20200214 Index: crypto/openssh/ssh_config.5 =================================================================== --- crypto/openssh/ssh_config.5 +++ crypto/openssh/ssh_config.5 @@ -34,6 +34,7 @@ .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $OpenBSD: ssh_config.5,v 1.286 2018/10/03 06:38:35 djm Exp $ +.\" $FreeBSD$ .Dd $Mdocdate: October 3 2018 $ .Dt SSH_CONFIG 5 .Os @@ -387,8 +388,7 @@ .Cm no . .It Cm CheckHostIP If set to -.Cm yes -(the default), +.Cm yes , .Xr ssh 1 will additionally check the host IP address in the .Pa known_hosts @@ -401,6 +401,8 @@ If the option is set to .Cm no , the check will not be executed. +The default is +.Cm no . .It Cm Ciphers Specifies the ciphers allowed and their order of preference. Multiple ciphers must be comma-separated. @@ -1643,12 +1645,23 @@ .Cm StrictHostKeyChecking option. The default is -.Cm no . +.Cm yes +if compiled with LDNS and +.Cm no +otherwise. .Pp See also .Sx VERIFYING HOST KEYS in .Xr ssh 1 . +.It Cm VersionAddendum +Specifies a string to append to the regular version string to identify +OS- or site-specific modifications. +The default is +.Dq FreeBSD-20180909 . +The value +.Cm none +may be used to disable this. .It Cm VisualHostKey If this flag is set to .Cm yes , @@ -1665,7 +1678,7 @@ .Xr xauth 1 program. The default is -.Pa /usr/X11R6/bin/xauth . +.Pa /usr/local/bin/xauth . .El .Sh PATTERNS A Index: crypto/openssh/sshconnect.c =================================================================== --- crypto/openssh/sshconnect.c +++ crypto/openssh/sshconnect.c @@ -14,6 +14,7 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include @@ -608,8 +609,10 @@ send_client_banner(int connection_out, int minor1) { /* Send our own protocol version identification. */ - xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n", - PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION); + xasprintf(&client_version_string, "SSH-%d.%d-%.100s%s%s\n", + PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION, + *options.version_addendum == '\0' ? "" : " ", + options.version_addendum); if (atomicio(vwrite, connection_out, client_version_string, strlen(client_version_string)) != strlen(client_version_string)) fatal("write: %.100s", strerror(errno)); Index: crypto/openssh/sshd.8 =================================================================== --- crypto/openssh/sshd.8 +++ crypto/openssh/sshd.8 @@ -34,6 +34,7 @@ .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $OpenBSD: sshd.8,v 1.304 2018/07/22 12:16:59 dtucker Exp $ +.\" $FreeBSD$ .Dd $Mdocdate: July 22 2018 $ .Dt SSHD 8 .Os @@ -65,7 +66,7 @@ .Nm listens for connections from clients. It is normally started at boot from -.Pa /etc/rc . +.Pa /etc/rc.d/sshd . It forks a new daemon for each incoming connection. The forked daemons handle @@ -332,8 +333,9 @@ If the login is on a tty, records login time. .It Checks -.Pa /etc/nologin ; -if it exists, prints contents and quits +.Pa /etc/nologin and +.Pa /var/run/nologin ; +if one exists, it prints the contents and quits (unless root). .It Changes to run with normal user privileges. @@ -358,7 +360,8 @@ option is set, runs it; else if .Pa /etc/ssh/sshrc exists, runs -it; otherwise runs xauth. +it; otherwise runs +.Xr xauth 1 . The .Dq rc files are given the X11 @@ -873,6 +876,12 @@ This file should be writable only by the user, and need not be readable by anyone else. .Pp +.It Pa /etc/hosts.allow +.It Pa /etc/hosts.deny +Access controls that should be enforced by tcp-wrappers are defined here. +Further details are described in +.Xr hosts_access 5 . +.Pp .It Pa /etc/hosts.equiv This file is for host-based authentication (see .Xr ssh 1 ) . @@ -975,6 +984,7 @@ .Xr ssh-keygen 1 , .Xr ssh-keyscan 1 , .Xr chroot 2 , +.Xr hosts_access 5 , .Xr login.conf 5 , .Xr moduli 5 , .Xr sshd_config 5 , Index: crypto/openssh/sshd.c =================================================================== --- crypto/openssh/sshd.c +++ crypto/openssh/sshd.c @@ -43,9 +43,11 @@ */ #include "includes.h" +__RCSID("$FreeBSD$"); #include #include +#include #include #ifdef HAVE_SYS_STAT_H # include @@ -85,6 +87,15 @@ #include #endif +#ifdef __FreeBSD__ +#include +#if defined(GSSAPI) && defined(HAVE_GSSAPI_GSSAPI_H) +#include +#elif defined(GSSAPI) && defined(HAVE_GSSAPI_H) +#include +#endif +#endif + #include "xmalloc.h" #include "ssh.h" #include "ssh2.h" @@ -122,7 +133,15 @@ #include "auth-options.h" #include "version.h" #include "ssherr.h" +#include "blacklist_client.h" +#ifdef LIBWRAP +#include +#include +int allow_severity; +int deny_severity; +#endif /* LIBWRAP */ + /* Re-exec fds */ #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) @@ -358,6 +377,8 @@ kill(0, SIGTERM); } + BLACKLIST_NOTIFY(BLACKLIST_AUTH_FAIL, "ssh"); + /* Log error and exit. */ sigdie("Timeout before authentication for %s port %d", ssh_remote_ipaddr(active_state), ssh_remote_port(active_state)); @@ -914,14 +935,13 @@ static void usage(void) { - fprintf(stderr, "%s, %s\n", + if (options.version_addendum && *options.version_addendum != '\0') + fprintf(stderr, "%s %s, %s\n", SSH_RELEASE, -#ifdef WITH_OPENSSL - SSLeay_version(SSLEAY_VERSION) -#else - "without OpenSSL" -#endif - ); + options.version_addendum, OPENSSL_VERSION_STRING); + else + fprintf(stderr, "%s, %s\n", + SSH_RELEASE, OPENSSL_VERSION_STRING); fprintf(stderr, "usage: sshd [-46DdeiqTt] [-C connection_spec] [-c host_cert_file]\n" " [-E log_file] [-f config_file] [-g login_grace_time]\n" @@ -1723,7 +1743,7 @@ debug("sshd version %s, %s", SSH_VERSION, #ifdef WITH_OPENSSL - SSLeay_version(SSLEAY_VERSION) + OpenSSL_version(OPENSSL_VERSION) #else "without OpenSSL" #endif @@ -1939,6 +1959,10 @@ /* Reinitialize the log (because of the fork above). */ log_init(__progname, options.log_level, options.log_facility, log_stderr); + /* Avoid killing the process in high-pressure swapping environments. */ + if (!inetd_flag && madvise(NULL, 0, MADV_PROTECT) != 0) + debug("madvise(): %.200s", strerror(errno)); + /* Chdir to the root directory so that the current disk can be unmounted if desired. */ if (chdir("/") == -1) @@ -2054,7 +2078,30 @@ signal(SIGCHLD, SIG_DFL); signal(SIGINT, SIG_DFL); +#ifdef __FreeBSD__ /* + * Initialize the resolver. This may not happen automatically + * before privsep chroot(). + */ + if ((_res.options & RES_INIT) == 0) { + debug("res_init()"); + res_init(); + } +#ifdef GSSAPI + /* + * Force GSS-API to parse its configuration and load any + * mechanism plugins. + */ + { + gss_OID_set mechs; + OM_uint32 minor_status; + gss_indicate_mechs(&minor_status, &mechs); + gss_release_oid_set(&minor_status, &mechs); + } +#endif +#endif + + /* * Register our connection. This turns encryption off because we do * not have a key. */ @@ -2089,10 +2136,33 @@ */ remote_ip = ssh_remote_ipaddr(ssh); +#ifdef HAVE_LOGIN_CAP + /* Also caches remote hostname for sandboxed child. */ + auth_get_canonical_hostname(ssh, options.use_dns); +#endif + #ifdef SSH_AUDIT_EVENTS audit_connection_from(remote_ip, remote_port); #endif +#ifdef LIBWRAP + allow_severity = options.log_facility|LOG_INFO; + deny_severity = options.log_facility|LOG_WARNING; + /* Check whether logins are denied from this host. */ + if (packet_connection_is_on_socket()) { + struct request_info req; + request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0); + fromhost(&req); + + if (!hosts_access(&req)) { + debug("Connection refused by tcp wrapper"); + refuse(&req); + /* NOTREACHED */ + fatal("libwrap refuse returns"); + } + } +#endif /* LIBWRAP */ + rdomain = ssh_packet_rdomain_in(ssh); /* Log the connection. */ @@ -2135,6 +2205,8 @@ if ((loginmsg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); auth_debug_reset(); + + BLACKLIST_INIT(); if (use_privsep) { if (privsep_preauth(authctxt) == 1) Index: crypto/openssh/sshd_config =================================================================== --- crypto/openssh/sshd_config +++ crypto/openssh/sshd_config @@ -1,4 +1,5 @@ # $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $ +# $FreeBSD$ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. @@ -10,6 +11,9 @@ # possible, but leave them commented. Uncommented options override the # default value. +# Note that some of FreeBSD's defaults differ from OpenBSD's, and +# FreeBSD has a few additional options. + #Port 22 #AddressFamily any #ListenAddress 0.0.0.0 @@ -29,7 +33,7 @@ # Authentication: #LoginGraceTime 2m -#PermitRootLogin prohibit-password +#PermitRootLogin no #StrictModes yes #MaxAuthTries 6 #MaxSessions 10 @@ -53,11 +57,11 @@ # Don't read the user's ~/.rhosts and ~/.shosts files #IgnoreRhosts yes -# To disable tunneled clear text passwords, change to no here! -#PasswordAuthentication yes +# Change to yes to enable built-in password authentication. +#PasswordAuthentication no #PermitEmptyPasswords no -# Change to no to disable s/key passwords +# Change to no to disable PAM authentication #ChallengeResponseAuthentication yes # Kerberos options @@ -70,7 +74,7 @@ #GSSAPIAuthentication no #GSSAPICleanupCredentials yes -# Set this to 'yes' to enable PAM authentication, account processing, +# Set this to 'no' to disable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will # be allowed through the ChallengeResponseAuthentication and # PasswordAuthentication. Depending on your PAM configuration, @@ -79,12 +83,12 @@ # If you just want the PAM account and session checks to run without # PAM authentication, then enable this but set PasswordAuthentication # and ChallengeResponseAuthentication to 'no'. -#UsePAM no +#UsePAM yes #AllowAgentForwarding yes #AllowTcpForwarding yes #GatewayPorts no -#X11Forwarding no +#X11Forwarding yes #X11DisplayOffset 10 #X11UseLocalhost yes #PermitTTY yes @@ -95,12 +99,13 @@ #Compression delayed #ClientAliveInterval 0 #ClientAliveCountMax 3 -#UseDNS no +#UseDNS yes #PidFile /var/run/sshd.pid #MaxStartups 10:30:100 #PermitTunnel no #ChrootDirectory none -#VersionAddendum none +#UseBlacklist no +#VersionAddendum FreeBSD-20200214 # no default banner path #Banner none Index: crypto/openssh/sshd_config.5 =================================================================== --- crypto/openssh/sshd_config.5 +++ crypto/openssh/sshd_config.5 @@ -34,7 +34,8 @@ .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $OpenBSD: sshd_config.5,v 1.282 2018/09/20 03:28:06 djm Exp $ -.Dd $Mdocdate: September 20 2018 $ +.\" $FreeBSD$ +.Dd $Mdocdate: July 28 2020 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -780,7 +781,7 @@ .Pp .Pa /etc/hosts.equiv and -.Pa /etc/shosts.equiv +.Pa /etc/ssh/shosts.equiv are still used. The default is .Cm yes . @@ -1193,8 +1194,10 @@ are refused if the number of unauthenticated connections reaches full (60). .It Cm PasswordAuthentication Specifies whether password authentication is allowed. +See also +.Cm UsePAM . The default is -.Cm yes . +.Cm no . .It Cm PermitEmptyPasswords When password authentication is allowed, it specifies whether the server allows login to accounts with empty password strings. @@ -1285,7 +1288,14 @@ or .Cm no . The default is -.Cm prohibit-password . +.Cm no . +Note that if +.Cm ChallengeResponseAuthentication +and +.Cm UsePAM +are both +.Cm yes , +this setting may be overridden by the PAM policy. .Pp If this option is set to .Cm prohibit-password @@ -1583,6 +1593,20 @@ .Cm TrustedUserCAKeys . For more details on certificates, see the CERTIFICATES section in .Xr ssh-keygen 1 . +.It Cm UseBlacklist +Specifies whether +.Xr sshd 8 +attempts to send authentication success and failure messages +to the +.Xr blacklistd 8 +daemon. +The default is +.Cm no . +For forward compatibility with an upcoming +.Xr blacklistd +rename, the +.Cm UseBlocklist +alias can be used instead. .It Cm UseDNS Specifies whether .Xr sshd 8 @@ -1591,8 +1615,8 @@ very same IP address. .Pp If this option is set to -.Cm no -(the default) then only addresses and not host names may be used in +.Cm no , +then only addresses and not host names may be used in .Pa ~/.ssh/authorized_keys .Cm from and @@ -1600,6 +1624,8 @@ .Cm Match .Cm Host directives. +The default is +.Dq yes . .It Cm UsePAM Enables the Pluggable Authentication Module interface. If set to @@ -1623,12 +1649,15 @@ .Xr sshd 8 as a non-root user. The default is -.Cm no . +.Cm yes . .It Cm VersionAddendum Optionally specifies additional text to append to the SSH protocol banner sent by the server upon connection. The default is -.Cm none . +.Qq FreeBSD-20180909 . +The value +.Cm none +may be used to disable this. .It Cm X11DisplayOffset Specifies the first display number available for .Xr sshd 8 Ns 's @@ -1642,7 +1671,7 @@ or .Cm no . The default is -.Cm no . +.Cm yes . .Pp When X11 forwarding is enabled, there may be additional exposure to the server and to client displays if the @@ -1698,7 +1727,7 @@ .Cm none to not use one. The default is -.Pa /usr/X11R6/bin/xauth . +.Pa /usr/local/bin/xauth . .El .Sh TIME FORMATS .Xr sshd 8 Index: crypto/openssh/umac128.c =================================================================== --- crypto/openssh/umac128.c +++ crypto/openssh/umac128.c @@ -1,4 +1,12 @@ /* $OpenBSD: umac128.c,v 1.2 2018/02/08 04:12:32 dtucker Exp $ */ +/* $FreeBSD$ */ + +/* undo ssh_namespace.h munging */ +#undef umac_new +#undef umac_update +#undef umac_final +#undef umac_delete +#undef umac_ctx #define UMAC_OUTPUT_LEN 16 #define umac_new umac128_new Index: crypto/openssh/version.h =================================================================== --- crypto/openssh/version.h +++ crypto/openssh/version.h @@ -1,6 +1,15 @@ /* $OpenBSD: version.h,v 1.83 2018/10/10 16:43:49 deraadt Exp $ */ +/* $FreeBSD$ */ #define SSH_VERSION "OpenSSH_7.9" #define SSH_PORTABLE "p1" #define SSH_RELEASE SSH_VERSION SSH_PORTABLE + +#define SSH_VERSION_FREEBSD "FreeBSD-20200214" + +#ifdef WITH_OPENSSL +#define OPENSSL_VERSION_STRING OpenSSL_version(OPENSSL_VERSION) +#else +#define OPENSSL_VERSION_STRING "without OpenSSL" +#endif