diff --git a/ChangeLog b/ChangeLog index 9ca8e55ff..b367ddc40 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,38 @@ Martin Petrak - (djm) Include sys/types.h when including netinet/in.h in configure tests. Patch from Jun-ichiro itojun Hagino + - OpenBSD CVS updates: + - deraadt@cvs.openbsd.org 2000/06/17 09:58:46 + [channels.c] + everyone says "nix it" (remove protocol 2 debugging message) + - markus@cvs.openbsd.org 2000/06/17 13:24:34 + [sshconnect.c] + allow extended server banners + - markus@cvs.openbsd.org 2000/06/17 14:30:10 + [sshconnect.c] + missing atomicio, typo + - jakob@cvs.openbsd.org 2000/06/17 16:52:34 + [servconf.c servconf.h session.c sshd.8 sshd_config] + add support for ssh v2 subsystems. ok markus@. + - deraadt@cvs.openbsd.org 2000/06/17 18:57:48 + [readconf.c servconf.c] + include = in WHITESPACE; markus ok + - markus@cvs.openbsd.org 2000/06/17 19:09:10 + [auth2.c] + implement bug compatibility with ssh-2.0.13 pubkey, server side + - markus@cvs.openbsd.org 2000/06/17 21:00:28 + [compat.c] + initial support for ssh.com's 2.2.0 + - markus@cvs.openbsd.org 2000/06/17 21:16:09 + [scp.c] + typo + - markus@cvs.openbsd.org 2000/06/17 22:05:02 + [auth-rsa.c auth2.c serverloop.c session.c auth-options.c auth-options.h] + split auth-rsa option parsing into auth-options + add options support to authorized_keys2 + - markus@cvs.openbsd.org 2000/06/17 22:42:54 + [session.c] + typo 20000613 - (djm) Fixes from Andrew McGill : diff --git a/Makefile.in b/Makefile.in index 0a2a2cfc7..4037bfe8a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -40,7 +40,7 @@ LIBOPENBSD_COMPAT_OBJS=bsd-base64.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o b SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o clientloop.o -SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o +SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0 diff --git a/auth-options.c b/auth-options.c new file mode 100644 index 000000000..7ebbb7661 --- /dev/null +++ b/auth-options.c @@ -0,0 +1,208 @@ +#include "includes.h" +RCSID("$Id: auth-options.c,v 1.1 2000/06/18 04:50:44 djm Exp $"); + +#include "ssh.h" +#include "packet.h" +#include "xmalloc.h" +#include "match.h" + +/* Flags set authorized_keys flags */ +int no_port_forwarding_flag = 0; +int no_agent_forwarding_flag = 0; +int no_x11_forwarding_flag = 0; +int no_pty_flag = 0; + +/* "command=" option. */ +char *forced_command = NULL; + +/* "environment=" options. */ +struct envstring *custom_environment = NULL; + +/* return 1 if access is granted, 0 if not. side effect: sets key option flags */ +int +auth_parse_options(struct passwd *pw, char *options, unsigned long linenum) +{ + const char *cp; + if (!options) + return 1; + while (*options && *options != ' ' && *options != '\t') { + cp = "no-port-forwarding"; + if (strncmp(options, cp, strlen(cp)) == 0) { + packet_send_debug("Port forwarding disabled."); + no_port_forwarding_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "no-agent-forwarding"; + if (strncmp(options, cp, strlen(cp)) == 0) { + packet_send_debug("Agent forwarding disabled."); + no_agent_forwarding_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "no-X11-forwarding"; + if (strncmp(options, cp, strlen(cp)) == 0) { + packet_send_debug("X11 forwarding disabled."); + no_x11_forwarding_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "no-pty"; + if (strncmp(options, cp, strlen(cp)) == 0) { + packet_send_debug("Pty allocation disabled."); + no_pty_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "command=\""; + if (strncmp(options, cp, strlen(cp)) == 0) { + int i; + options += strlen(cp); + forced_command = xmalloc(strlen(options) + 1); + i = 0; + while (*options) { + if (*options == '"') + break; + if (*options == '\\' && options[1] == '"') { + options += 2; + forced_command[i++] = '"'; + continue; + } + forced_command[i++] = *options++; + } + if (!*options) { + debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + continue; + } + forced_command[i] = 0; + packet_send_debug("Forced command: %.900s", forced_command); + options++; + goto next_option; + } + cp = "environment=\""; + if (strncmp(options, cp, strlen(cp)) == 0) { + int i; + char *s; + struct envstring *new_envstring; + options += strlen(cp); + s = xmalloc(strlen(options) + 1); + i = 0; + while (*options) { + if (*options == '"') + break; + if (*options == '\\' && options[1] == '"') { + options += 2; + s[i++] = '"'; + continue; + } + s[i++] = *options++; + } + if (!*options) { + debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + continue; + } + s[i] = 0; + packet_send_debug("Adding to environment: %.900s", s); + debug("Adding to environment: %.900s", s); + options++; + new_envstring = xmalloc(sizeof(struct envstring)); + new_envstring->s = s; + new_envstring->next = custom_environment; + custom_environment = new_envstring; + goto next_option; + } + cp = "from=\""; + if (strncmp(options, cp, strlen(cp)) == 0) { + int mname, mip; + char *patterns = xmalloc(strlen(options) + 1); + int i; + options += strlen(cp); + i = 0; + while (*options) { + if (*options == '"') + break; + if (*options == '\\' && options[1] == '"') { + options += 2; + patterns[i++] = '"'; + continue; + } + patterns[i++] = *options++; + } + if (!*options) { + debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + continue; + } + patterns[i] = 0; + options++; + /* + * Deny access if we get a negative + * match for the hostname or the ip + * or if we get not match at all + */ + mname = match_hostname(get_canonical_hostname(), + patterns, strlen(patterns)); + mip = match_hostname(get_remote_ipaddr(), + patterns, strlen(patterns)); + xfree(patterns); + if (mname == -1 || mip == -1 || + (mname != 1 && mip != 1)) { + log("Authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).", + pw->pw_name, get_canonical_hostname(), + get_remote_ipaddr()); + packet_send_debug("Your host '%.200s' is not permitted to use this key for login.", + get_canonical_hostname()); + /* key invalid for this host, reset flags */ + no_agent_forwarding_flag = 0; + no_port_forwarding_flag = 0; + no_pty_flag = 0; + no_x11_forwarding_flag = 0; + while (custom_environment) { + struct envstring *ce = custom_environment; + custom_environment = ce->next; + xfree(ce->s); + xfree(ce); + } + if (forced_command) { + xfree(forced_command); + forced_command = NULL; + } + /* deny access */ + return 0; + } + /* Host name matches. */ + goto next_option; + } +next_option: + /* + * Skip the comma, and move to the next option + * (or break out if there are no more). + */ + if (!*options) + fatal("Bugs in auth-options.c option processing."); + if (*options == ' ' || *options == '\t') + break; /* End of options. */ + if (*options != ',') + goto bad_option; + options++; + /* Process the next option. */ + } + /* grant access */ + return 1; + +bad_option: + log("Bad options in %.100s file, line %lu: %.50s", + SSH_USER_PERMITTED_KEYS, linenum, options); + packet_send_debug("Bad options in %.100s file, line %lu: %.50s", + SSH_USER_PERMITTED_KEYS, linenum, options); + /* deny access */ + return 0; +} diff --git a/auth-options.h b/auth-options.h new file mode 100644 index 000000000..1ecdb9df4 --- /dev/null +++ b/auth-options.h @@ -0,0 +1,13 @@ +#ifndef AUTH_OPTIONS_H +#define AUTH_OPTIONS_H +/* Flags that may be set in authorized_keys options. */ +extern int no_port_forwarding_flag; +extern int no_agent_forwarding_flag; +extern int no_x11_forwarding_flag; +extern int no_pty_flag; +extern char *forced_command; +extern struct envstring *custom_environment; + +/* return 1 if access is granted, 0 if not. side effect: sets key option flags */ +int auth_parse_options(struct passwd *pw, char *options, unsigned long linenum); +#endif diff --git a/auth-rsa.c b/auth-rsa.c index f01c5c920..546e1d845 100644 --- a/auth-rsa.c +++ b/auth-rsa.c @@ -16,7 +16,7 @@ */ #include "includes.h" -RCSID("$Id: auth-rsa.c,v 1.20 2000/06/07 09:55:44 djm Exp $"); +RCSID("$Id: auth-rsa.c,v 1.21 2000/06/18 04:50:44 djm Exp $"); #include "rsa.h" #include "packet.h" @@ -26,18 +26,11 @@ RCSID("$Id: auth-rsa.c,v 1.20 2000/06/07 09:55:44 djm Exp $"); #include "uidswap.h" #include "match.h" #include "servconf.h" +#include "auth-options.h" #include #include -/* Flags that may be set in authorized_keys options. */ -extern int no_port_forwarding_flag; -extern int no_agent_forwarding_flag; -extern int no_x11_forwarding_flag; -extern int no_pty_flag; -extern char *forced_command; -extern struct envstring *custom_environment; - /* * Session identifier that is used to bind key exchange and authentication * responses to a particular session. @@ -133,7 +126,6 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) unsigned long linenum = 0; struct stat st; RSA *pk; - int mname, mip; /* Temporarily use the user's uid. */ temporarily_use_uid(pw->pw_uid); @@ -269,195 +261,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) * authenticated. Note that we have not yet processed the * options; this will be reset if the options cause the * authentication to be rejected. - */ - authenticated = 1; - - /* RSA part of authentication was accepted. Now process the options. */ - if (options) { - while (*options && *options != ' ' && *options != '\t') { - cp = "no-port-forwarding"; - if (strncmp(options, cp, strlen(cp)) == 0) { - packet_send_debug("Port forwarding disabled."); - no_port_forwarding_flag = 1; - options += strlen(cp); - goto next_option; - } - cp = "no-agent-forwarding"; - if (strncmp(options, cp, strlen(cp)) == 0) { - packet_send_debug("Agent forwarding disabled."); - no_agent_forwarding_flag = 1; - options += strlen(cp); - goto next_option; - } - cp = "no-X11-forwarding"; - if (strncmp(options, cp, strlen(cp)) == 0) { - packet_send_debug("X11 forwarding disabled."); - no_x11_forwarding_flag = 1; - options += strlen(cp); - goto next_option; - } - cp = "no-pty"; - if (strncmp(options, cp, strlen(cp)) == 0) { - packet_send_debug("Pty allocation disabled."); - no_pty_flag = 1; - options += strlen(cp); - goto next_option; - } - cp = "command=\""; - if (strncmp(options, cp, strlen(cp)) == 0) { - int i; - options += strlen(cp); - forced_command = xmalloc(strlen(options) + 1); - i = 0; - while (*options) { - if (*options == '"') - break; - if (*options == '\\' && options[1] == '"') { - options += 2; - forced_command[i++] = '"'; - continue; - } - forced_command[i++] = *options++; - } - if (!*options) { - debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - continue; - } - forced_command[i] = 0; - packet_send_debug("Forced command: %.900s", forced_command); - options++; - goto next_option; - } - cp = "environment=\""; - if (strncmp(options, cp, strlen(cp)) == 0) { - int i; - char *s; - struct envstring *new_envstring; - options += strlen(cp); - s = xmalloc(strlen(options) + 1); - i = 0; - while (*options) { - if (*options == '"') - break; - if (*options == '\\' && options[1] == '"') { - options += 2; - s[i++] = '"'; - continue; - } - s[i++] = *options++; - } - if (!*options) { - debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - continue; - } - s[i] = 0; - packet_send_debug("Adding to environment: %.900s", s); - debug("Adding to environment: %.900s", s); - options++; - new_envstring = xmalloc(sizeof(struct envstring)); - new_envstring->s = s; - new_envstring->next = custom_environment; - custom_environment = new_envstring; - goto next_option; - } - cp = "from=\""; - if (strncmp(options, cp, strlen(cp)) == 0) { - char *patterns = xmalloc(strlen(options) + 1); - int i; - options += strlen(cp); - i = 0; - while (*options) { - if (*options == '"') - break; - if (*options == '\\' && options[1] == '"') { - options += 2; - patterns[i++] = '"'; - continue; - } - patterns[i++] = *options++; - } - if (!*options) { - debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - continue; - } - patterns[i] = 0; - options++; - /* - * Deny access if we get a negative - * match for the hostname or the ip - * or if we get not match at all - */ - mname = match_hostname(get_canonical_hostname(), - patterns, strlen(patterns)); - mip = match_hostname(get_remote_ipaddr(), - patterns, strlen(patterns)); - if (mname == -1 || mip == -1 || - (mname != 1 && mip != 1)) { - log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).", - pw->pw_name, get_canonical_hostname(), - get_remote_ipaddr()); - packet_send_debug("Your host '%.200s' is not permitted to use this key for login.", - get_canonical_hostname()); - xfree(patterns); - /* key invalid for this host, reset flags */ - authenticated = 0; - no_agent_forwarding_flag = 0; - no_port_forwarding_flag = 0; - no_pty_flag = 0; - no_x11_forwarding_flag = 0; - while (custom_environment) { - struct envstring *ce = custom_environment; - custom_environment = ce->next; - xfree(ce->s); - xfree(ce); - } - if (forced_command) { - xfree(forced_command); - forced_command = NULL; - } - break; - } - xfree(patterns); - /* Host name matches. */ - goto next_option; - } - bad_option: - log("Bad options in %.100s file, line %lu: %.50s", - SSH_USER_PERMITTED_KEYS, linenum, options); - packet_send_debug("Bad options in %.100s file, line %lu: %.50s", - SSH_USER_PERMITTED_KEYS, linenum, options); - authenticated = 0; - break; - - next_option: - /* - * Skip the comma, and move to the next option - * (or break out if there are no more). - */ - if (!*options) - fatal("Bugs in auth-rsa.c option processing."); - if (*options == ' ' || *options == '\t') - break; /* End of options. */ - if (*options != ',') - goto bad_option; - options++; - /* Process the next option. */ - continue; - } - } - /* * Break out of the loop if authentication was successful; * otherwise continue searching. */ + authenticated = auth_parse_options(pw, options, linenum); if (authenticated) break; } diff --git a/auth2.c b/auth2.c index 46c8c1f81..c7dcf1953 100644 --- a/auth2.c +++ b/auth2.c @@ -27,7 +27,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: auth2.c,v 1.8 2000/05/08 17:42:24 markus Exp $"); +RCSID("$OpenBSD: auth2.c,v 1.10 2000/06/18 04:05:02 markus Exp $"); #include #include @@ -54,6 +54,7 @@ RCSID("$OpenBSD: auth2.c,v 1.8 2000/05/08 17:42:24 markus Exp $"); #include "dsa.h" #include "uidswap.h" +#include "auth-options.h" /* import */ extern ServerOptions options; @@ -69,7 +70,7 @@ void protocol_error(int type, int plen); /* auth */ int ssh2_auth_none(struct passwd *pw); int ssh2_auth_password(struct passwd *pw); -int ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen); +int ssh2_auth_pubkey(struct passwd *pw, char *service); /* helper */ struct passwd* auth_set_user(char *u, char *s); @@ -150,17 +151,14 @@ input_userauth_request(int type, int plen) { static void (*authlog) (const char *fmt,...) = verbose; static int attempt = 0; - unsigned int len, rlen; + unsigned int len; int authenticated = 0; - char *raw, *user, *service, *method, *authmsg = NULL; + char *user, *service, *method, *authmsg = NULL; struct passwd *pw; #ifdef WITH_AIXAUTHENTICATE extern char *aixloginmsg; #endif /* WITH_AIXAUTHENTICATE */ - raw = packet_get_raw(&rlen); - if (plen != rlen) - fatal("plen != rlen"); user = packet_get_string(&len); service = packet_get_string(&len); method = packet_get_string(&len); @@ -180,7 +178,7 @@ input_userauth_request(int type, int plen) } else if (strcmp(method, "password") == 0) { authenticated = ssh2_auth_password(pw); } else if (strcmp(method, "publickey") == 0) { - authenticated = ssh2_auth_pubkey(pw, raw, rlen); + authenticated = ssh2_auth_pubkey(pw, service); } } if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) { @@ -277,7 +275,7 @@ ssh2_auth_password(struct passwd *pw) return authenticated; } int -ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen) +ssh2_auth_pubkey(struct passwd *pw, char *service) { Buffer b; Key *key; @@ -290,10 +288,6 @@ ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen) debug("pubkey auth disabled"); return 0; } - if (datafellows & SSH_BUG_PUBKEYAUTH) { - log("bug compatibility with ssh-2.0.13 pubkey not implemented"); - return 0; - } have_sig = packet_get_char(); pkalg = packet_get_string(&alen); if (strcmp(pkalg, KEX_DSS) != 0) { @@ -309,10 +303,18 @@ ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen) packet_done(); buffer_init(&b); buffer_append(&b, session_id2, session_id2_len); + + /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); - if (slen + 4 > rlen) - fatal("bad rlen/slen"); - buffer_append(&b, raw, rlen - slen - 4); + buffer_put_cstring(&b, pw->pw_name); + buffer_put_cstring(&b, + datafellows & SSH_BUG_PUBKEYAUTH ? + "ssh-userauth" : + service); + buffer_put_cstring(&b, "publickey"); + buffer_put_char(&b, have_sig); + buffer_put_cstring(&b, KEX_DSS); + buffer_put_string(&b, pkblob, blen); #ifdef DEBUG_DSS buffer_dump(&b); #endif @@ -471,17 +473,36 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) found = key_new(KEY_DSA); while (fgets(line, sizeof(line), f)) { - char *cp; + char *cp, *options = NULL; linenum++; /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; + bits = key_read(found, &cp); - if (bits == 0) - continue; - if (key_equal(found, key)) { + if (bits == 0) { + /* no key? check if there are options for this key */ + int quoted = 0; + options = cp; + for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { + if (*cp == '\\' && cp[1] == '"') + cp++; /* Skip both */ + else if (*cp == '"') + quoted = !quoted; + } + /* Skip remaining whitespace. */ + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + bits = key_read(found, &cp); + if (bits == 0) { + /* still no key? advance to next line*/ + continue; + } + } + if (key_equal(found, key) && + auth_parse_options(pw, options, linenum) == 1) { found_key = 1; debug("matching key found: file %s, line %ld", file, linenum); diff --git a/channels.c b/channels.c index bfa025ad7..9da9db474 100644 --- a/channels.c +++ b/channels.c @@ -17,7 +17,7 @@ */ #include "includes.h" -RCSID("$Id: channels.c,v 1.32 2000/06/07 09:55:44 djm Exp $"); +RCSID("$Id: channels.c,v 1.33 2000/06/18 04:50:44 djm Exp $"); #include "ssh.h" #include "packet.h" @@ -932,7 +932,6 @@ channel_output_poll() packet_send(); buffer_consume(&c->input, len); c->remote_window -= len; - debug("channel %d: send data len %d", c->self, len); } } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) { if (compat13) diff --git a/compat.c b/compat.c index 967e0b6b8..8e77fd799 100644 --- a/compat.c +++ b/compat.c @@ -28,7 +28,7 @@ */ #include "includes.h" -RCSID("$Id: compat.c,v 1.11 2000/05/30 03:44:53 damien Exp $"); +RCSID("$Id: compat.c,v 1.12 2000/06/18 04:50:44 djm Exp $"); #include "ssh.h" #include "packet.h" @@ -61,6 +61,7 @@ compat_datafellows(const char *version) char *version; int bugs; } check[] = { + {"2.2.0", SSH_BUG_HMAC}, {"2.1.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC}, {"2.0.1", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD}, {NULL, 0} diff --git a/readconf.c b/readconf.c index 2751db345..c6d6f67db 100644 --- a/readconf.c +++ b/readconf.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$Id: readconf.c,v 1.16 2000/06/07 09:55:44 djm Exp $"); +RCSID("$Id: readconf.c,v 1.17 2000/06/18 04:50:44 djm Exp $"); #include "ssh.h" #include "cipher.h" @@ -165,7 +165,7 @@ static struct { }; /* Characters considered whitespace in strtok calls. */ -#define WHITESPACE " \t\r\n" +#define WHITESPACE " \t\r\n=" /* diff --git a/scp.c b/scp.c index 19f0fd944..773a4f59f 100644 --- a/scp.c +++ b/scp.c @@ -45,7 +45,7 @@ */ #include "includes.h" -RCSID("$Id: scp.c,v 1.23 2000/05/17 12:53:35 damien Exp $"); +RCSID("$Id: scp.c,v 1.24 2000/06/18 04:50:44 djm Exp $"); #include "ssh.h" #include "xmalloc.h" @@ -155,7 +155,6 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) args[i++] = "-4"; if (IPv6) args[i++] = "-6"; - args[i++] = "-oFallBackToRsh no"; if (verbose_mode) args[i++] = "-v"; if (compress_flag) @@ -1008,7 +1007,7 @@ run_err(const char *fmt,...) * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: scp.c,v 1.23 2000/05/17 12:53:35 damien Exp $ + * $Id: scp.c,v 1.24 2000/06/18 04:50:44 djm Exp $ */ char * diff --git a/servconf.c b/servconf.c index 6583829e7..0e323231d 100644 --- a/servconf.c +++ b/servconf.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$Id: servconf.c,v 1.18 2000/06/07 09:55:44 djm Exp $"); +RCSID("$Id: servconf.c,v 1.19 2000/06/18 04:50:44 djm Exp $"); #include "ssh.h" #include "servconf.h" @@ -75,6 +75,7 @@ initialize_server_options(ServerOptions *options) options->ciphers = NULL; options->protocol = SSH_PROTO_UNKNOWN; options->gateway_ports = -1; + options->num_subsystems = 0; } void @@ -160,7 +161,7 @@ fill_default_server_options(ServerOptions *options) options->gateway_ports = 0; } -#define WHITESPACE " \t\r\n" +#define WHITESPACE " \t\r\n=" /* Keyword tokens. */ typedef enum { @@ -182,7 +183,7 @@ typedef enum { sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile, - sGatewayPorts, sDSAAuthentication, sXAuthLocation + sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem } ServerOpCodes; /* Textual representation of the tokens. */ @@ -237,6 +238,7 @@ static struct { { "ciphers", sCiphers }, { "protocol", sProtocol }, { "gatewayports", sGatewayPorts }, + { "subsystem", sSubsystem }, { NULL, 0 } }; @@ -302,6 +304,7 @@ read_server_config(ServerOptions *options, const char *filename) int linenum, *intptr, value; int bad_options = 0; ServerOpCodes opcode; + int i; f = fopen(filename, "r"); if (!f) { @@ -613,6 +616,28 @@ parse_flag: *intptr = value; break; + case sSubsystem: + if(options->num_subsystems >= MAX_SUBSYSTEMS) { + fatal("%s line %d: too many subsystems defined.", + filename, linenum); + } + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%s line %d: Missing subsystem name.", + filename, linenum); + for (i = 0; i < options->num_subsystems; i++) + if(strcmp(cp, options->subsystem_name[i]) == 0) + fatal("%s line %d: Subsystem '%s' already defined.", + filename, linenum, cp); + options->subsystem_name[options->num_subsystems] = xstrdup(cp); + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%s line %d: Missing subsystem command.", + filename, linenum); + options->subsystem_command[options->num_subsystems] = xstrdup(cp); + options->num_subsystems++; + break; + default: fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n", filename, linenum, cp, opcode); diff --git a/servconf.h b/servconf.h index 5c6212f2d..6c647c2ed 100644 --- a/servconf.h +++ b/servconf.h @@ -13,7 +13,7 @@ * */ -/* RCSID("$Id: servconf.h,v 1.12 2000/06/07 09:55:44 djm Exp $"); */ +/* RCSID("$Id: servconf.h,v 1.13 2000/06/18 04:50:44 djm Exp $"); */ #ifndef SERVCONF_H #define SERVCONF_H @@ -24,6 +24,7 @@ #define MAX_DENY_USERS 256 /* Max # users on deny list. */ #define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */ #define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ +#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ typedef struct { unsigned int num_ports; @@ -94,6 +95,10 @@ typedef struct { char *allow_groups[MAX_ALLOW_GROUPS]; unsigned int num_deny_groups; char *deny_groups[MAX_DENY_GROUPS]; + + unsigned int num_subsystems; + char *subsystem_name[MAX_SUBSYSTEMS]; + char *subsystem_command[MAX_SUBSYSTEMS]; } ServerOptions; /* * Initializes the server options to special values that indicate that they diff --git a/serverloop.c b/serverloop.c index b08fcfd92..311a285c3 100644 --- a/serverloop.c +++ b/serverloop.c @@ -23,6 +23,7 @@ #include "ssh2.h" #include "session.h" #include "dispatch.h" +#include "auth-options.h" static Buffer stdin_buffer; /* Buffer for stdin data. */ static Buffer stdout_buffer; /* Buffer for stdout data. */ @@ -719,7 +720,13 @@ input_direct_tcpip(void) debug("open direct-tcpip: from %s port %d to %s port %d", originator, originator_port, target, target_port); + /* XXX check permission */ + if (! no_port_forwarding_flag) { + xfree(target); + xfree(originator); + return -1; + } sock = channel_connect_to(target, target_port); xfree(target); xfree(originator); diff --git a/session.c b/session.c index 6c1c32767..64e240b73 100644 --- a/session.c +++ b/session.c @@ -8,7 +8,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.17 2000/06/05 19:53:40 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.20 2000/06/18 04:42:54 markus Exp $"); #include "xmalloc.h" #include "ssh.h" @@ -26,6 +26,7 @@ RCSID("$OpenBSD: session.c,v 1.17 2000/06/05 19:53:40 markus Exp $"); #include "bufaux.h" #include "ssh2.h" #include "auth.h" +#include "auth-options.h" /* types */ @@ -88,18 +89,6 @@ Session sessions[MAX_SESSIONS]; char *aixloginmsg; #endif /* WITH_AIXAUTHENTICATE */ -/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */ -int no_port_forwarding_flag = 0; -int no_agent_forwarding_flag = 0; -int no_x11_forwarding_flag = 0; -int no_pty_flag = 0; - -/* RSA authentication "command=" option. */ -char *forced_command = NULL; - -/* RSA authentication "environment=" options. */ -struct envstring *custom_environment = NULL; - /* * Remove local Xauthority file. */ @@ -1260,6 +1249,8 @@ session_pty_req(Session *s) unsigned int len; char *term_modes; /* encoded terminal modes */ + if (no_pty_flag) + return 0; if (s->ttyfd != -1) return 0; s->term = packet_get_string(&len); @@ -1307,10 +1298,22 @@ session_subsystem_req(Session *s) unsigned int len; int success = 0; char *subsys = packet_get_string(&len); + int i; packet_done(); log("subsystem request for %s", subsys); + for (i = 0; i < options.num_subsystems; i++) { + if(strcmp(subsys, options.subsystem_name[i]) == 0) { + debug("subsystem: exec() %s", options.subsystem_command[i]); + do_exec_no_pty(s, options.subsystem_command[i], s->pw); + success = 1; + } + } + + if (!success) + log("subsystem request for %s failed, subsystem not found", subsys); + xfree(subsys); return success; } @@ -1318,6 +1321,10 @@ session_subsystem_req(Session *s) int session_x11_req(Session *s) { + if (!no_port_forwarding_flag) { + debug("X11 forwarding disabled in user configuration file."); + return 0; + } if (!options.x11_forwarding) { debug("X11 forwarding disabled in server configuration file."); return 0; @@ -1364,6 +1371,41 @@ session_x11_req(Session *s) return 1; } +int +session_shell_req(Session *s) +{ + /* if forced_command == NULL, the shell is execed */ + char *shell = forced_command; + packet_done(); + s->extended = 1; + if (s->ttyfd == -1) + do_exec_no_pty(s, shell, s->pw); + else + do_exec_pty(s, shell, s->pw); + return 1; +} + +int +session_exec_req(Session *s) +{ + unsigned int len; + char *command = packet_get_string(&len); + packet_done(); + if (forced_command) { + xfree(command); + command = forced_command; + debug("Forced command '%.500s'", forced_command); + } + s->extended = 1; + if (s->ttyfd == -1) + do_exec_no_pty(s, command, s->pw); + else + do_exec_pty(s, command, s->pw); + if (forced_command == NULL) + xfree(command); + return 1; +} + void session_input_channel_req(int id, void *arg) { @@ -1393,23 +1435,9 @@ session_input_channel_req(int id, void *arg) */ if (c->type == SSH_CHANNEL_LARVAL) { if (strcmp(rtype, "shell") == 0) { - packet_done(); - s->extended = 1; - if (s->ttyfd == -1) - do_exec_no_pty(s, NULL, s->pw); - else - do_exec_pty(s, NULL, s->pw); - success = 1; + success = session_shell_req(s); } else if (strcmp(rtype, "exec") == 0) { - char *command = packet_get_string(&len); - packet_done(); - s->extended = 1; - if (s->ttyfd == -1) - do_exec_no_pty(s, command, s->pw); - else - do_exec_pty(s, command, s->pw); - xfree(command); - success = 1; + success = session_exec_req(s); } else if (strcmp(rtype, "pty-req") == 0) { success = session_pty_req(s); } else if (strcmp(rtype, "x11-req") == 0) { diff --git a/sshconnect.c b/sshconnect.c index bf00159b3..835ca7b3a 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -8,7 +8,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect.c,v 1.74 2000/05/17 16:57:02 markus Exp $"); +RCSID("$OpenBSD: sshconnect.c,v 1.76 2000/06/17 20:30:10 markus Exp $"); #include #include @@ -314,23 +314,28 @@ ssh_exchange_identification() int connection_out = packet_get_connection_out(); /* Read other side\'s version identification. */ - for (i = 0; i < sizeof(buf) - 1; i++) { - int len = read(connection_in, &buf[i], 1); - if (len < 0) - fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); - if (len != 1) - fatal("ssh_exchange_identification: Connection closed by remote host"); - if (buf[i] == '\r') { - buf[i] = '\n'; - buf[i + 1] = 0; - continue; /**XXX wait for \n */ + for (;;) { + for (i = 0; i < sizeof(buf) - 1; i++) { + int len = atomicio(read, connection_in, &buf[i], 1); + if (len < 0) + fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); + if (len != 1) + fatal("ssh_exchange_identification: Connection closed by remote host"); + if (buf[i] == '\r') { + buf[i] = '\n'; + buf[i + 1] = 0; + continue; /**XXX wait for \n */ + } + if (buf[i] == '\n') { + buf[i + 1] = 0; + break; + } } - if (buf[i] == '\n') { - buf[i + 1] = 0; + buf[sizeof(buf) - 1] = 0; + if (strncmp(buf, "SSH-", 4) == 0) break; - } + debug("ssh_exchange_identification: %s", buf); } - buf[sizeof(buf) - 1] = 0; server_version_string = xstrdup(buf); /* diff --git a/sshd.8 b/sshd.8 index deb72e447..b71378c1e 100644 --- a/sshd.8 +++ b/sshd.8 @@ -9,7 +9,7 @@ .\" .\" Created: Sat Apr 22 21:55:14 1995 ylo .\" -.\" $Id: sshd.8,v 1.23 2000/06/07 09:55:44 djm Exp $ +.\" $Id: sshd.8,v 1.24 2000/06/18 04:50:45 djm Exp $ .\" .Dd September 25, 1999 .Dt SSHD 8 @@ -543,6 +543,11 @@ This is normally desirable because novices sometimes accidentally leave their directory or files world-writable. The default is .Dq yes . +.It Cm Subsystem +Configures an external subsystem (e.g. file transfer daemon). +Arguments should be a subsystem name and a command to execute upon subsystem request. +By default no subsystems are defined. +Note that this option applies to protocol version 2 only. .It Cm SyslogFacility Gives the facility code that is used when logging messages from .Nm sshd . diff --git a/sshd_config b/sshd_config index 52436ac36..d3bab840a 100644 --- a/sshd_config +++ b/sshd_config @@ -49,3 +49,5 @@ PermitEmptyPasswords no CheckMail no UseLogin no + +#Subsystem sftp /usr/local/sbin/sftpd