From 4890e539774ab8b57aa0ee733a5b07bdf9561af6 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 17 Sep 2007 11:57:38 +1000 Subject: - djm@cvs.openbsd.org 2007/08/23 03:22:16 [auth2-none.c sshd_config sshd_config.5] Support "Banner=none" to disable displaying of the pre-login banner; ok dtucker@ deraadt@ --- sshd_config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sshd_config') diff --git a/sshd_config b/sshd_config index 3393cec50..c7094e775 100644 --- a/sshd_config +++ b/sshd_config @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.75 2007/03/19 01:01:29 djm Exp $ +# $OpenBSD: sshd_config,v 1.76 2007/08/23 03:22:16 djm Exp $ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. @@ -104,7 +104,7 @@ Protocol 2 #PermitTunnel no # no default banner path -#Banner /some/path +#Banner none # override default of no subsystems Subsystem sftp /usr/libexec/sftp-server -- cgit v1.2.3 From d8cb1f184f9acaae02bb4d15ce1e00ffbeeeac88 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sun, 10 Feb 2008 22:40:12 +1100 Subject: - djm@cvs.openbsd.org 2008/02/08 23:24:07 [servconf.c servconf.h session.c sftp-server.c sftp.h sshd_config] [sshd_config.5] add sshd_config ChrootDirectory option to chroot(2) users to a directory and tweak internal sftp server to work with it (no special files in chroot required). ok markus@ --- Makefile.in | 6 +-- servconf.c | 12 +++++- servconf.h | 4 +- session.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++------- sftp-server-main.c | 50 +++++++++++++++++++++++++ sftp-server.c | 10 ++--- sftp.h | 6 ++- sshd_config | 3 +- sshd_config.5 | 54 ++++++++++++++++++++++++++- 9 files changed, 220 insertions(+), 31 deletions(-) create mode 100644 sftp-server-main.c (limited to 'sshd_config') diff --git a/Makefile.in b/Makefile.in index 2486edc95..1f78ea9cc 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.285 2007/06/11 04:01:42 djm Exp $ +# $Id: Makefile.in,v 1.286 2008/02/10 11:40:12 djm Exp $ # uncomment if you run a non bourne compatable shell. Ie. csh #SHELL = @SH@ @@ -156,8 +156,8 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) -sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o - $(LD) -o $@ sftp-server.o sftp-common.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) +sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o + $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) diff --git a/servconf.c b/servconf.c index 19c286c18..d38d0bfb1 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.175 2008/01/01 09:27:33 dtucker Exp $ */ +/* $OpenBSD: servconf.c,v 1.176 2008/02/08 23:24:08 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -122,6 +122,7 @@ initialize_server_options(ServerOptions *options) options->permit_tun = -1; options->num_permitted_opens = -1; options->adm_forced_command = NULL; + options->chroot_directory = NULL; } void @@ -291,7 +292,7 @@ typedef enum { sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, - sMatch, sPermitOpen, sForceCommand, + sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sDeprecated, sUnsupported } ServerOpCodes; @@ -403,6 +404,7 @@ static struct { { "match", sMatch, SSHCFG_ALL }, { "permitopen", sPermitOpen, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL }, + { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; @@ -1147,6 +1149,7 @@ parse_flag: case sBanner: charptr = &options->banner; goto parse_filename; + /* * These options can contain %X options expanded at * connect time, so that you can specify paths like: @@ -1255,6 +1258,10 @@ parse_flag: options->adm_forced_command = xstrdup(cp + len); return 0; + case sChrootDirectory: + charptr = &options->chroot_directory; + goto parse_filename; + case sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); @@ -1363,6 +1370,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) if (preauth) return; M_CP_STROPT(adm_forced_command); + M_CP_STROPT(chroot_directory); } #undef M_CP_INTOPT diff --git a/servconf.h b/servconf.h index 8a5b950ea..81a68be89 100644 --- a/servconf.h +++ b/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.80 2007/02/19 10:45:58 dtucker Exp $ */ +/* $OpenBSD: servconf.h,v 1.81 2008/02/08 23:24:08 djm Exp $ */ /* * Author: Tatu Ylonen @@ -141,6 +141,8 @@ typedef struct { int permit_tun; int num_permitted_opens; + + char *chroot_directory; } ServerOptions; void initialize_server_options(ServerOptions *); diff --git a/session.c b/session.c index a1319b384..1768c8c2f 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.225 2008/02/04 21:53:00 markus Exp $ */ +/* $OpenBSD: session.c,v 1.226 2008/02/08 23:24:07 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -84,6 +84,7 @@ #include "sshlogin.h" #include "serverloop.h" #include "canohost.h" +#include "misc.h" #include "session.h" #include "kex.h" #include "monitor_wrap.h" @@ -93,6 +94,9 @@ #include #endif +/* Magic name for internal sftp-server */ +#define INTERNAL_SFTP_NAME "internal-sftp" + /* func */ Session *session_new(void); @@ -130,7 +134,7 @@ extern Buffer loginmsg; const char *original_command = NULL; /* data */ -#define MAX_SESSIONS 10 +#define MAX_SESSIONS 20 Session sessions[MAX_SESSIONS]; #define SUBSYSTEM_NONE 0 @@ -688,13 +692,17 @@ do_exec(Session *s, const char *command) if (options.adm_forced_command) { original_command = command; command = options.adm_forced_command; - if (s->is_subsystem) + if (strcmp(INTERNAL_SFTP_NAME, command) == 0) + s->is_subsystem = SUBSYSTEM_INT_SFTP; + else if (s->is_subsystem) s->is_subsystem = SUBSYSTEM_EXT; debug("Forced command (config) '%.900s'", command); } else if (forced_command) { original_command = command; command = forced_command; - if (s->is_subsystem) + if (strcmp(INTERNAL_SFTP_NAME, command) == 0) + s->is_subsystem = SUBSYSTEM_INT_SFTP; + else if (s->is_subsystem) s->is_subsystem = SUBSYSTEM_EXT; debug("Forced command (key option) '%.900s'", command); } @@ -710,7 +718,6 @@ do_exec(Session *s, const char *command) PRIVSEP(audit_run_command(shell)); } #endif - if (s->ttyfd != -1) do_exec_pty(s, command); else @@ -1293,6 +1300,61 @@ do_nologin(struct passwd *pw) } } +/* + * Chroot into a directory after checking it for safety: all path components + * must be root-owned directories with strict permissions. + */ +static void +safely_chroot(const char *path, uid_t uid) +{ + const char *cp; + char component[MAXPATHLEN]; + struct stat st; + + if (*path != '/') + fatal("chroot path does not begin at root"); + if (strlen(path) >= sizeof(component)) + fatal("chroot path too long"); + + /* + * Descend the path, checking that each component is a + * root-owned directory with strict permissions. + */ + for (cp = path; cp != NULL;) { + if ((cp = strchr(cp, '/')) == NULL) + strlcpy(component, path, sizeof(component)); + else { + cp++; + memcpy(component, path, cp - path); + component[cp - path] = '\0'; + } + + debug3("%s: checking '%s'", __func__, component); + + if (stat(component, &st) != 0) + fatal("%s: stat(\"%s\"): %s", __func__, + component, strerror(errno)); + if (st.st_uid != 0 || (st.st_mode & 022) != 0) + fatal("bad ownership or modes for chroot " + "directory %s\"%s\"", + cp == NULL ? "" : "component ", component); + if (!S_ISDIR(st.st_mode)) + fatal("chroot path %s\"%s\" is not a directory", + cp == NULL ? "" : "component ", component); + + } + + if (chdir(path) == -1) + fatal("Unable to chdir to chroot path \"%s\": " + "%s", path, strerror(errno)); + if (chroot(path) == -1) + fatal("chroot(\"%s\"): %s", path, strerror(errno)); + if (chdir("/") == -1) + fatal("%s: chdir(/) after chroot: %s", + __func__, strerror(errno)); + verbose("Changed root directory to \"%s\"", path); +} + /* Set login name, uid, gid, and groups. */ void do_setusercontext(struct passwd *pw) @@ -1324,7 +1386,7 @@ do_setusercontext(struct passwd *pw) } # endif /* USE_PAM */ if (setusercontext(lc, pw, pw->pw_uid, - (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { + (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { perror("unable to set user context"); exit(1); } @@ -1347,13 +1409,13 @@ do_setusercontext(struct passwd *pw) exit(1); } endgrent(); -#ifdef GSSAPI +# ifdef GSSAPI if (options.gss_authentication) { temporarily_use_uid(pw); ssh_gssapi_storecreds(); restore_uid(); } -#endif +# endif # ifdef USE_PAM /* * PAM credentials may take the form of supplementary groups. @@ -1367,15 +1429,33 @@ do_setusercontext(struct passwd *pw) # endif /* USE_PAM */ # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) irix_setusercontext(pw); -# endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ +# endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ # ifdef _AIX aix_usrinfo(pw); # endif /* _AIX */ -#ifdef USE_LIBIAF +# ifdef USE_LIBIAF if (set_id(pw->pw_name) != 0) { exit(1); } -#endif /* USE_LIBIAF */ +# endif /* USE_LIBIAF */ +#endif + + if (options.chroot_directory != NULL && + strcasecmp(options.chroot_directory, "none") != 0) { + char *chroot_path; + + chroot_path = percent_expand(options.chroot_directory, + "h", pw->pw_dir, "u", pw->pw_name, (char *)NULL); + safely_chroot(chroot_path, pw->pw_uid); + free(chroot_path); + } + +#ifdef HAVE_LOGIN_CAP + if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) { + perror("unable to set user context (setuser)"); + exit(1); + } +#else /* Permanently switch to the desired uid. */ permanently_set_uid(pw); #endif @@ -1625,7 +1705,7 @@ do_child(Session *s, const char *command) argv[i] = NULL; optind = optreset = 1; __progname = argv[0]; - exit(sftp_server_main(i, argv)); + exit(sftp_server_main(i, argv, s->pw)); } if (options.use_login) { @@ -1900,7 +1980,7 @@ session_subsystem_req(Session *s) if (strcmp(subsys, options.subsystem_name[i]) == 0) { prog = options.subsystem_command[i]; cmd = options.subsystem_args[i]; - if (!strcmp("internal-sftp", prog)) { + if (!strcmp(INTERNAL_SFTP_NAME, prog)) { s->is_subsystem = SUBSYSTEM_INT_SFTP; } else if (stat(prog, &st) < 0) { error("subsystem: cannot stat %s: %s", prog, diff --git a/sftp-server-main.c b/sftp-server-main.c new file mode 100644 index 000000000..1d2ea6220 --- /dev/null +++ b/sftp-server-main.c @@ -0,0 +1,50 @@ +/* $OpenBSD: */ +/* + * Copyright (c) 2008 Markus Friedl. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include +#include +#include +#include +#include + +#include "log.h" +#include "sftp.h" +#include "misc.h" + +void +cleanup_exit(int i) +{ + sftp_server_cleanup_exit(i); +} + +int +main(int argc, char **argv) +{ + struct passwd *user_pw; + + /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ + sanitise_stdfd(); + + if ((user_pw = getpwuid(getuid())) == NULL) { + fprintf(stderr, "No user found for uid %lu", (u_long)getuid()); + return 1; + } + + return (sftp_server_main(argc, argv, user_pw)); +} diff --git a/sftp-server.c b/sftp-server.c index 373bd5eda..44ccefff8 100644 --- a/sftp-server.c +++ b/sftp-server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-server.c,v 1.76 2008/02/04 21:53:00 markus Exp $ */ +/* $OpenBSD: sftp-server.c,v 1.77 2008/02/08 23:24:07 djm Exp $ */ /* * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. * @@ -1219,7 +1219,7 @@ sftp_server_usage(void) } int -sftp_server_main(int argc, char **argv) +sftp_server_main(int argc, char **argv, struct passwd *user_pw) { fd_set *rset, *wset; int in, out, max, ch, skipargs = 0, log_stderr = 0; @@ -1277,11 +1277,7 @@ sftp_server_main(int argc, char **argv) } else client_addr = xstrdup("UNKNOWN"); - if ((pw = getpwuid(getuid())) == NULL) { - error("No user found for uid %lu", (u_long)getuid()); - sftp_server_cleanup_exit(255); - } - pw = pwcopy(pw); + pw = pwcopy(user_pw); logit("session opened for local user %s from [%s]", pw->pw_name, client_addr); diff --git a/sftp.h b/sftp.h index 12b9cc056..0835da6ed 100644 --- a/sftp.h +++ b/sftp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.h,v 1.6 2008/02/04 21:53:00 markus Exp $ */ +/* $OpenBSD: sftp.h,v 1.7 2008/02/08 23:24:07 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -91,5 +91,7 @@ #define SSH2_FX_OP_UNSUPPORTED 8 #define SSH2_FX_MAX 8 -int sftp_server_main(int, char **); +struct passwd; + +int sftp_server_main(int, char **, struct passwd *); void sftp_server_cleanup_exit(int) __dead; diff --git a/sshd_config b/sshd_config index c7094e775..ddfbbe91e 100644 --- a/sshd_config +++ b/sshd_config @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.76 2007/08/23 03:22:16 djm Exp $ +# $OpenBSD: sshd_config,v 1.77 2008/02/08 23:24:07 djm Exp $ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. @@ -102,6 +102,7 @@ Protocol 2 #PidFile /var/run/sshd.pid #MaxStartups 10 #PermitTunnel no +#ChrootDirectory none # no default banner path #Banner none diff --git a/sshd_config.5 b/sshd_config.5 index aa6720dc3..2f83bf2e1 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.79 2008/01/01 09:27:33 dtucker Exp $ -.Dd $Mdocdate: January 1 2008 $ +.\" $OpenBSD: sshd_config.5,v 1.80 2008/02/08 23:24:07 djm Exp $ +.Dd $Mdocdate: February 8 2008 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -173,6 +173,45 @@ All authentication styles from are supported. The default is .Dq yes . +.It Cm ChrootDirectory +Specifies a path to +.Xr chroot 2 +to after authentication. +This path, and all its components, must be root-owned directories that are +not writable by any other user or group. +.Pp +The path may contain the following tokens that are expanded at runtime once +the connecting user has been authenticated: %% is replaced by a literal '%', +%h is replaced by the home directory of the user being authenticated, and +%u is replaced by the username of that user. +.Pp +The +.Cm ChrootDirectory +must contain the necessary files and directories to support the +users' session. +For an interactive session this requires at least a shell, typically +.Xr sh 1 , +and basic +.Pa /dev +nodes such as +.Xr null 4 , +.Xr zero 4 , +.Xr stdin 4 , +.Xr stdout 4 , +.Xr stderr 4 , +.Xr arandom 4 +and +.Xr tty 4 +devices. +For file transfer sessions using +.Dq sftp , +no additional configuration of the environment is necessary if the +in-process sftp server is used (see +.Cm Subsystem +for details. +.Pp +The default is not to +.Xr chroot 2 . .It Cm Ciphers Specifies the ciphers allowed for protocol version 2. Multiple ciphers must be comma-separated. @@ -740,11 +779,22 @@ The default is Configures an external subsystem (e.g. file transfer daemon). Arguments should be a subsystem name and a command (with optional arguments) to execute upon subsystem request. +.Pp The command .Xr sftp-server 8 implements the .Dq sftp file transfer subsystem. +.Pp +Alternately the name +.Dq internal-sftp +implements an in-process +.Dq sftp +server. +This may simplify configurations using +.Cm ChrootDirectory +to force a different filesystem root on clients. +.Pp By default no subsystems are defined. Note that this option applies to protocol version 2 only. .It Cm SyslogFacility -- cgit v1.2.3 From ba3a6599a2c1f2547747653608c6235bb8f252e4 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 19 May 2008 14:58:22 +1000 Subject: - pyr@cvs.openbsd.org 2008/05/07 06:43:35 [sshd_config] push the sshd_config bits in, spotted by ajacoutot@ --- ChangeLog | 5 ++++- sshd_config | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'sshd_config') diff --git a/ChangeLog b/ChangeLog index 8ee0b0e55..01274c697 100644 --- a/ChangeLog +++ b/ChangeLog @@ -52,6 +52,9 @@ unless users are also denied shell access, as they can always install their own forwarders.'' ok djm@, ok and a mild frown markus@ + - pyr@cvs.openbsd.org 2008/05/07 06:43:35 + [sshd_config] + push the sshd_config bits in, spotted by ajacoutot@ 20080403 - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- @@ -3912,4 +3915,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4916 2008/05/19 04:57:41 djm Exp $ +$Id: ChangeLog,v 1.4917 2008/05/19 04:58:22 djm Exp $ diff --git a/sshd_config b/sshd_config index ddfbbe91e..1f97a9dcc 100644 --- a/sshd_config +++ b/sshd_config @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.77 2008/02/08 23:24:07 djm Exp $ +# $OpenBSD: sshd_config,v 1.78 2008/05/07 06:43:35 pyr Exp $ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. @@ -84,6 +84,7 @@ Protocol 2 # and ChallengeResponseAuthentication to 'no'. #UsePAM no +#AllowAgentForwarding yes #AllowTcpForwarding yes #GatewayPorts no #X11Forwarding no -- cgit v1.2.3 From 7207f64a23a49a719aad3083c068f50e5034ccb8 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 19 May 2008 15:34:50 +1000 Subject: - djm@cvs.openbsd.org 2008/05/08 12:21:16 [monitor.c monitor_wrap.c session.h servconf.c servconf.h session.c] [sshd_config sshd_config.5] Make the maximum number of sessions run-time controllable via a sshd_config MaxSessions knob. This is useful for disabling login/shell/subsystem access while leaving port-forwarding working (MaxSessions 0), disabling connection multiplexing (MaxSessions 1) or simply increasing the number of allows multiplexed sessions. Because some bozos are sure to configure MaxSessions in excess of the number of available file descriptors in sshd (which, at peak, might be as many as 9*MaxSessions), audit sshd to ensure that it doesn't leak fds on error paths, and make it fail gracefully on out-of-fd conditions - sending channel errors instead of than exiting with fatal(). bz#1090; MaxSessions config bits and manpage from junyer AT gmail.com ok markus@ --- ChangeLog | 17 ++- monitor.c | 4 +- monitor_wrap.c | 22 +++- servconf.c | 21 +++- servconf.h | 4 +- session.c | 382 +++++++++++++++++++++++++++++++++++++++------------------ session.h | 4 +- sshd_config | 3 +- sshd_config.5 | 7 +- 9 files changed, 326 insertions(+), 138 deletions(-) (limited to 'sshd_config') diff --git a/ChangeLog b/ChangeLog index 99dbdaf78..5ea4afcac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -77,6 +77,21 @@ shouldn't happen in compliant implementations, but it could be abused to leak memory. ok markus@ (as part of a larger diff) + - djm@cvs.openbsd.org 2008/05/08 12:21:16 + [monitor.c monitor_wrap.c session.h servconf.c servconf.h session.c] + [sshd_config sshd_config.5] + Make the maximum number of sessions run-time controllable via + a sshd_config MaxSessions knob. This is useful for disabling + login/shell/subsystem access while leaving port-forwarding working + (MaxSessions 0), disabling connection multiplexing (MaxSessions 1) or + simply increasing the number of allows multiplexed sessions. + Because some bozos are sure to configure MaxSessions in excess of the + number of available file descriptors in sshd (which, at peak, might be + as many as 9*MaxSessions), audit sshd to ensure that it doesn't leak fds + on error paths, and make it fail gracefully on out-of-fd conditions - + sending channel errors instead of than exiting with fatal(). + bz#1090; MaxSessions config bits and manpage from junyer AT gmail.com + ok markus@ 20080403 - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- @@ -3937,4 +3952,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4922 2008/05/19 05:28:35 djm Exp $ +$Id: ChangeLog,v 1.4923 2008/05/19 05:34:50 djm Exp $ diff --git a/monitor.c b/monitor.c index 04f6924b6..f872edbb5 100644 --- a/monitor.c +++ b/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.95 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: monitor.c,v 1.96 2008/05/08 12:21:16 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -1273,7 +1273,7 @@ mm_session_close(Session *s) debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); session_pty_cleanup2(s); } - s->used = 0; + session_unused(s->self); } int diff --git a/monitor_wrap.c b/monitor_wrap.c index 72fd5c83c..e65fb1279 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.61 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.62 2008/05/08 12:21:16 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -666,7 +666,20 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen) { Buffer m; char *p, *msg; - int success = 0; + int success = 0, tmp1 = -1, tmp2 = -1; + + /* Kludge: ensure there are fds free to receive the pty/tty */ + if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 || + (tmp2 = dup(pmonitor->m_recvfd)) == -1) { + error("%s: cannot allocate fds for pty", __func__); + if (tmp1 > 0) + close(tmp1); + if (tmp2 > 0) + close(tmp2); + return 0; + } + close(tmp1); + close(tmp2); buffer_init(&m); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, &m); @@ -711,8 +724,9 @@ mm_session_pty_cleanup2(Session *s) buffer_free(&m); /* closed dup'ed master */ - if (close(s->ptymaster) < 0) - error("close(s->ptymaster): %s", strerror(errno)); + if (s->ptymaster != -1 && close(s->ptymaster) < 0) + error("close(s->ptymaster/%d): %s", + s->ptymaster, strerror(errno)); /* unlink pty from session */ s->ttyfd = -1; diff --git a/servconf.c b/servconf.c index b8a968aa3..94dff1fd6 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.179 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.180 2008/05/08 12:21:16 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -114,6 +114,7 @@ initialize_server_options(ServerOptions *options) options->max_startups_rate = -1; options->max_startups = -1; options->max_authtries = -1; + options->max_sessions = -1; options->banner = NULL; options->use_dns = -1; options->client_alive_interval = -1; @@ -237,6 +238,8 @@ fill_default_server_options(ServerOptions *options) options->max_startups_begin = options->max_startups; if (options->max_authtries == -1) options->max_authtries = DEFAULT_AUTH_FAIL_MAX; + if (options->max_sessions == -1) + options->max_sessions = DEFAULT_SESSIONS_MAX; if (options->use_dns == -1) options->use_dns = 1; if (options->client_alive_interval == -1) @@ -291,7 +294,7 @@ typedef enum { sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, - sMaxStartups, sMaxAuthTries, + sMaxStartups, sMaxAuthTries, sMaxSessions, sBanner, sUseDNS, sHostbasedAuthentication, sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, @@ -395,6 +398,7 @@ static struct { { "subsystem", sSubsystem, SSHCFG_GLOBAL }, { "maxstartups", sMaxStartups, SSHCFG_GLOBAL }, { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL }, + { "maxsessions", sMaxSessions, SSHCFG_ALL }, { "banner", sBanner, SSHCFG_ALL }, { "usedns", sUseDNS, SSHCFG_GLOBAL }, { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, @@ -695,7 +699,7 @@ process_server_config_line(ServerOptions *options, char *line, case sServerKeyBits: intptr = &options->server_key_bits; -parse_int: + parse_int: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing integer value.", @@ -707,7 +711,7 @@ parse_int: case sLoginGraceTime: intptr = &options->login_grace_time; -parse_time: + parse_time: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing time value.", @@ -776,7 +780,7 @@ parse_time: fatal("%s line %d: too many host keys specified (max %d).", filename, linenum, MAX_HOSTKEYS); charptr = &options->host_key_files[*intptr]; -parse_filename: + parse_filename: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing file name.", @@ -819,7 +823,7 @@ parse_filename: case sIgnoreRhosts: intptr = &options->ignore_rhosts; -parse_flag: + parse_flag: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing yes/no argument.", @@ -1155,6 +1159,10 @@ parse_flag: intptr = &options->max_authtries; goto parse_int; + case sMaxSessions: + intptr = &options->max_sessions; + goto parse_int; + case sBanner: charptr = &options->banner; goto parse_filename; @@ -1382,6 +1390,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) M_CP_INTOPT(x11_display_offset); M_CP_INTOPT(x11_forwarding); M_CP_INTOPT(x11_use_localhost); + M_CP_INTOPT(max_sessions); M_CP_STROPT(banner); if (preauth) diff --git a/servconf.h b/servconf.h index aaf87cd18..819a028c8 100644 --- a/servconf.h +++ b/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.83 2008/05/07 05:49:37 pyr Exp $ */ +/* $OpenBSD: servconf.h,v 1.84 2008/05/08 12:21:16 djm Exp $ */ /* * Author: Tatu Ylonen @@ -35,6 +35,7 @@ #define PERMIT_YES 3 #define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ +#define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */ /* Magic name for internal sftp-server */ #define INTERNAL_SFTP_NAME "internal-sftp" @@ -123,6 +124,7 @@ typedef struct { int max_startups_rate; int max_startups; int max_authtries; + int max_sessions; char *banner; /* SSH-2 banner message */ int use_dns; int client_alive_interval; /* diff --git a/session.c b/session.c index ca04a4532..c8ed25234 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.236 2008/05/08 12:02:23 djm Exp $ */ +/* $OpenBSD: session.c,v 1.237 2008/05/08 12:21:16 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -102,9 +102,9 @@ void session_set_fds(Session *, int, int, int); void session_pty_cleanup(Session *); void session_proctitle(Session *); int session_setup_x11fwd(Session *); -void do_exec_pty(Session *, const char *); -void do_exec_no_pty(Session *, const char *); -void do_exec(Session *, const char *); +int do_exec_pty(Session *, const char *); +int do_exec_no_pty(Session *, const char *); +int do_exec(Session *, const char *); void do_login(Session *, const char *); #ifdef LOGIN_NEEDS_UTMPX static void do_pre_login(Session *s); @@ -132,8 +132,9 @@ extern Buffer loginmsg; const char *original_command = NULL; /* data */ -#define MAX_SESSIONS 20 -Session sessions[MAX_SESSIONS]; +static int sessions_first_unused = -1; +static int sessions_nalloc = 0; +static Session *sessions = NULL; #define SUBSYSTEM_NONE 0 #define SUBSYSTEM_EXT 1 @@ -167,7 +168,7 @@ static int auth_input_request_forwarding(struct passwd * pw) { Channel *nc; - int sock; + int sock = -1; struct sockaddr_un sunaddr; if (auth_sock_name != NULL) { @@ -179,43 +180,48 @@ auth_input_request_forwarding(struct passwd * pw) temporarily_use_uid(pw); /* Allocate a buffer for the socket name, and format the name. */ - auth_sock_name = xmalloc(MAXPATHLEN); - auth_sock_dir = xmalloc(MAXPATHLEN); - strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN); + auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX"); /* Create private directory for socket */ if (mkdtemp(auth_sock_dir) == NULL) { packet_send_debug("Agent forwarding disabled: " "mkdtemp() failed: %.100s", strerror(errno)); restore_uid(); - xfree(auth_sock_name); xfree(auth_sock_dir); - auth_sock_name = NULL; auth_sock_dir = NULL; - return 0; + goto authsock_err; } - snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", - auth_sock_dir, (long) getpid()); + + xasprintf(&auth_sock_name, "%s/agent.%ld", + auth_sock_dir, (long) getpid()); /* Create the socket. */ sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) - packet_disconnect("socket: %.100s", strerror(errno)); + if (sock < 0) { + error("socket: %.100s", strerror(errno)); + restore_uid(); + goto authsock_err; + } /* Bind it to the name. */ memset(&sunaddr, 0, sizeof(sunaddr)); sunaddr.sun_family = AF_UNIX; strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); - if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) - packet_disconnect("bind: %.100s", strerror(errno)); + if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) { + error("bind: %.100s", strerror(errno)); + restore_uid(); + goto authsock_err; + } /* Restore the privileged uid. */ restore_uid(); /* Start listening on the socket. */ - if (listen(sock, SSH_LISTEN_BACKLOG) < 0) - packet_disconnect("listen: %.100s", strerror(errno)); + if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { + error("listen: %.100s", strerror(errno)); + goto authsock_err; + } /* Allocate a channel for the authentication agent socket. */ nc = channel_new("auth socket", @@ -224,6 +230,19 @@ auth_input_request_forwarding(struct passwd * pw) 0, "auth socket", 1); strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); return 1; + + authsock_err: + if (auth_sock_name != NULL) + xfree(auth_sock_name); + if (auth_sock_dir != NULL) { + rmdir(auth_sock_dir); + xfree(auth_sock_dir); + } + if (sock != -1) + close(sock); + auth_sock_name = NULL; + auth_sock_dir = NULL; + return 0; } static void @@ -373,10 +392,14 @@ do_authenticated1(Authctxt *authctxt) if (type == SSH_CMSG_EXEC_CMD) { command = packet_get_string(&dlen); debug("Exec command '%.500s'", command); - do_exec(s, command); + if (do_exec(s, command) != 0) + packet_disconnect( + "command execution failed"); xfree(command); } else { - do_exec(s, NULL); + if (do_exec(s, NULL) != 0) + packet_disconnect( + "shell execution failed"); } packet_check_eom(); session_close(s); @@ -401,41 +424,84 @@ do_authenticated1(Authctxt *authctxt) } } +#define USE_PIPES /* * This is called to fork and execute a command when we have no tty. This * will call do_child from the child, and server_loop from the parent after * setting up file descriptors and such. */ -void +int do_exec_no_pty(Session *s, const char *command) { pid_t pid; #ifdef USE_PIPES int pin[2], pout[2], perr[2]; + /* Allocate pipes for communicating with the program. */ - if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) - packet_disconnect("Could not create pipes: %.100s", - strerror(errno)); -#else /* USE_PIPES */ + if (pipe(pin) < 0) { + error("%s: pipe in: %.100s", __func__, strerror(errno)); + return -1; + } + if (pipe(pout) < 0) { + error("%s: pipe out: %.100s", __func__, strerror(errno)); + close(pin[0]); + close(pin[1]); + return -1; + } + if (pipe(perr) < 0) { + error("%s: pipe err: %.100s", __func__, strerror(errno)); + close(pin[0]); + close(pin[1]); + close(pout[0]); + close(pout[1]); + return -1; + } +#else int inout[2], err[2]; + /* Uses socket pairs to communicate with the program. */ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || - socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) - packet_disconnect("Could not create socket pairs: %.100s", - strerror(errno)); -#endif /* USE_PIPES */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) { + error("%s: socketpair #1: %.100s", __func__, strerror(errno)); + return -1; + } + if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) { + error("%s: socketpair #2: %.100s", __func__, strerror(errno)); + close(inout[0]); + close(inout[1]); + return -1; + } +#endif + if (s == NULL) fatal("do_exec_no_pty: no session"); session_proctitle(s); /* Fork the child. */ - if ((pid = fork()) == 0) { + switch ((pid = fork())) { + case -1: + error("%s: fork: %.100s", __func__, strerror(errno)); +#ifdef USE_PIPES + close(pin[0]); + close(pin[1]); + close(pout[0]); + close(pout[1]); + close(perr[0]); + close(perr[1]); +#else + close(inout[0]); + close(inout[1]); + close(err[0]); + close(err[1]); +#endif + return -1; + case 0: is_child = 1; /* Child. Reinitialize the log since the pid has changed. */ - log_init(__progname, options.log_level, options.log_facility, log_stderr); + log_init(__progname, options.log_level, + options.log_facility, log_stderr); /* * Create a new session and process group since the 4.4BSD @@ -465,7 +531,7 @@ do_exec_no_pty(Session *s, const char *command) if (dup2(perr[1], 2) < 0) perror("dup2 stderr"); close(perr[1]); -#else /* USE_PIPES */ +#else /* * Redirect stdin, stdout, and stderr. Stdin and stdout will * use the same socket, as some programs (particularly rdist) @@ -475,11 +541,14 @@ do_exec_no_pty(Session *s, const char *command) close(err[1]); if (dup2(inout[0], 0) < 0) /* stdin */ perror("dup2 stdin"); - if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */ + if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */ perror("dup2 stdout"); + close(inout[0]); if (dup2(err[0], 2) < 0) /* stderr */ perror("dup2 stderr"); -#endif /* USE_PIPES */ + close(err[0]); +#endif + #ifdef _UNICOS cray_init_job(s->pw); /* set up cray jid and tmpdir */ @@ -488,7 +557,10 @@ do_exec_no_pty(Session *s, const char *command) /* Do processing for the child (exec command etc). */ do_child(s, command); /* NOTREACHED */ + default: + break; } + #ifdef _UNICOS signal(WJSIGNAL, cray_job_termination_handler); #endif /* _UNICOS */ @@ -496,11 +568,18 @@ do_exec_no_pty(Session *s, const char *command) if (is_winnt) cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); #endif - if (pid < 0) - packet_disconnect("fork failed: %.100s", strerror(errno)); + s->pid = pid; /* Set interactive/non-interactive mode. */ packet_set_interactive(s->display != NULL); + + /* + * Clear loginmsg, since it's the child's responsibility to display + * it to the user, otherwise multiple sessions may accumulate + * multiple copies of the login messages. + */ + buffer_clear(&loginmsg); + #ifdef USE_PIPES /* We are the parent. Close the child sides of the pipes. */ close(pin[0]); @@ -518,29 +597,26 @@ do_exec_no_pty(Session *s, const char *command) server_loop(pid, pin[1], pout[0], perr[0]); /* server_loop has closed pin[1], pout[0], and perr[0]. */ } -#else /* USE_PIPES */ +#else /* We are the parent. Close the child sides of the socket pairs. */ close(inout[0]); close(err[0]); - /* - * Clear loginmsg, since it's the child's responsibility to display - * it to the user, otherwise multiple sessions may accumulate - * multiple copies of the login messages. - */ - buffer_clear(&loginmsg); - /* * Enter the interactive session. Note: server_loop must be able to * handle the case that fdin and fdout are the same. */ if (compat20) { - session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]); + session_set_fds(s, inout[1], inout[1], + s->is_subsystem ? -1 : err[1]); + if (s->is_subsystem) + close(err[1]); } else { server_loop(pid, inout[1], inout[1], err[1]); /* server_loop has closed inout[1] and err[1]. */ } -#endif /* USE_PIPES */ +#endif + return 0; } /* @@ -549,7 +625,7 @@ do_exec_no_pty(Session *s, const char *command) * setting up file descriptors, controlling tty, updating wtmp, utmp, * lastlog, and other such operations. */ -void +int do_exec_pty(Session *s, const char *command) { int fdout, ptyfd, ttyfd, ptymaster; @@ -560,12 +636,46 @@ do_exec_pty(Session *s, const char *command) ptyfd = s->ptyfd; ttyfd = s->ttyfd; + /* + * Create another descriptor of the pty master side for use as the + * standard input. We could use the original descriptor, but this + * simplifies code in server_loop. The descriptor is bidirectional. + * Do this before forking (and cleanup in the child) so as to + * detect and gracefully fail out-of-fd conditions. + */ + if ((fdout = dup(ptyfd)) < 0) { + error("%s: dup #1: %s", __func__, strerror(errno)); + close(ttyfd); + close(ptyfd); + return -1; + } + /* we keep a reference to the pty master */ + if ((ptymaster = dup(ptyfd)) < 0) { + error("%s: dup #2: %s", __func__, strerror(errno)); + close(ttyfd); + close(ptyfd); + close(fdout); + return -1; + } + /* Fork the child. */ - if ((pid = fork()) == 0) { + switch ((pid = fork())) { + case -1: + error("%s: fork: %.100s", __func__, strerror(errno)); + close(fdout); + close(ptymaster); + close(ttyfd); + close(ptyfd); + return -1; + case 0: is_child = 1; + close(fdout); + close(ptymaster); + /* Child. Reinitialize the log because the pid has changed. */ - log_init(__progname, options.log_level, options.log_facility, log_stderr); + log_init(__progname, options.log_level, + options.log_facility, log_stderr); /* Close the master side of the pseudo tty. */ close(ptyfd); @@ -596,11 +706,16 @@ do_exec_pty(Session *s, const char *command) do_pre_login(s); # endif #endif - - /* Do common processing for the child, such as execing the command. */ - do_child(s, command); - /* NOTREACHED */ + /* + * Do common processing for the child, such as execing + * the command. + */ + do_child(s, command); + /* NOTREACHED */ + default: + break; } + #ifdef _UNICOS signal(WJSIGNAL, cray_job_termination_handler); #endif /* _UNICOS */ @@ -608,29 +723,14 @@ do_exec_pty(Session *s, const char *command) if (is_winnt) cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); #endif - if (pid < 0) - packet_disconnect("fork failed: %.100s", strerror(errno)); + s->pid = pid; /* Parent. Close the slave side of the pseudo tty. */ close(ttyfd); - /* - * Create another descriptor of the pty master side for use as the - * standard input. We could use the original descriptor, but this - * simplifies code in server_loop. The descriptor is bidirectional. - */ - fdout = dup(ptyfd); - if (fdout < 0) - packet_disconnect("dup #1 failed: %.100s", strerror(errno)); - - /* we keep a reference to the pty master */ - ptymaster = dup(ptyfd); - if (ptymaster < 0) - packet_disconnect("dup #2 failed: %.100s", strerror(errno)); - s->ptymaster = ptymaster; - /* Enter interactive session. */ + s->ptymaster = ptymaster; packet_set_interactive(1); if (compat20) { session_set_fds(s, ptyfd, fdout, -1); @@ -638,6 +738,7 @@ do_exec_pty(Session *s, const char *command) server_loop(pid, ptyfd, fdout, -1); /* server_loop _has_ closed ptyfd and fdout. */ } + return 0; } #ifdef LOGIN_NEEDS_UTMPX @@ -672,9 +773,11 @@ do_pre_login(Session *s) * This is called to fork and execute a command. If another command is * to be forced, execute that instead. */ -void +int do_exec(Session *s, const char *command) { + int ret; + if (options.adm_forced_command) { original_command = command; command = options.adm_forced_command; @@ -705,9 +808,9 @@ do_exec(Session *s, const char *command) } #endif if (s->ttyfd != -1) - do_exec_pty(s, command); + ret = do_exec_pty(s, command); else - do_exec_no_pty(s, command); + ret = do_exec_no_pty(s, command); original_command = NULL; @@ -717,6 +820,8 @@ do_exec(Session *s, const char *command) * multiple copies of the login messages. */ buffer_clear(&loginmsg); + + return ret; } /* administrative, login(1)-like work */ @@ -1740,43 +1845,79 @@ do_child(Session *s, const char *command) exit(1); } +void +session_unused(int id) +{ + debug3("%s: session id %d unused", __func__, id); + if (id >= options.max_sessions || + id >= sessions_nalloc) { + fatal("%s: insane session id %d (max %d nalloc %d)", + __func__, id, options.max_sessions, sessions_nalloc); + } + bzero(&sessions[id], sizeof(*sessions)); + sessions[id].self = id; + sessions[id].used = 0; + sessions[id].chanid = -1; + sessions[id].ptyfd = -1; + sessions[id].ttyfd = -1; + sessions[id].ptymaster = -1; + sessions[id].x11_chanids = NULL; + sessions[id].next_unused = sessions_first_unused; + sessions_first_unused = id; +} + Session * session_new(void) { - int i; - static int did_init = 0; - if (!did_init) { - debug("session_new: init"); - for (i = 0; i < MAX_SESSIONS; i++) { - sessions[i].used = 0; + Session *s, *tmp; + + if (sessions_first_unused == -1) { + if (sessions_nalloc >= options.max_sessions) + return NULL; + debug2("%s: allocate (allocated %d max %d)", + __func__, sessions_nalloc, options.max_sessions); + tmp = xrealloc(sessions, sessions_nalloc + 1, + sizeof(*sessions)); + if (tmp == NULL) { + error("%s: cannot allocate %d sessions", + __func__, sessions_nalloc + 1); + return NULL; } - did_init = 1; + sessions = tmp; + session_unused(sessions_nalloc++); } - for (i = 0; i < MAX_SESSIONS; i++) { - Session *s = &sessions[i]; - if (! s->used) { - memset(s, 0, sizeof(*s)); - s->chanid = -1; - s->ptyfd = -1; - s->ttyfd = -1; - s->used = 1; - s->self = i; - s->x11_chanids = NULL; - debug("session_new: session %d", i); - return s; - } + + if (sessions_first_unused >= sessions_nalloc || + sessions_first_unused < 0) { + fatal("%s: insane first_unused %d max %d nalloc %d", + __func__, sessions_first_unused, options.max_sessions, + sessions_nalloc); } - return NULL; + + s = &sessions[sessions_first_unused]; + if (s->used) { + fatal("%s: session %d already used", + __func__, sessions_first_unused); + } + sessions_first_unused = s->next_unused; + s->used = 1; + s->next_unused = -1; + debug("session_new: session %d", s->self); + + return s; } static void session_dump(void) { int i; - for (i = 0; i < MAX_SESSIONS; i++) { + for (i = 0; i < sessions_nalloc; i++) { Session *s = &sessions[i]; - debug("dump: used %d session %d %p channel %d pid %ld", + + debug("dump: used %d next_unused %d session %d %p " + "channel %d pid %ld", s->used, + s->next_unused, s->self, s, s->chanid, @@ -1806,7 +1947,7 @@ Session * session_by_tty(char *tty) { int i; - for (i = 0; i < MAX_SESSIONS; i++) { + for (i = 0; i < sessions_nalloc; i++) { Session *s = &sessions[i]; if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { debug("session_by_tty: session %d tty %s", i, tty); @@ -1822,10 +1963,11 @@ static Session * session_by_channel(int id) { int i; - for (i = 0; i < MAX_SESSIONS; i++) { + for (i = 0; i < sessions_nalloc; i++) { Session *s = &sessions[i]; if (s->used && s->chanid == id) { - debug("session_by_channel: session %d channel %d", i, id); + debug("session_by_channel: session %d channel %d", + i, id); return s; } } @@ -1839,7 +1981,7 @@ session_by_x11_channel(int id) { int i, j; - for (i = 0; i < MAX_SESSIONS; i++) { + for (i = 0; i < sessions_nalloc; i++) { Session *s = &sessions[i]; if (s->x11_chanids == NULL || !s->used) @@ -1862,7 +2004,7 @@ session_by_pid(pid_t pid) { int i; debug("session_by_pid: pid %ld", (long)pid); - for (i = 0; i < MAX_SESSIONS; i++) { + for (i = 0; i < sessions_nalloc; i++) { Session *s = &sessions[i]; if (s->used && s->pid == pid) return s; @@ -1918,7 +2060,8 @@ session_pty_req(Session *s) /* Allocate a pty and open it. */ debug("Allocating pty."); - if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { + if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, + sizeof(s->tty)))) { if (s->term) xfree(s->term); s->term = NULL; @@ -1971,8 +2114,7 @@ session_subsystem_req(Session *s) s->is_subsystem = SUBSYSTEM_EXT; } debug("subsystem: exec() %s", cmd); - do_exec(s, cmd); - success = 1; + success = do_exec(s, cmd) == 0; break; } } @@ -2015,19 +2157,19 @@ static int session_shell_req(Session *s) { packet_check_eom(); - do_exec(s, NULL); - return 1; + return do_exec(s, NULL) == 0; } static int session_exec_req(Session *s) { - u_int len; + u_int len, success; + char *command = packet_get_string(&len); packet_check_eom(); - do_exec(s, command); + success = do_exec(s, command) == 0; xfree(command); - return 1; + return success; } static int @@ -2037,8 +2179,7 @@ session_break_req(Session *s) packet_get_int(); /* ignored */ packet_check_eom(); - if (s->ttyfd == -1 || - tcsendbreak(s->ttyfd, 0) < 0) + if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0) return 0; return 1; } @@ -2185,8 +2326,9 @@ session_pty_cleanup2(Session *s) * the pty cleanup, so that another process doesn't get this pty * while we're still cleaning up. */ - if (close(s->ptymaster) < 0) - error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); + if (s->ptymaster != -1 && close(s->ptymaster) < 0) + error("close(s->ptymaster/%d): %s", + s->ptymaster, strerror(errno)); /* unlink pty from session */ s->ttyfd = -1; @@ -2346,7 +2488,6 @@ session_close(Session *s) xfree(s->auth_data); if (s->auth_proto) xfree(s->auth_proto); - s->used = 0; if (s->env != NULL) { for (i = 0; i < s->num_env; i++) { xfree(s->env[i].name); @@ -2355,6 +2496,7 @@ session_close(Session *s) xfree(s->env); } session_proctitle(s); + session_unused(s->self); } void @@ -2418,7 +2560,7 @@ void session_destroy_all(void (*closefunc)(Session *)) { int i; - for (i = 0; i < MAX_SESSIONS; i++) { + for (i = 0; i < sessions_nalloc; i++) { Session *s = &sessions[i]; if (s->used) { if (closefunc != NULL) @@ -2437,7 +2579,7 @@ session_tty_list(void) char *cp; buf[0] = '\0'; - for (i = 0; i < MAX_SESSIONS; i++) { + for (i = 0; i < sessions_nalloc; i++) { Session *s = &sessions[i]; if (s->used && s->ttyfd != -1) { diff --git a/session.h b/session.h index ee9338e4f..cbb8e3a32 100644 --- a/session.h +++ b/session.h @@ -1,4 +1,4 @@ -/* $OpenBSD: session.h,v 1.29 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: session.h,v 1.30 2008/05/08 12:21:16 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -31,6 +31,7 @@ typedef struct Session Session; struct Session { int used; int self; + int next_unused; struct passwd *pw; Authctxt *authctxt; pid_t pid; @@ -65,6 +66,7 @@ void do_authenticated(Authctxt *); void do_cleanup(Authctxt *); int session_open(Authctxt *, int); +void session_unused(int); int session_input_channel_req(Channel *, const char *); void session_close_by_pid(pid_t, int); void session_close_by_channel(int, void *); diff --git a/sshd_config b/sshd_config index 1f97a9dcc..c5ee7c8a4 100644 --- a/sshd_config +++ b/sshd_config @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.78 2008/05/07 06:43:35 pyr Exp $ +# $OpenBSD: sshd_config,v 1.79 2008/05/08 12:21:16 djm Exp $ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. @@ -41,6 +41,7 @@ Protocol 2 #PermitRootLogin yes #StrictModes yes #MaxAuthTries 6 +#MaxSessions 10 #RSAAuthentication yes #PubkeyAuthentication yes diff --git a/sshd_config.5 b/sshd_config.5 index 99b5621e7..0d8c140bf 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.89 2008/05/07 08:00:14 jmc Exp $ -.Dd $Mdocdate: May 19 2008 $ +.\" $OpenBSD: sshd_config.5,v 1.90 2008/05/08 12:21:16 djm Exp $ +.Dd $Mdocdate: May 8 2008 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -594,6 +594,9 @@ connection. Once the number of failures reaches half this value, additional failures are logged. The default is 6. +.It Cm MaxSessions +Specifies the maximum number of open sessions permitted per network connection. +The default is 10. .It Cm MaxStartups Specifies the maximum number of concurrent unauthenticated connections to the SSH daemon. -- cgit v1.2.3 From 7499b0cca021f14c615cbfef170aba3e24cf8d4d Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Wed, 2 Jul 2008 22:35:43 +1000 Subject: - djm@cvs.openbsd.org 2008/07/02 02:24:18 [sshd_config sshd_config.5 sshd.8 servconf.c] increase default size of ssh protocol 1 ephemeral key from 768 to 1024 bits; prodded by & ok dtucker@ ok deraadt@ --- ChangeLog | 6 +++++- servconf.c | 4 ++-- sshd.8 | 6 +++--- sshd_config | 4 ++-- sshd_config.5 | 6 +++--- 5 files changed, 15 insertions(+), 11 deletions(-) (limited to 'sshd_config') diff --git a/ChangeLog b/ChangeLog index fadf27a7d..9e7326d85 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,10 @@ - stevesk@cvs.openbsd.org 2008/07/01 23:12:47 [PROTOCOL.agent] fix some typos; ok djm@ + - djm@cvs.openbsd.org 2008/07/02 02:24:18 + [sshd_config sshd_config.5 sshd.8 servconf.c] + increase default size of ssh protocol 1 ephemeral key from 768 to 1024 + bits; prodded by & ok dtucker@ ok deraadt@ 20080630 - (djm) OpenBSD CVS Sync @@ -4507,4 +4511,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.5045 2008/07/02 12:35:00 dtucker Exp $ +$Id: ChangeLog,v 1.5046 2008/07/02 12:35:43 dtucker Exp $ diff --git a/servconf.c b/servconf.c index 67e7d7db3..9d9c9508e 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.184 2008/06/15 16:58:40 dtucker Exp $ */ +/* $OpenBSD: servconf.c,v 1.185 2008/07/02 02:24:18 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -158,7 +158,7 @@ fill_default_server_options(ServerOptions *options) if (options->pid_file == NULL) options->pid_file = _PATH_SSH_DAEMON_PID_FILE; if (options->server_key_bits == -1) - options->server_key_bits = 768; + options->server_key_bits = 1024; if (options->login_grace_time == -1) options->login_grace_time = 120; if (options->key_regeneration_time == -1) diff --git a/sshd.8 b/sshd.8 index fdbe7abfa..c4c4181fc 100644 --- a/sshd.8 +++ b/sshd.8 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd.8,v 1.245 2008/06/11 07:30:37 jmc Exp $ -.Dd $Mdocdate: June 11 2008 $ +.\" $OpenBSD: sshd.8,v 1.246 2008/07/02 02:24:18 djm Exp $ +.Dd $Mdocdate: July 2 2008 $ .Dt SSHD 8 .Os .Sh NAME @@ -100,7 +100,7 @@ Forces to use IPv6 addresses only. .It Fl b Ar bits Specifies the number of bits in the ephemeral protocol version 1 -server key (default 768). +server key (default 1024). .It Fl C Ar connection_spec Specify the connection parameters to use for the .Fl T diff --git a/sshd_config b/sshd_config index c5ee7c8a4..1b53a0efb 100644 --- a/sshd_config +++ b/sshd_config @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.79 2008/05/08 12:21:16 djm Exp $ +# $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. @@ -28,7 +28,7 @@ Protocol 2 # Lifetime and size of ephemeral version 1 server key #KeyRegenerationInterval 1h -#ServerKeyBits 768 +#ServerKeyBits 1024 # Logging # obsoletes QuietMode and FascistLogging diff --git a/sshd_config.5 b/sshd_config.5 index 0d41edf98..7255b1c22 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.95 2008/06/15 16:58:40 dtucker Exp $ -.Dd $Mdocdate: June 15 2008 $ +.\" $OpenBSD: sshd_config.5,v 1.96 2008/07/02 02:24:18 djm Exp $ +.Dd $Mdocdate: July 2 2008 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -811,7 +811,7 @@ The default is This option applies to protocol version 1 only. .It Cm ServerKeyBits Defines the number of bits in the ephemeral protocol version 1 server key. -The minimum value is 512, and the default is 768. +The minimum value is 512, and the default is 1024. .It Cm StrictModes Specifies whether .Xr sshd 8 -- cgit v1.2.3