From 1d1ffb876ba515d13d488979fc6c752c1289aebb Mon Sep 17 00:00:00 2001 From: damien Date: Sun, 7 May 2000 02:03:14 +0000 Subject: [PATCH] - Remove references to SSLeay. - Big OpenBSD CVS update - markus@cvs.openbsd.org [clientloop.c] - typo [session.c] - update proctitle on pty alloc/dealloc, e.g. w/ windows client [session.c] - update proctitle for proto 1, too [channels.h nchan.c serverloop.c session.c sshd.c] - use c-style comments - deraadt@cvs.openbsd.org [scp.c] - more atomicio - markus@cvs.openbsd.org [channels.c] - set O_NONBLOCK [ssh.1] - update AUTHOR [readconf.c ssh-keygen.c ssh.h] - default DSA key file ~/.ssh/id_dsa [clientloop.c] - typo, rm verbose debug - deraadt@cvs.openbsd.org [ssh-keygen.1] - document DSA use of ssh-keygen [sshd.8] - a start at describing what i understand of the DSA side [ssh-keygen.1] - document -X and -x [ssh-keygen.c] - simplify usage - markus@cvs.openbsd.org [sshd.8] - there is no rhosts_dsa [ssh-keygen.1] - document -y, update -X,-x [nchan.c] - fix close for non-open ssh1 channels [servconf.c servconf.h ssh.h sshd.8 sshd.c ] - s/DsaKey/HostDSAKey/, document option [sshconnect2.c] - respect number_of_password_prompts [channels.c channels.h servconf.c servconf.h session.c sshd.8] - GatewayPorts for sshd, ok deraadt@ [ssh-add.1 ssh-agent.1 ssh.1] - more doc on: DSA, id_dsa, known_hosts2, authorized_keys2 [ssh.1] - more info on proto 2 [sshd.8] - sync AUTHOR w/ ssh.1 [key.c key.h sshconnect.c] - print key type when talking about host keys [packet.c] - clear padding in ssh2 [dsa.c key.c radix.c ssh.h sshconnect1.c uuencode.c uuencode.h] - replace broken uuencode w/ libc b64_ntop [auth2.c] - log failure before sending the reply [key.c radix.c uuencode.c] - remote trailing comments before calling __b64_pton [auth2.c readconf.c readconf.h servconf.c servconf.h ssh.1] [sshconnect2.c sshd.8] - add DSAAuthetication option to ssh/sshd, document SSH2 in sshd.8 - Bring in b64_ntop and b64_pton from OpenBSD libc (bsd-base64.[ch]) --- ChangeLog | 67 +++++++++++ Makefile.in | 2 +- auth2.c | 48 +++++--- bsd-base64.c | 315 ++++++++++++++++++++++++++++++++++++++++++++++++++ bsd-base64.h | 19 +++ channels.c | 31 ++++- channels.h | 4 +- clientloop.c | 4 +- configure.in | 4 +- dsa.c | 2 +- includes.h | 1 + key.c | 25 +++- key.h | 1 + nchan.c | 21 +++- packet.c | 11 +- radix.c | 7 +- readconf.c | 16 ++- readconf.h | 1 + scp.c | 16 +-- servconf.c | 31 +++-- servconf.h | 4 +- serverloop.c | 2 +- session.c | 43 ++++++- ssh-add.1 | 4 +- ssh-agent.1 | 4 +- ssh-keygen.1 | 61 +++++++++- ssh-keygen.c | 6 +- ssh.1 | 158 +++++++++++++++++++------ ssh.h | 5 +- sshconnect.c | 34 +++--- sshconnect1.c | 6 +- sshconnect2.c | 8 +- sshd.8 | 102 ++++++++++++++-- sshd.c | 9 +- uuencode.c | 110 ++++-------------- uuencode.h | 4 +- 36 files changed, 943 insertions(+), 243 deletions(-) create mode 100644 bsd-base64.c create mode 100644 bsd-base64.h diff --git a/ChangeLog b/ChangeLog index d7143d5d..c6e3548a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,70 @@ +20000507 + - Remove references to SSLeay. + - Big OpenBSD CVS update + - markus@cvs.openbsd.org + [clientloop.c] + - typo + [session.c] + - update proctitle on pty alloc/dealloc, e.g. w/ windows client + [session.c] + - update proctitle for proto 1, too + [channels.h nchan.c serverloop.c session.c sshd.c] + - use c-style comments + - deraadt@cvs.openbsd.org + [scp.c] + - more atomicio + - markus@cvs.openbsd.org + [channels.c] + - set O_NONBLOCK + [ssh.1] + - update AUTHOR + [readconf.c ssh-keygen.c ssh.h] + - default DSA key file ~/.ssh/id_dsa + [clientloop.c] + - typo, rm verbose debug + - deraadt@cvs.openbsd.org + [ssh-keygen.1] + - document DSA use of ssh-keygen + [sshd.8] + - a start at describing what i understand of the DSA side + [ssh-keygen.1] + - document -X and -x + [ssh-keygen.c] + - simplify usage + - markus@cvs.openbsd.org + [sshd.8] + - there is no rhosts_dsa + [ssh-keygen.1] + - document -y, update -X,-x + [nchan.c] + - fix close for non-open ssh1 channels + [servconf.c servconf.h ssh.h sshd.8 sshd.c ] + - s/DsaKey/HostDSAKey/, document option + [sshconnect2.c] + - respect number_of_password_prompts + [channels.c channels.h servconf.c servconf.h session.c sshd.8] + - GatewayPorts for sshd, ok deraadt@ + [ssh-add.1 ssh-agent.1 ssh.1] + - more doc on: DSA, id_dsa, known_hosts2, authorized_keys2 + [ssh.1] + - more info on proto 2 + [sshd.8] + - sync AUTHOR w/ ssh.1 + [key.c key.h sshconnect.c] + - print key type when talking about host keys + [packet.c] + - clear padding in ssh2 + [dsa.c key.c radix.c ssh.h sshconnect1.c uuencode.c uuencode.h] + - replace broken uuencode w/ libc b64_ntop + [auth2.c] + - log failure before sending the reply + [key.c radix.c uuencode.c] + - remote trailing comments before calling __b64_pton + [auth2.c readconf.c readconf.h servconf.c servconf.h ssh.1] + [sshconnect2.c sshd.8] + - add DSAAuthetication option to ssh/sshd, document SSH2 in sshd.8 + - Bring in b64_ntop and b64_pton from OpenBSD libc (bsd-base64.[ch]) + 20000502 - OpenBSD CVS update [channels.c] diff --git a/Makefile.in b/Makefile.in index 646201c0..de2fbd26 100644 --- a/Makefile.in +++ b/Makefile.in @@ -33,7 +33,7 @@ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS) -LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o +LIBOBJS= atomicio.o authfd.o authfile.o bsd-base64.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o clientloop.o diff --git a/auth2.c b/auth2.c index e77358a3..3d997f45 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.5 2000/05/01 23:13:39 djm Exp $"); +RCSID("$OpenBSD: auth2.c,v 1.7 2000/05/06 17:45:36 markus Exp $"); #include #include @@ -188,9 +188,29 @@ input_userauth_request(int type, int plen) authenticated = 0; #endif /* USE_PAM */ - /* XXX todo: check if multiple auth methods are needed */ + /* Raise logging level */ + if (authenticated == 1 || + attempt == AUTH_FAIL_LOG || + strcmp(method, "password") == 0) + authlog = log; + + /* Log before sending the reply */ if (authenticated == 1) { authmsg = "Accepted"; + } else if (authenticated == 0) { + authmsg = "Failed"; + } else { + authmsg = "Postponed"; + } + authlog("%s %s for %.200s from %.200s port %d ssh2", + authmsg, + method, + pw && pw->pw_uid == 0 ? "ROOT" : user, + get_remote_ipaddr(), + get_remote_port()); + + /* XXX todo: check if multiple auth methods are needed */ + if (authenticated == 1) { /* turn off userauth */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error); packet_start(SSH2_MSG_USERAUTH_SUCCESS); @@ -199,27 +219,12 @@ input_userauth_request(int type, int plen) /* now we can break out */ userauth_success = 1; } else if (authenticated == 0) { - authmsg = "Failed"; packet_start(SSH2_MSG_USERAUTH_FAILURE); packet_put_cstring("publickey,password"); /* XXX dynamic */ packet_put_char(0); /* XXX partial success, unused */ packet_send(); packet_write_wait(); - } else { - authmsg = "Postponed"; } - /* Raise logging level */ - if (authenticated == 1|| - attempt == AUTH_FAIL_LOG || - strcmp(method, "password") == 0) - authlog = log; - - authlog("%s %s for %.200s from %.200s port %d ssh2", - authmsg, - method, - pw && pw->pw_uid == 0 ? "ROOT" : user, - get_remote_ipaddr(), - get_remote_port()); xfree(service); xfree(user); @@ -269,7 +274,7 @@ ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen) int have_sig; int authenticated = 0; - if (options.rsa_authentication == 0) { + if (options.dsa_authentication == 0) { debug("pubkey auth disabled"); return 0; } @@ -306,6 +311,13 @@ ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen) debug("test key..."); /* test whether pkalg/pkblob are acceptable */ /* XXX fake reply and always send PK_OK ? */ + /* + * XXX this allows testing whether a user is allowed + * to login: if you happen to have a valid pubkey this + * message is sent. the message is NEVER sent at all + * if a user is not allowed to login. is this an + * issue? -markus + */ if (user_dsa_key_allowed(pw, key)) { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); diff --git a/bsd-base64.c b/bsd-base64.c new file mode 100644 index 00000000..57a95736 --- /dev/null +++ b/bsd-base64.c @@ -0,0 +1,315 @@ +/* $OpenBSD: base64.c,v 1.3 1997/11/08 20:46:55 deraadt Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM 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. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "config.h" + +#ifndef HAVE_B64_NTOP + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define Assert(Cond) if (!(Cond)) abort() + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int +b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) +{ + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + Assert(output[3] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +b64_pton(char const *src, u_char *target, size_t targsize) +{ + int tarindex, state, ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} + +#endif /* HAVE_B64_NTOP */ diff --git a/bsd-base64.h b/bsd-base64.h new file mode 100644 index 00000000..c5dace7c --- /dev/null +++ b/bsd-base64.h @@ -0,0 +1,19 @@ +#ifndef _BSD_BASE64_H +#define _BSD_BASE64_H + +#include "config.h" + +#ifndef HAVE___B64_NTOP +# ifdef HAVE_B64_NTOP +# define __b64_ntop b64_ntop +# define __b64_pton b64_pton +# else /* !HAVE_B64_NTOP */ + +int b64_ntop(u_char const *src, size_t srclength, char *target, + size_t targsize); +int b64_pton(char const *src, u_char *target, size_t targsize); + +# endif /* HAVE_B64_NTOP */ +#endif /* HAVE___B64_NTOP */ + +#endif /* _BSD_BINRESVPORT_H */ diff --git a/channels.c b/channels.c index abeb4955..7cd36adf 100644 --- a/channels.c +++ b/channels.c @@ -147,8 +147,25 @@ channel_lookup(int id) return c; } +void +set_nonblock(int fd) +{ + int val; + val = fcntl(fd, F_GETFL, 0); + if (val < 0) { + error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); + return; + } + if (val & O_NONBLOCK) + return; + debug("fd %d setting O_NONBLOCK", fd); + val |= O_NONBLOCK; + if (fcntl(fd, F_SETFL, val) == -1) + error("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd, strerror(errno)); +} + /* - * register filedescriptors for a channel, used when allocating a channel or + * Register filedescriptors for a channel, used when allocating a channel or * when the channel consumer/producer is ready, e.g. shell exec'd */ @@ -163,11 +180,18 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, int extusage) if (efd > channel_max_fd_value) channel_max_fd_value = efd; /* XXX set close-on-exec -markus */ + c->rfd = rfd; c->wfd = wfd; c->sock = (rfd == wfd) ? rfd : -1; c->efd = efd; c->extended_usage = extusage; + if (rfd != -1) + set_nonblock(rfd); + if (wfd != -1) + set_nonblock(wfd); + if (efd != -1) + set_nonblock(efd); } /* @@ -1532,7 +1556,7 @@ channel_request_remote_forwarding(u_short listen_port, const char *host_to_conne */ void -channel_input_port_forward_request(int is_root) +channel_input_port_forward_request(int is_root, int gateway_ports) { u_short port, host_port; char *hostname; @@ -1551,9 +1575,8 @@ channel_input_port_forward_request(int is_root) port); /* * Initiate forwarding, - * bind port to localhost only (gateway ports == 0). */ - channel_request_local_forwarding(port, hostname, host_port, 0); + channel_request_local_forwarding(port, hostname, host_port, gateway_ports); /* Free the argument string. */ xfree(hostname); diff --git a/channels.h b/channels.h index 24fedb32..613c0107 100644 --- a/channels.h +++ b/channels.h @@ -56,7 +56,7 @@ typedef struct Channel { char *ctype; /* type */ - // callback + /* callback */ channel_callback_fn *cb_fn; void *cb_arg; int cb_event; @@ -175,7 +175,7 @@ void channel_permit_all_opens(void); * listening for the port, and sends back a success reply (or disconnect * message if there was an error). This never returns if there was an error. */ -void channel_input_port_forward_request(int is_root); +void channel_input_port_forward_request(int is_root, int gateway_ports); /* * Creates a port for X11 connections, and starts listening for it. Returns diff --git a/clientloop.c b/clientloop.c index ab671378..86972f67 100644 --- a/clientloop.c +++ b/clientloop.c @@ -971,7 +971,7 @@ client_input_channel_open(int type, int plen) rwindow = packet_get_int(); rmaxpack = packet_get_int(); - log("server_input_open: ctype %s rchan %d win %d max %d", + debug("client_input_channel_open: ctype %s rchan %d win %d max %d", ctype, rchan, rwindow, rmaxpack); if (strcmp(ctype, "x11") == 0) { @@ -1077,7 +1077,7 @@ client_input_channel_req(int id, void *arg) rtype = packet_get_string(&len); reply = packet_get_char(); - debug("session_input_channel_req: rtype %s reply %d", rtype, reply); + debug("client_input_channel_req: rtype %s reply %d", rtype, reply); c = channel_lookup(id); if (c == NULL) diff --git a/configure.in b/configure.in index be2a63df..1b099c6b 100644 --- a/configure.in +++ b/configure.in @@ -132,7 +132,7 @@ fi AC_CHECK_HEADERS(bstring.h endian.h lastlog.h login.h maillock.h netdb.h netgroup.h netinet/in_systm.h paths.h poll.h pty.h shadow.h security/pam_appl.h sys/bitypes.h sys/bsdtty.h sys/cdefs.h sys/poll.h sys/select.h sys/stropts.h sys/sysmacros.h sys/time.h sys/ttcompat.h stddef.h util.h utmp.h utmpx.h) # Checks for library functions. -AC_CHECK_FUNCS(arc4random bindresvport_af clock freeaddrinfo gai_strerror getaddrinfo getnameinfo getrusage innetgr md5_crypt mkdtemp openpty rresvport_af setenv seteuid setlogin setproctitle setreuid snprintf strlcat strlcpy updwtmpx vsnprintf vhangup _getpty) +AC_CHECK_FUNCS(arc4random b64_ntop bindresvport_af clock freeaddrinfo gai_strerror getaddrinfo getnameinfo getrusage innetgr md5_crypt mkdtemp openpty rresvport_af setenv seteuid setlogin setproctitle setreuid snprintf strlcat strlcpy updwtmpx vsnprintf vhangup _getpty __b64_ntop) AC_CHECK_FUNC(login, [AC_DEFINE(HAVE_LOGIN)], @@ -196,7 +196,7 @@ saved_CFLAGS="$CFLAGS" if test "x$prefix" != "xNONE" ; then tryssldir="$tryssldir $prefix" fi -AC_MSG_CHECKING([for OpenSSL/SSLeay directory]) +AC_MSG_CHECKING([for OpenSSL directory]) for ssldir in "" $tryssldir /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/pkg /opt /opt/openssl ; do if test ! -z "$ssldir" ; then LDFLAGS="$saved_LDFLAGS -L$ssldir/lib -L$ssldir" diff --git a/dsa.c b/dsa.c index e1f23ec3..1b0251e5 100644 --- a/dsa.c +++ b/dsa.c @@ -63,7 +63,7 @@ dsa_key_from_blob( Key *key; #ifdef DEBUG_DSS - dump_base64(blob, blen); + dump_base64(stderr, blob, blen); #endif /* fetch & parse DSA/DSS pubkey */ key = key_new(KEY_DSA); diff --git a/includes.h b/includes.h index a83e0316..56878a04 100644 --- a/includes.h +++ b/includes.h @@ -99,6 +99,7 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } #include "bsd-snprintf.h" #include "bsd-daemon.h" #include "bsd-login.h" +#include "bsd-base64.h" /* rfc2553 socket API replacements */ #include "fake-getaddrinfo.h" diff --git a/key.c b/key.c index 583c5290..ae355a3f 100644 --- a/key.c +++ b/key.c @@ -255,6 +255,10 @@ key_read(Key *ret, char **cpp) len = 2*strlen(cp); blob = xmalloc(len); n = uudecode(cp, blob, len); + if (n < 0) { + error("uudecode %s failed", cp); + return 0; + } k = dsa_key_from_blob(blob, n); if (k == NULL) return 0; @@ -297,11 +301,26 @@ key_write(Key *key, FILE *f) unsigned char *blob, *uu; dsa_make_key_blob(key, &blob, &len); uu = xmalloc(2*len); - n = uuencode(blob, len, uu); - fprintf(f, "%s %s", SSH_DSS, uu); + n = uuencode(blob, len, uu, 2*len); + if (n > 0) { + fprintf(f, "%s %s", SSH_DSS, uu); + success = 1; + } xfree(blob); xfree(uu); - success = 1; } return success; } +char * +key_type(Key *k) +{ + switch (k->type) { + case KEY_RSA: + return "RSA"; + break; + case KEY_DSA: + return "DSA"; + break; + } + return "unknown"; +} diff --git a/key.h b/key.h index d1bcf3b1..ed3f770b 100644 --- a/key.h +++ b/key.h @@ -17,6 +17,7 @@ Key *key_new(int type); void key_free(Key *k); int key_equal(Key *a, Key *b); char *key_fingerprint(Key *k); +char *key_type(Key *k); int key_write(Key *key, FILE *f); unsigned int key_read(Key *key, char **cpp); diff --git a/nchan.c b/nchan.c index cef94323..51e5ba3c 100644 --- a/nchan.c +++ b/nchan.c @@ -139,6 +139,25 @@ static void chan_rcvd_ieof1(Channel *c) { debug("channel %d: rcvd ieof", c->self); + if (c->type != SSH_CHANNEL_OPEN) { + debug("channel %d: non-open", c->self); + if (c->istate == CHAN_INPUT_OPEN) { + debug("channel %d: non-open: input open -> wait_oclose", c->self); + chan_shutdown_read(c); + chan_send_ieof1(c); + c->istate = CHAN_INPUT_WAIT_OCLOSE; + } else { + error("channel %d: istate %d != open", c->self, c->istate); + } + if (c->ostate == CHAN_OUTPUT_OPEN) { + debug("channel %d: non-open: output open -> closed", c->self); + chan_send_oclose1(c); + c->ostate = CHAN_OUTPUT_CLOSED; + } else { + error("channel %d: ostate %d != open", c->self, c->ostate); + } + return; + } switch (c->ostate) { case CHAN_OUTPUT_OPEN: debug("channel %d: output open -> drain", c->self); @@ -314,7 +333,7 @@ chan_write_failed2(Channel *c) switch (c->ostate) { case CHAN_OUTPUT_OPEN: debug("channel %d: output open -> closed", c->self); - chan_shutdown_write(c); // ?? + chan_shutdown_write(c); /* ?? */ c->ostate = CHAN_OUTPUT_CLOSED; break; case CHAN_OUTPUT_WAIT_DRAIN: diff --git a/packet.c b/packet.c index 0b5850a2..7bc6cada 100644 --- a/packet.c +++ b/packet.c @@ -465,7 +465,7 @@ packet_send1() /* Compute packet length without padding (add checksum, remove padding). */ len = buffer_len(&outgoing_packet) + 4 - 8; - /* Insert padding. */ + /* Insert padding. Initialized to zero in packet_start1() */ padding = 8 - len % 8; if (cipher_type != SSH_CIPHER_NONE) { cp = buffer_ptr(&outgoing_packet); @@ -569,12 +569,16 @@ packet_send2() padlen += block_size; buffer_append_space(&outgoing_packet, &cp, padlen); if (enc && enc->type != SSH_CIPHER_NONE) { + /* random padding */ for (i = 0; i < padlen; i++) { if (i % 4 == 0) rand = arc4random(); cp[i] = rand & 0xff; rand <<= 8; } + } else { + /* clear padding */ + memset(cp, 0, padlen); } /* packet_length includes payload, padding and padding length field */ packet_length = buffer_len(&outgoing_packet) - 4; @@ -657,10 +661,11 @@ packet_read(int *payload_len_ptr) for (;;) { /* Try to read a packet from the buffer. */ type = packet_read_poll(payload_len_ptr); - if (type == SSH_SMSG_SUCCESS + if (!use_ssh2_packet_format && ( + type == SSH_SMSG_SUCCESS || type == SSH_SMSG_FAILURE || type == SSH_CMSG_EOF - || type == SSH_CMSG_EXIT_CONFIRMATION) + || type == SSH_CMSG_EXIT_CONFIRMATION)) packet_integrity_check(*payload_len_ptr, 0, type); /* If we got a packet, return it. */ if (type != SSH_MSG_NONE) diff --git a/radix.c b/radix.c index 9d1c999a..03377334 100644 --- a/radix.c +++ b/radix.c @@ -69,7 +69,7 @@ typedef unsigned short my_u_short; int -creds_to_radix(CREDENTIALS *creds, unsigned char *buf) +creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen) { char *p, *s; int len; @@ -119,7 +119,7 @@ creds_to_radix(CREDENTIALS *creds, unsigned char *buf) p += creds->ticket_st.length; len = p - temp; - return (uuencode((unsigned char *)temp, len, (char *)buf)); + return (uuencode((unsigned char *)temp, len, (char *)buf, buflen)); } int @@ -131,7 +131,8 @@ radix_to_creds(const char *buf, CREDENTIALS *creds) char version; char temp[2048]; - if (!(len = uudecode(buf, (unsigned char *)temp, sizeof(temp)))) + len = uudecode(buf, (unsigned char *)temp, sizeof(temp)); + if (len < 0) return 0; p = temp; diff --git a/readconf.c b/readconf.c index 6c00cd66..fdbd1e7d 100644 --- a/readconf.c +++ b/readconf.c @@ -105,7 +105,7 @@ typedef enum { oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication, oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2, - oGlobalKnownHostsFile2, oUserKnownHostsFile2 + oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication } OpCodes; /* Textual representations of the tokens. */ @@ -121,6 +121,7 @@ static struct { { "rhostsauthentication", oRhostsAuthentication }, { "passwordauthentication", oPasswordAuthentication }, { "rsaauthentication", oRSAAuthentication }, + { "dsaauthentication", oDSAAuthentication }, { "skeyauthentication", oSkeyAuthentication }, #ifdef KRB4 { "kerberosauthentication", oKerberosAuthentication }, @@ -290,6 +291,10 @@ parse_flag: intptr = &options->password_authentication; goto parse_flag; + case oDSAAuthentication: + intptr = &options->dsa_authentication; + goto parse_flag; + case oRSAAuthentication: intptr = &options->rsa_authentication; goto parse_flag; @@ -637,6 +642,7 @@ initialize_options(Options * options) options->use_privileged_port = -1; options->rhosts_authentication = -1; options->rsa_authentication = -1; + options->dsa_authentication = -1; options->skey_authentication = -1; #ifdef KRB4 options->kerberos_authentication = -1; @@ -696,6 +702,8 @@ fill_default_options(Options * options) options->rhosts_authentication = 1; if (options->rsa_authentication == -1) options->rsa_authentication = 1; + if (options->dsa_authentication == -1) + options->dsa_authentication = 1; if (options->skey_authentication == -1) options->skey_authentication = 0; #ifdef KRB4 @@ -745,14 +753,12 @@ fill_default_options(Options * options) sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY); options->num_identity_files = 1; } -#if 0 if (options->num_identity_files2 == 0) { options->identity_files2[0] = - xmalloc(2 + strlen(SSH2_CLIENT_IDENTITY) + 1); - sprintf(options->identity_files2[0], "~/%.100s", SSH2_CLIENT_IDENTITY); + xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1); + sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA); options->num_identity_files2 = 1; } -#endif if (options->escape_char == -1) options->escape_char = '~'; if (options->system_hostfile == NULL) diff --git a/readconf.h b/readconf.h index 7a6dcc81..f3ebe359 100644 --- a/readconf.h +++ b/readconf.h @@ -36,6 +36,7 @@ typedef struct { int rhosts_rsa_authentication; /* Try rhosts with RSA * authentication. */ int rsa_authentication; /* Try RSA authentication. */ + int dsa_authentication; /* Try DSA authentication. */ int skey_authentication; /* Try S/Key or TIS authentication. */ #ifdef KRB4 int kerberos_authentication; /* Try Kerberos diff --git a/scp.c b/scp.c index e6da90a3..df6a691e 100644 --- a/scp.c +++ b/scp.c @@ -573,7 +573,7 @@ next: (void) close(fd); if (i + amt > stb.st_size) amt = stb.st_size - i; if (!haderr) { - result = read(fd, bp->buf, amt); + result = atomicio(read, fd, bp->buf, amt); if (result != amt) haderr = result >= 0 ? EIO : errno; } @@ -692,12 +692,12 @@ sink(argc, argv) targisdir = 1; for (first = 1;; first = 0) { cp = buf; - if (read(remin, cp, 1) <= 0) + if (atomicio(read, remin, cp, 1) <= 0) return; if (*cp++ == '\n') SCREWUP("unexpected "); do { - if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) + if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) SCREWUP("lost connection"); *cp++ = ch; } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); @@ -835,7 +835,7 @@ bad: run_err("%s: %s", np, strerror(errno)); amt = size - i; count += amt; do { - j = read(remin, cp, amt); + j = atomicio(read, remin, cp, amt); if (j <= 0) { run_err("%s", j ? strerror(errno) : "dropped connection"); @@ -848,7 +848,7 @@ bad: run_err("%s: %s", np, strerror(errno)); if (count == bp->cnt) { /* Keep reading so we stay sync'd up. */ if (wrerr == NO) { - j = write(ofd, bp->buf, count); + j = atomicio(write, ofd, bp->buf, count); if (j != count) { wrerr = YES; wrerrno = j >= 0 ? EIO : errno; @@ -861,7 +861,7 @@ bad: run_err("%s: %s", np, strerror(errno)); if (showprogress) progressmeter(1); if (count != 0 && wrerr == NO && - (j = write(ofd, bp->buf, count)) != count) { + (j = atomicio(write, ofd, bp->buf, count)) != count) { wrerr = YES; wrerrno = j >= 0 ? EIO : errno; } @@ -913,7 +913,7 @@ response() { char ch, *cp, resp, rbuf[2048]; - if (read(remin, &resp, sizeof(resp)) != sizeof(resp)) + if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp)) lostconn(0); cp = rbuf; @@ -926,7 +926,7 @@ response() case 1: /* error, followed by error msg */ case 2: /* fatal error, "" */ do { - if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) + if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) lostconn(0); *cp++ = ch; } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); diff --git a/servconf.c b/servconf.c index 8aeed3e3..36a7d1a1 100644 --- a/servconf.c +++ b/servconf.c @@ -32,7 +32,7 @@ initialize_server_options(ServerOptions *options) options->ports_from_cmdline = 0; options->listen_addrs = NULL; options->host_key_file = NULL; - options->dsa_key_file = NULL; + options->host_dsa_key_file = NULL; options->pid_file = NULL; options->server_key_bits = -1; options->login_grace_time = -1; @@ -51,6 +51,7 @@ initialize_server_options(ServerOptions *options) options->rhosts_authentication = -1; options->rhosts_rsa_authentication = -1; options->rsa_authentication = -1; + options->dsa_authentication = -1; #ifdef KRB4 options->kerberos_authentication = -1; options->kerberos_or_local_passwd = -1; @@ -72,6 +73,7 @@ initialize_server_options(ServerOptions *options) options->num_deny_groups = 0; options->ciphers = NULL; options->protocol = SSH_PROTO_UNKNOWN; + options->gateway_ports = -1; } void @@ -83,8 +85,8 @@ fill_default_server_options(ServerOptions *options) add_listen_addr(options, NULL); if (options->host_key_file == NULL) options->host_key_file = HOST_KEY_FILE; - if (options->dsa_key_file == NULL) - options->dsa_key_file = DSA_KEY_FILE; + if (options->host_dsa_key_file == NULL) + options->host_dsa_key_file = HOST_DSA_KEY_FILE; if (options->pid_file == NULL) options->pid_file = SSH_DAEMON_PID_FILE; if (options->server_key_bits == -1) @@ -121,6 +123,8 @@ fill_default_server_options(ServerOptions *options) options->rhosts_rsa_authentication = 0; if (options->rsa_authentication == -1) options->rsa_authentication = 1; + if (options->dsa_authentication == -1) + options->dsa_authentication = 1; #ifdef KRB4 if (options->kerberos_authentication == -1) options->kerberos_authentication = (access(KEYFILE, R_OK) == 0); @@ -147,6 +151,8 @@ fill_default_server_options(ServerOptions *options) options->use_login = 0; if (options->protocol == SSH_PROTO_UNKNOWN) options->protocol = SSH_PROTO_1|SSH_PROTO_2; + if (options->gateway_ports == -1) + options->gateway_ports = 0; } #define WHITESPACE " \t\r\n" @@ -170,7 +176,8 @@ typedef enum { sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset, sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, - sIgnoreUserKnownHosts, sDSAKeyFile, sCiphers, sProtocol, sPidFile + sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile, + sGatewayPorts, sDSAAuthentication } ServerOpCodes; /* Textual representation of the tokens. */ @@ -180,7 +187,7 @@ static struct { } keywords[] = { { "port", sPort }, { "hostkey", sHostKeyFile }, - { "dsakey", sDSAKeyFile }, + { "hostdsakey", sHostDSAKeyFile }, { "pidfile", sPidFile }, { "serverkeybits", sServerKeyBits }, { "logingracetime", sLoginGraceTime }, @@ -191,6 +198,7 @@ static struct { { "rhostsauthentication", sRhostsAuthentication }, { "rhostsrsaauthentication", sRhostsRSAAuthentication }, { "rsaauthentication", sRSAAuthentication }, + { "dsaauthentication", sDSAAuthentication }, #ifdef KRB4 { "kerberosauthentication", sKerberosAuthentication }, { "kerberosorlocalpasswd", sKerberosOrLocalPasswd }, @@ -222,6 +230,7 @@ static struct { { "denygroups", sDenyGroups }, { "ciphers", sCiphers }, { "protocol", sProtocol }, + { "gatewayports", sGatewayPorts }, { NULL, 0 } }; @@ -353,9 +362,9 @@ parse_int: break; case sHostKeyFile: - case sDSAKeyFile: + case sHostDSAKeyFile: charptr = (opcode == sHostKeyFile ) ? - &options->host_key_file : &options->dsa_key_file; + &options->host_key_file : &options->host_dsa_key_file; cp = strtok(NULL, WHITESPACE); if (!cp) { fprintf(stderr, "%s line %d: missing file name.\n", @@ -445,6 +454,10 @@ parse_flag: intptr = &options->rsa_authentication; goto parse_flag; + case sDSAAuthentication: + intptr = &options->dsa_authentication; + goto parse_flag; + #ifdef KRB4 case sKerberosAuthentication: intptr = &options->kerberos_authentication; @@ -511,6 +524,10 @@ parse_flag: intptr = &options->use_login; goto parse_flag; + case sGatewayPorts: + intptr = &options->gateway_ports; + goto parse_flag; + case sLogFacility: intptr = (int *) &options->log_facility; cp = strtok(NULL, WHITESPACE); diff --git a/servconf.h b/servconf.h index f2b17792..40ef05fb 100644 --- a/servconf.h +++ b/servconf.h @@ -32,7 +32,7 @@ typedef struct { char *listen_addr; /* Address on which the server listens. */ struct addrinfo *listen_addrs; /* Addresses on which the server listens. */ char *host_key_file; /* File containing host key. */ - char *dsa_key_file; /* File containing dsa host key. */ + char *host_dsa_key_file; /* File containing dsa host key. */ char *pid_file; /* Where to put our pid */ int server_key_bits;/* Size of the server key. */ int login_grace_time; /* Disconnect if no auth in this time @@ -51,6 +51,7 @@ typedef struct { int keepalives; /* If true, set SO_KEEPALIVE. */ char *ciphers; /* Ciphers in order of preference. */ int protocol; /* Protocol in order of preference. */ + int gateway_ports; /* If true, allow remote connects to forwarded ports. */ SyslogFacility log_facility; /* Facility for system logging. */ LogLevel log_level; /* Level for system logging. */ int rhosts_authentication; /* If true, permit rhosts @@ -58,6 +59,7 @@ typedef struct { int rhosts_rsa_authentication; /* If true, permit rhosts RSA * authentication. */ int rsa_authentication; /* If true, permit RSA authentication. */ + int dsa_authentication; /* If true, permit DSA authentication. */ #ifdef KRB4 int kerberos_authentication; /* If true, permit Kerberos * authentication. */ diff --git a/serverloop.c b/serverloop.c index 1e031873..1bc5d8b7 100644 --- a/serverloop.c +++ b/serverloop.c @@ -171,7 +171,7 @@ retry_select: * stdin or channel data. */ if (compat20) { - // wrong: bad conditionXXX + /* wrong: bad condition XXX */ if (channel_not_very_much_buffered_data()) FD_SET(connection_in, readset); } else { diff --git a/session.c b/session.c index 0679d837..c490f087 100644 --- a/session.c +++ b/session.c @@ -8,7 +8,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.8 2000/04/29 16:06:08 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.12 2000/05/03 18:03:07 markus Exp $"); #include "xmalloc.h" #include "ssh.h" @@ -57,6 +57,7 @@ struct Session { Session *session_new(void); void session_set_fds(Session *s, int fdin, int fdout, int fderr); void session_pty_cleanup(Session *s); +void session_proctitle(Session *s); void do_exec_pty(Session *s, const char *command, struct passwd * pw); void do_exec_no_pty(Session *s, const char *command, struct passwd * pw); @@ -240,6 +241,8 @@ do_authenticated(struct passwd * pw) tty_parse_modes(s->ttyfd, &n_bytes); packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type); + session_proctitle(s); + /* Indicate that we now have a pty. */ success = 1; have_pty = 1; @@ -312,7 +315,7 @@ do_authenticated(struct passwd * pw) break; } debug("Received TCP/IP port forwarding request."); - channel_input_port_forward_request(pw->pw_uid == 0); + channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports); success = 1; break; @@ -397,7 +400,7 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) if (s == NULL) fatal("do_exec_no_pty: no session"); - setproctitle("%s@notty", pw->pw_name); + session_proctitle(s); #ifdef USE_PAM do_pam_setcred(); @@ -527,7 +530,6 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, buf, sizeof(buf)); } - setproctitle("%s@%s", pw->pw_name, strrchr(s->tty, '/') + 1); #ifdef USE_PAM do_pam_session(pw->pw_name, s->tty); @@ -563,7 +565,7 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) /* Close the extra descriptor for the pseudo tty. */ close(ttyfd); -///XXXX ? move to do_child() ?? +/* XXXX ? move to do_child() ??*/ /* * Get IP address of client. This is needed because we want * to record where the user logged in from. If the @@ -1257,6 +1259,8 @@ session_pty_req(Session *s) /* Get window size from the packet. */ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); + session_proctitle(s); + /* XXX parse and set terminal modes */ xfree(term_modes); return 1; @@ -1499,6 +1503,7 @@ session_close(Session *s) { session_pty_cleanup(s); session_free(s); + session_proctitle(s); } void @@ -1542,6 +1547,34 @@ session_close_by_channel(int id, void *arg) } } +char * +session_tty_list(void) +{ + static char buf[1024]; + int i; + buf[0] = '\0'; + for(i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + if (s->used && s->ttyfd != -1) { + if (buf[0] != '\0') + strlcat(buf, ",", sizeof buf); + strlcat(buf, strrchr(s->tty, '/') + 1, sizeof buf); + } + } + if (buf[0] == '\0') + strlcpy(buf, "notty", sizeof buf); + return buf; +} + +void +session_proctitle(Session *s) +{ + if (s->pw == NULL) + error("no user for session %d", s->self); + else + setproctitle("%s@%s", s->pw->pw_name, session_tty_list()); +} + void do_authenticated2(void) { diff --git a/ssh-add.1 b/ssh-add.1 index eadf4fa0..5fe73a9c 100644 --- a/ssh-add.1 +++ b/ssh-add.1 @@ -16,14 +16,14 @@ .Os .Sh NAME .Nm ssh-add -.Nd adds identities for the authentication agent +.Nd adds RSA identities for the authentication agent .Sh SYNOPSIS .Nm ssh-add .Op Fl lLdD .Op Ar .Sh DESCRIPTION .Nm -adds identities to the authentication agent, +adds RSA identities to the authentication agent, .Xr ssh-agent 1 . When run without arguments, it adds the file .Pa $HOME/.ssh/identity . diff --git a/ssh-agent.1 b/ssh-agent.1 index 68e6b84e..66a47569 100644 --- a/ssh-agent.1 +++ b/ssh-agent.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-agent.1,v 1.11 2000/04/12 21:47:50 aaron Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.12 2000/05/03 18:04:39 markus Exp $ .\" .\" -*- nroff -*- .\" @@ -27,7 +27,7 @@ .Oc .Sh DESCRIPTION .Nm -is a program to hold authentication private keys. +is a program to hold private keys used for RSA authentication. The idea is that .Nm is started in the beginning of an X-session or a login session, and diff --git a/ssh-keygen.1 b/ssh-keygen.1 index dfc40408..200761f1 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 @@ -19,7 +19,7 @@ .Nd authentication key generation .Sh SYNOPSIS .Nm ssh-keygen -.Op Fl q +.Op Fl dq .Op Fl b Ar bits .Op Fl N Ar new_passphrase .Op Fl C Ar comment @@ -30,6 +30,15 @@ .Op Fl N Ar new_passphrase .Op Fl f Ar keyfile .Nm ssh-keygen +.Fl x +.Op Fl f Ar keyfile +.Nm ssh-keygen +.Fl X +.Op Fl f Ar keyfile +.Nm ssh-keygen +.Fl y +.Op Fl f Ar keyfile +.Nm ssh-keygen .Fl c .Op Fl P Ar passphrase .Op Fl C Ar comment @@ -43,11 +52,21 @@ .Nm generates and manages authentication keys for .Xr ssh 1 . +.Nm +defaults to generating an RSA key for use by protocols 1.3 and 1.5; +specifying the +.Fl d +flag will create a DSA key instead for use by protocol 2.0. +.Pp Normally each user wishing to use SSH -with RSA authentication runs this once to create the authentication +with RSA or DSA authentication runs this once to create the authentication key in -.Pa $HOME/.ssh/identity . -Additionally, the system administrator may use this to generate host keys. +.Pa $HOME/.ssh/identity +or +.Pa $HOME/.ssh/id_dsa . +Additionally, the system administrator may use this to generate host keys, +as seen in +.Pa /etc/rc . .Pp Normally this program generates the key and asks for a file in which to store the private key. @@ -71,7 +90,7 @@ If the passphrase is lost or forgotten, you will have to generate a new key and copy the corresponding public key to other machines. .Pp -There is also a comment field in the key file that is only for +For RSA, there is also a comment field in the key file that is only for convenience to the user to help identify the key. The comment can tell what the key is for, or whatever is useful. The comment is initialized to @@ -80,6 +99,9 @@ when the key is created, but can be changed using the .Fl c option. .Pp +After a key is generated, instructions below detail where the keys +should be placed to be activated. +.Pp The options are as follows: .Bl -tag -width Ds .It Fl b Ar bits @@ -118,6 +140,15 @@ Provides the (old) passphrase. If RSA support is functional, immediately exits with code 0. If RSA support is not functional, exits with code 1. This flag will be removed once the RSA patent expires. +.It Fl x +This option will read a private +OpenSSH DSA format file and prints to stdout a SSH2-compatible public key. +.It Fl X +This option will read a +SSH2-compatible public key file and print to stdout an OpenSSH DSA compatible public key. +.It Fl y +This option will read a private +OpenSSH DSA format file and prints to stdout an OpenSSH DSA public key. .El .Sh FILES .Bl -tag -width Ds @@ -130,6 +161,8 @@ used to encrypt the private part of this file using 3DES. This file is not automatically accessed by .Nm but it is offered as the default file for the private key. +.Xr sshd 8 +will read this file when a login attempt is made. .It Pa $HOME/.ssh/identity.pub Contains the public key for authentication. The contents of this file should be added to @@ -137,6 +170,24 @@ The contents of this file should be added to on all machines where you wish to log in using RSA authentication. There is no need to keep the contents of this file secret. +.It Pa $HOME/.ssh/id_dsa +Contains the DSA authentication identity of the user. +This file should not be readable by anyone but the user. +It is possible to +specify a passphrase when generating the key; that passphrase will be +used to encrypt the private part of this file using 3DES. +This file is not automatically accessed by +.Nm +but it is offered as the default file for the private key. +.Xr sshd 8 +will read this file when a login attempt is made. +.It Pa $HOME/.ssh/id_dsa.pub +Contains the public key for authentication. +The contents of this file should be added to +.Pa $HOME/.ssh/authorized_keys2 +on all machines +where you wish to log in using DSA authentication. +There is no need to keep the contents of this file secret. .Sh AUTHOR Tatu Ylonen .Pp diff --git a/ssh-keygen.c b/ssh-keygen.c index e3337dd6..9beb653d 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -76,7 +76,8 @@ ask_filename(struct passwd *pw, const char *prompt) { char buf[1024]; snprintf(identity_file, sizeof(identity_file), "%s/%s", - pw->pw_dir, SSH_CLIENT_IDENTITY); + pw->pw_dir, + dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY); printf("%s (%s): ", prompt, identity_file); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) == NULL) @@ -491,8 +492,7 @@ do_change_comment(struct passwd *pw) void usage(void) { - printf("ssh-keygen version %s\n", SSH_VERSION); - printf("Usage: %s [-b bits] [-c] [-d] [-f file] [-l] [-p] [-q] [-x] [-y] [-C comment] [-N new-pass] [-P pass] [-X]\n", __progname); + printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname); exit(1); } diff --git a/ssh.1 b/ssh.1 index b7be8dae..662e4082 100644 --- a/ssh.1 +++ b/ssh.1 @@ -63,7 +63,10 @@ arbitrary TCP/IP ports can also be forwarded over the secure channel. connects and logs into the specified .Ar hostname . The user must prove -his/her identity to the remote machine using one of several methods. +his/her identity to the remote machine using one of several methods +depending on the protocol version used: +.Pp +.Ss SSH protocol version 1 .Pp First, if the machine the user logs in from is listed in .Pa /etc/hosts.equiv @@ -88,8 +91,8 @@ or .Pa hosts.equiv method combined with RSA-based host authentication. It means that if the login would be permitted by -.Pa \&.rhosts , -.Pa \&.shosts , +.Pa $HOME/.rhosts , +.Pa $HOME/.shosts , .Pa /etc/hosts.equiv , or .Pa /etc/shosts.equiv , @@ -105,7 +108,7 @@ This authentication method closes security holes due to IP spoofing, DNS spoofing and routing spoofing. [Note to the administrator: .Pa /etc/hosts.equiv , -.Pa \&.rhosts , +.Pa $HOME/.rhosts , and the rlogin/rsh protocol in general, are inherently insecure and should be disabled if security is desired.] .Pp @@ -143,18 +146,18 @@ implements the RSA authentication protocol automatically. The user creates his/her RSA key pair by running .Xr ssh-keygen 1 . This stores the private key in -.Pa \&.ssh/identity +.Pa $HOME/.ssh/identity and the public key in -.Pa \&.ssh/identity.pub +.Pa $HOME/.ssh/identity.pub in the user's home directory. The user should then copy the .Pa identity.pub to -.Pa \&.ssh/authorized_keys +.Pa $HOME/.ssh/authorized_keys in his/her home directory on the remote machine (the .Pa authorized_keys file corresponds to the conventional -.Pa \&.rhosts +.Pa $HOME/.rhosts file, and has one key per line, though the lines can be very long). After this, the user can log in without giving the password. @@ -174,6 +177,38 @@ The password is sent to the remote host for checking; however, since all communications are encrypted, the password cannot be seen by someone listening on the network. .Pp +.Ss SSH protocol version 2 +.Pp +When a user connects using the protocol version 2 +different authentication methods are available: +At first, the client attempts to authenticate using the public key method. +If this method fails password authentication is tried. +.Pp +The public key method is similar to RSA authentication described +in the previous section except that the DSA algorithm is used +instead of the patented RSA algorithm. +The client uses his private DSA key +.Pa $HOME/.ssh/id_dsa +to sign the session identifier and sends the result to the server. +The server checks whether the matching public key is listed in +.Pa $HOME/.ssh/authorized_keys2 +and grants access if both the key is found and the signature is correct. +The session identifier is derived from a shared Diffie-Hellman value +and is only known to the client and the server. +.Pp +If public key authentication fails or is not available a password +can be sent encrypted to the remote host for proving the user's identity. +This protocol 2 implementation does not yet support Kerberos or +S/Key authentication. +.Pp +Protocol 2 provides additional mechanisms for confidentiality +(the traffic is encrypted using 3DES, blowfish, cast128 or arcfour) +and integrity (hmac-sha1, hmac-md5). +Note that protocol 1 lacks a strong mechanism for ensuring the +integrity of the connection. +.Pp +.Ss Login session and remote execution +.Pp When the user's identity has been accepted by the server, the server either executes the given command, or logs into the machine and gives the user a normal shell on the remote machine. @@ -219,6 +254,8 @@ The exit status of the remote program is returned as the exit status of .Nm ssh . .Pp +.Ss X11 and TCP forwarding +.Pp If the user is using X11 (the .Ev DISPLAY environment variable is set), the connection to the X11 display is @@ -262,15 +299,22 @@ be specified either on command line or in a configuration file. One possible application of TCP/IP forwarding is a secure connection to an electronic purse; another is going trough firewalls. .Pp +.Ss Server authentication +.Pp .Nm -automatically maintains and checks a database containing RSA-based +automatically maintains and checks a database containing identifications for all hosts it has ever been used with. -The database is stored in -.Pa \&.ssh/known_hosts +RSA host keys are stored in +.Pa $HOME/.ssh/known_hosts +and +DSA host keys are stored in +.Pa $HOME/.ssh/known_hosts2 in the user's home directory. -Additionally, the file +Additionally, the files .Pa /etc/ssh_known_hosts -is automatically checked for known hosts. +and +.Pa /etc/ssh_known_hosts2 +are automatically checked for known hosts. Any new hosts are automatically added to the user's file. If a host's identification ever changes, @@ -333,7 +377,7 @@ Allows remote hosts to connect to local forwarded ports. Selects the file from which the identity (private key) for RSA authentication is read. Default is -.Pa \&.ssh/identity +.Pa $HOME/.ssh/identity in the user's home directory. Identity files may also be specified on a per-host basis in the configuration file. @@ -458,7 +502,7 @@ logging in as root on the remote machine. .It Fl 2 Forces .Nm -to use protocol version 2 only. +to try protocol version 2 only. .It Fl 4 Forces .Nm @@ -575,6 +619,15 @@ Specifies the number of tries (one per second) to make before falling back to rsh or exiting. The argument must be an integer. This may be useful in scripts if the connection sometimes fails. +.It Cm DSAAuthentication +Specifies whether to try DSA authentication. +The argument to this keyword must be +.Dq yes +or +.Dq no . +DSA authentication will only be +attempted if a DSA identity file exists. +Note that this option applies to protocol version 2 only. .It Cm EscapeChar Sets the escape character (default: .Ql ~ ) . @@ -640,7 +693,7 @@ specifications). .It Cm IdentityFile Specifies the file from which the user's RSA authentication identity is read (default -.Pa .ssh/identity +.Pa $HOME/.ssh/identity in the user's home directory). Additionally, any identities represented by the authentication agent will be used for authentication. @@ -649,6 +702,16 @@ syntax to refer to a user's home directory. It is possible to have multiple identity files specified in configuration files; all these identities will be tried in sequence. +.It Cm IdentityFile2 +Specifies the file from which the user's DSA authentication identity +is read (default +.Pa $HOME/.ssh/id_dsa +in the user's home directory). +The file name may use the tilde +syntax to refer to a user's home directory. +It is possible to have +multiple identity files specified in configuration files; all these +identities will be tried in sequence. .It Cm KeepAlive Specifies whether the system should send keepalive messages to the other side. @@ -704,6 +767,7 @@ The argument to this keyword must be .Dq yes or .Dq no . +Note that this option applies to both protocol version 1 and 2. .It Cm Port Specifies the port number to connect on the remote host. Default is 22. @@ -717,7 +781,11 @@ and .Dq 2 . Multiple versions must be comma-separated. The default is -.Dq 1 . +.Dq 1,2 . +This means that +.Nm +tries version 1 and falls back to version 2 +if version 1 is no available. .It Cm ProxyCommand Specifies the command to use to connect to the server. The command @@ -782,6 +850,7 @@ or RSA authentication will only be attempted if the identity file exists, or an authentication agent is running. +Note that this option applies to protocol version 1 only. .It Cm SkeyAuthentication Specifies whether to use .Xr skey 1 @@ -798,10 +867,14 @@ If this flag is set to .Nm ssh will never automatically add host keys to the .Pa $HOME/.ssh/known_hosts -file, and refuses to connect hosts whose host key has changed. +and +.Pa $HOME/.ssh/known_hosts2 +files, and refuses to connect hosts whose host key has changed. This provides maximum protection against trojan horse attacks. However, it can be somewhat annoying if you don't have good .Pa /etc/ssh_known_hosts +and +.Pa /etc/ssh_known_hosts2 files installed and frequently connect new hosts. Basically this option forces the user to manually @@ -921,28 +994,36 @@ in .Pa /etc/ssh_known_hosts ) . See .Xr sshd 8 . -.It Pa $HOME/.ssh/identity -Contains the RSA authentication identity of the user. -This file -contains sensitive data and should be readable by the user but not +.It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa +Contains the RSA and the DSA authentication identity of the user. +These files +contain sensitive data and should be readable by the user but not accessible by others (read/write/execute). Note that .Nm -ignores this file if it is accessible by others. +ignores a private key file if it is accessible by others. It is possible to specify a passphrase when generating the key; the passphrase will be used to encrypt the sensitive part of this file using 3DES. -.It Pa $HOME/.ssh/identity.pub +.It Pa $HOME/.ssh/identity.pub, $HOME/.ssh/id_dsa.pub Contains the public key for authentication (public part of the identity file in human-readable form). -The contents of this file should be added to +The contents of the +.Pa $HOME/.ssh/identity.pub +file should be added to .Pa $HOME/.ssh/authorized_keys on all machines where you wish to log in using RSA authentication. -This file is not +The contents of the +.Pa $HOME/.ssh/id_dsa.pub +file should be added to +.Pa $HOME/.ssh/authorized_keys2 +on all machines +where you wish to log in using DSA authentication. +These files are not sensitive and can (but need not) be readable by anyone. -This file is -never used automatically and is not necessary; it is only provided for +These files are +never used automatically and are not necessary; they is only provided for the convenience of the user. .It Pa $HOME/.ssh/config This is the per-user configuration file. @@ -964,9 +1045,17 @@ modulus, public exponent, modulus, and comment fields, separated by spaces). This file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others. -.It Pa /etc/ssh_known_hosts +.It Pa $HOME/.ssh/authorized_keys2 +Lists the DSA keys that can be used for logging in as this user. +This file is not highly sensitive, but the recommended +permissions are read/write for the user, and not accessible by others. +.It Pa /etc/ssh_known_hosts, /etc/ssh_known_hosts2 Systemwide list of known host keys. -This file should be prepared by the +.Pa /etc/ssh_known_hosts +contains RSA and +.Pa /etc/ssh_known_hosts2 +contains DSA keys. +These files should be prepared by the system administrator to contain the public host keys of all machines in the organization. This file should be world-readable. @@ -1025,7 +1114,7 @@ you can store it in .Pa $HOME/.ssh/known_hosts . The easiest way to do this is to connect back to the client from the server machine using ssh; this -will automatically add the host key inxi +will automatically add the host key to .Pa $HOME/.ssh/known_hosts . .It Pa $HOME/.shosts This file is used exactly the same way as @@ -1086,6 +1175,7 @@ but with bugs removed and newer features re-added. Rapidly after the 1.2.12 release, newer versions of the original ssh bore successively more restrictive licenses, and thus demand for a free version was born. +.Pp This version of OpenSSH .Bl -bullet .It @@ -1094,8 +1184,8 @@ directly removed from the source code; any licensed or patented components are chosen from external libraries. .It -has been updated to support ssh protocol 1.5, making it compatible with -all other ssh protocol 1 clients and servers. +has been updated to support SSH protocol 1.5 and 2, making it compatible with +all other SSH clients and servers. .It contains added support for .Xr kerberos 8 @@ -1107,6 +1197,8 @@ supports one-time password authentication with .Pp OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt, and Dug Song. +.Pp +The support for SSH protocol 2 was written by Markus Friedl. .Sh SEE ALSO .Xr rlogin 1 , .Xr rsh 1 , diff --git a/ssh.h b/ssh.h index a5c229d7..afc65272 100644 --- a/ssh.h +++ b/ssh.h @@ -97,7 +97,7 @@ #define HOST_KEY_FILE ETCDIR "/ssh_host_key" #define SERVER_CONFIG_FILE ETCDIR "/sshd_config" #define HOST_CONFIG_FILE ETCDIR "/ssh_config" -#define DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key" +#define HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key" #ifndef SSH_PROGRAM #define SSH_PROGRAM "/usr/bin/ssh" @@ -146,6 +146,7 @@ * file should only be readable by the user him/herself. */ #define SSH_CLIENT_IDENTITY ".ssh/identity" +#define SSH_CLIENT_ID_DSA ".ssh/id_dsa" /* * Configuration file in user\'s home directory. This file need not be @@ -527,7 +528,7 @@ int auth_krb4_password(struct passwd * pw, const char *password); int auth_kerberos_tgt(struct passwd * pw, const char *string); int auth_afs_token(struct passwd * pw, const char *token_string); -int creds_to_radix(CREDENTIALS * creds, unsigned char *buf); +int creds_to_radix(CREDENTIALS * creds, unsigned char *buf, size_t buflen); int radix_to_creds(const char *buf, CREDENTIALS * creds); #endif /* AFS */ diff --git a/sshconnect.c b/sshconnect.c index 859450d3..9b25d7c2 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -8,7 +8,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect.c,v 1.71 2000/04/26 21:28:33 markus Exp $"); +RCSID("$OpenBSD: sshconnect.c,v 1.72 2000/05/04 09:50:22 markus Exp $"); #include #include @@ -465,6 +465,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, const char *user_hostfile, const char *system_hostfile) { Key *file_key; + char *type = key_type(host_key); char *ip = NULL; char hostline[1000], *hostp; HostStatus host_status; @@ -551,18 +552,19 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, switch (host_status) { case HOST_OK: /* The host is known and the key matches. */ - debug("Host '%.200s' is known and matches the host key.", host); + debug("Host '%.200s' is known and matches the %s host key.", + host, type); if (options.check_host_ip) { if (ip_status == HOST_NEW) { if (!add_host_to_hostfile(user_hostfile, ip, host_key)) - log("Failed to add the host key for IP address '%.30s' to the list of known hosts (%.30s).", - ip, user_hostfile); + log("Failed to add the %s host key for IP address '%.30s' to the list of known hosts (%.30s).", + type, ip, user_hostfile); else - log("Warning: Permanently added host key for IP address '%.30s' to the list of known hosts.", - ip); + log("Warning: Permanently added the %s host key for IP address '%.30s' to the list of known hosts.", + type, ip); } else if (ip_status != HOST_OK) - log("Warning: the host key for '%.200s' differs from the key for the IP address '%.30s'", - host, ip); + log("Warning: the %s host key for '%.200s' differs from the key for the IP address '%.30s'", + type, host, ip); } break; case HOST_NEW: @@ -570,16 +572,16 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, if (options.strict_host_key_checking == 1) { /* User has requested strict host key checking. We will not add the host key automatically. The only alternative left is to abort. */ - fatal("No host key is known for %.200s and you have requested strict checking.", host); + fatal("No %s host key is known for %.200s and you have requested strict checking.", type, host); } else if (options.strict_host_key_checking == 2) { /* The default */ char prompt[1024]; char *fp = key_fingerprint(host_key); snprintf(prompt, sizeof(prompt), "The authenticity of host '%.200s' can't be established.\n" - "Key fingerprint is %s.\n" + "%s key fingerprint is %s.\n" "Are you sure you want to continue connecting (yes/no)? ", - host, fp); + host, type, fp); if (!read_yes_or_no(prompt, -1)) fatal("Aborted by user!\n"); } @@ -594,8 +596,8 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, log("Failed to add the host to the list of known hosts (%.500s).", user_hostfile); else - log("Warning: Permanently added '%.200s' to the list of known hosts.", - hostp); + log("Warning: Permanently added '%.200s' (%s) to the list of known hosts.", + hostp, type); break; case HOST_CHANGED: if (options.check_host_ip && host_ip_differ) { @@ -609,7 +611,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - error("The host key for %s has changed,", host); + error("The %s host key for %s has changed,", type, host); error("and the key for the according IP address %s", ip); error("%s. This could either mean that", msg); error("DNS SPOOFING is happening or the IP address for the host"); @@ -621,7 +623,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); - error("It is also possible that the host key has just been changed."); + error("It is also possible that the %s host key has just been changed.", type); error("Please contact your system administrator."); error("Add correct host key in %.100s to get rid of this message.", user_hostfile); @@ -631,7 +633,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, * to edit the key manually and we can only abort. */ if (options.strict_host_key_checking) - fatal("Host key for %.200s has changed and you have requested strict checking.", host); + fatal("%s host key for %.200s has changed and you have requested strict checking.", type, host); /* * If strict host key checking has not been requested, allow diff --git a/sshconnect1.c b/sshconnect1.c index c5a76654..31ee9843 100644 --- a/sshconnect1.c +++ b/sshconnect1.c @@ -9,7 +9,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect1.c,v 1.1 2000/04/26 21:28:33 markus Exp $"); +RCSID("$OpenBSD: sshconnect1.c,v 1.2 2000/05/04 22:38:00 markus Exp $"); #include #include @@ -505,7 +505,7 @@ send_kerberos_tgt() debug("Kerberos V4 ticket expired: %s", TKT_FILE); return 0; } - creds_to_radix(creds, (unsigned char *)buffer); + creds_to_radix(creds, (unsigned char *)buffer, sizeof buffer); xfree(creds); packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); @@ -573,7 +573,7 @@ send_afs_tokens(void) creds.pinst[0] = '\0'; /* Encode token, ship it off. */ - if (!creds_to_radix(&creds, (unsigned char*) buffer)) + if (creds_to_radix(&creds, (unsigned char*) buffer, sizeof buffer) <= 0) break; packet_start(SSH_CMSG_HAVE_AFS_TOKEN); packet_put_string(buffer, strlen(buffer)); diff --git a/sshconnect2.c b/sshconnect2.c index a4342e2d..17325b09 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -28,7 +28,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.5 2000/05/01 18:41:06 markus Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.7 2000/05/06 17:45:37 markus Exp $"); #include #include @@ -283,9 +283,13 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) int ssh2_try_passwd(const char *server_user, const char *host, const char *service) { + static int attempt = 0; char prompt[80]; char *password; + if (attempt++ > options.number_of_password_prompts) + return 0; + snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", server_user, host); password = read_passphrase(prompt, 0); @@ -428,7 +432,7 @@ ssh_userauth2(const char *server_user, char *host) packet_done(); if (partial) debug("partial success"); - if (options.rsa_authentication && + if (options.dsa_authentication && strstr(auths, "publickey") != NULL) { while (i < options.num_identity_files2) { sent = ssh2_try_pubkey( diff --git a/sshd.8 b/sshd.8 index 5043403b..b526827c 100644 --- a/sshd.8 +++ b/sshd.8 @@ -46,9 +46,14 @@ daemon for each incoming connection. The forked daemons handle key exchange, encryption, authentication, command execution, and data exchange. -.Pp +This implementation of +.Nm +supports both SSH protocol version 1 and 2 simultaneously. .Nm works as follows. +.Pp +.Ss SSH protocol version 1 +.Pp Each host has a host-specific RSA key (normally 1024 bits) used to identify the host. Additionally, when @@ -59,7 +64,7 @@ is never stored on disk. Whenever a client connects the daemon responds with its public host and server keys. The client compares the -host key against its own database to verify that it has not changed. +RSA host key against its own database to verify that it has not changed. The client then generates a 256 bit random number. It encrypts this random number using both the host key and the server key, and sends @@ -97,6 +102,28 @@ and .Xr rsh 1 into the machine). .Pp +.Ss SSH protocol version 2 +.Pp +Version 2 works similar: +Each host has a host-specific DSA key used to identify the host. +However, when the daemon starts, it does not generate a server key. +Forward security is provided through a Diffie-Hellman key agreement. +This key agreement results in a shared session key. +The rest of the session is encrypted +using a symmetric cipher, currently +Blowfish, 3DES or CAST128 in CBC mode or Arcfour. +The client selects the encryption algorithm +to use from those offered by the server. +Additionally, session integrity is provided +through a crytographic message authentication code +(hmac-sha1 or hmac-md5). +.Pp +Protocol version 2 provides a public key based +user authentication method (DSAAuthentication) +and conventional password authentication. +.Pp +.Ss Command execution and data forwarding +.Pp If the client successfully authenticates itself, a dialog for preparing the session is entered. At this time the client may request @@ -148,7 +175,7 @@ If the client fails to authenticate the user within this many seconds, the server disconnects and exits. A value of zero indicates no limit. .It Fl h Ar host_key_file -Specifies the file from which the host key is read (default +Specifies the file from which the RSA host key is read (default .Pa /etc/ssh_host_key ) . This option must be given if .Nm @@ -280,12 +307,34 @@ and can be used as wildcards in the patterns. Only user names are valid, a numerical user ID isn't recognized. By default login is allowed regardless of the user name. +.It Cm DSAAuthentication +Specifies whether DSA authentication is allowed. +The default is +.Dq yes . +Note that this option applies to protocol version 2 only. +.It Cm GatewayPorts +Specifies whether remote hosts are allowed to connect to ports +forwarded for the client. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +.It Cm HostDsaKey +Specifies the file containing the private DSA host key (default +.Pa /etc/ssh_host_dsa_key ) +used by SSH protocol 2.0. +Note that +.Nm +disables protcol 2.0 if this file is group/world-accessible. .It Cm HostKey -Specifies the file containing the private host key (default -.Pa /etc/ssh_host_key ) . +Specifies the file containing the private RSA host key (default +.Pa /etc/ssh_host_key ) +used by SSH protocols 1.3 and 1.5. Note that .Nm -does not start if this file is group/world-accessible. +disables protcols 1.3 and 1.5 if this file is group/world-accessible. .It Cm IgnoreRhosts Specifies that .Pa .rhosts @@ -390,6 +439,7 @@ and is not recommended. Specifies whether password authentication is allowed. The default is .Dq yes . +Note that this option applies to both protocol version 1 and 2. .It Cm PermitEmptyPasswords When password authentication is allowed, it specifies whether the server allows login to accounts with empty password strings. @@ -471,6 +521,7 @@ The default is Specifies whether pure RSA authentication is allowed. The default is .Dq yes . +Note that this option applies to protocol version 1 only. .It Cm ServerKeyBits Defines the number of bits in the server key. The minimum value is 512, and the default is 768. @@ -568,7 +619,11 @@ Runs user's shell or command. The .Pa $HOME/.ssh/authorized_keys file lists the RSA keys that are -permitted for RSA authentication. +permitted for RSA authentication in SSH protocols 1.3 and 1.5 +Similarily, the +.Pa $HOME/.ssh/authorized_keys2 +file lists the DSA keys that are +permitted for DSA authentication in SSH protocol 2.0. Each line of the file contains one key (empty lines and lines starting with a .Ql # @@ -655,9 +710,11 @@ from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23.\|.\|.\|2334 ylo@niksula command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hut.fi .Sh SSH_KNOWN_HOSTS FILE FORMAT The -.Pa /etc/ssh_known_hosts +.Pa /etc/ssh_known_hosts , +.Pa /etc/ssh_known_hosts2 , +.Pa $HOME/.ssh/known_hosts , and -.Pa $HOME/.ssh/known_hosts +.Pa $HOME/.ssh/known_hosts2 files contain host public keys for all known hosts. The global file should be prepared by the administrator (optional), and the per-user file is @@ -678,7 +735,7 @@ to indicate negation: if the host name matches a negated pattern, it is not accepted (by that line) even if it matched another pattern on the line. .Pp -Bits, exponent, and modulus are taken directly from the host key; they +Bits, exponent, and modulus are taken directly from the RSA host key; they can be obtained, e.g., from .Pa /etc/ssh_host_key.pub . The optional comment field continues to the end of the line, and is not used. @@ -744,6 +801,21 @@ it being world-readable if the user's home directory resides on an NFS volume). It is recommended that it not be accessible by others. The format of this file is described above. +Users will place the contents of their +.Pa identity.pub +files into this file, as described in +.Xr ssh-keygen 1 . +.It Pa $HOME/.ssh/authorized_keys2 +Lists the DSA keys that can be used to log into the user's account. +This file must be readable by root (which may on some machines imply +it being world-readable if the user's home directory resides on an NFS +volume). +It is recommended that it not be accessible by others. +The format of this file is described above. +Users will place the contents of their +.Pa id_dsa.pub +files into this file, as described in +.Xr ssh-keygen 1 . .It Pa "/etc/ssh_known_hosts" and "$HOME/.ssh/known_hosts" These files are consulted when using rhosts with RSA host authentication to check the public key of the host. @@ -875,6 +947,7 @@ but with bugs removed and newer features re-added. Rapidly after the 1.2.12 release, newer versions of the original ssh bore successively more restrictive licenses, and thus demand for a free version was born. +.Pp This version of OpenSSH .Bl -bullet .It @@ -883,8 +956,8 @@ directly removed from the source code; any licensed or patented components are chosen from external libraries. .It -has been updated to support ssh protocol 1.5, making it compatible with -all other ssh protocol 1 clients and servers. +has been updated to support SSH protocol 1.5 and 2, making it compatible with +all other SSH clients and servers. .It contains added support for .Xr kerberos 8 @@ -893,6 +966,11 @@ authentication and ticket passing. supports one-time password authentication with .Xr skey 1 . .El +.Pp +OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl, +Niels Provos, Theo de Raadt, and Dug Song. +.Pp +The support for SSH protocol 2 was written by Markus Friedl. .Sh SEE ALSO .Xr scp 1 , .Xr ssh 1 , diff --git a/sshd.c b/sshd.c index 70f292cc..d1ed1506 100644 --- a/sshd.c +++ b/sshd.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.113 2000/05/01 20:34:51 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.115 2000/05/03 10:21:49 markus Exp $"); #include "xmalloc.h" #include "rsa.h" @@ -562,8 +562,9 @@ main(int ac, char **av) } if (options.protocol & SSH_PROTO_2) { sensitive_data.dsa_host_key = key_new(KEY_DSA); - if (!load_private_key(options.dsa_key_file, "", sensitive_data.dsa_host_key, NULL)) { - error("Could not load DSA host key: %.200s", options.dsa_key_file); + if (!load_private_key(options.host_dsa_key_file, "", sensitive_data.dsa_host_key, NULL)) { + + error("Could not load DSA host key: %.200s", options.host_dsa_key_file); log("Disabling protocol version 2"); options.protocol &= ~SSH_PROTO_2; } @@ -1320,7 +1321,7 @@ do_ssh2_kex() /* send server hostkey, DH pubkey 'f' and singed H */ packet_start(SSH2_MSG_KEXDH_REPLY); packet_put_string((char *)server_host_key_blob, sbloblen); - packet_put_bignum2(dh->pub_key); // f + packet_put_bignum2(dh->pub_key); /* f */ packet_put_string((char *)signature, slen); packet_send(); xfree(signature); diff --git a/uuencode.c b/uuencode.c index 62689005..fc84d5a5 100644 --- a/uuencode.c +++ b/uuencode.c @@ -1,106 +1,36 @@ /* - * base-64 encoding pinched from lynx2-7-2, who pinched it from rpem. - * Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991 - * and placed in the public domain. - * - * Dug Song + * Copyright (c) 2000 Markus Friedl. All rights reserved. */ - #include "includes.h" #include "xmalloc.h" -char six2pr[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' -}; - -unsigned char pr2six[256]; +#include int -uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded) +uuencode(unsigned char *src, unsigned int srclength, + char *target, size_t targsize) { - /* ENC is the basic 1 character encoding function to make a char printing */ -#define ENC(c) six2pr[c] - - register char *outptr = bufcoded; - unsigned int i; - - for (i = 0; i < nbytes; i += 3) { - *(outptr++) = ENC(*bufin >> 2); /* c1 */ - *(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /* c2 */ - *(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)); /* c3 */ - *(outptr++) = ENC(bufin[2] & 077); /* c4 */ - bufin += 3; - } - if (i == nbytes + 1) { - outptr[-1] = '='; - } else if (i == nbytes + 2) { - outptr[-1] = '='; - outptr[-2] = '='; - } else if (i == nbytes) { - *(outptr++) = '='; - } - *outptr = '\0'; - return (outptr - bufcoded); + return __b64_ntop(src, srclength, target, targsize); } int -uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize) +uudecode(const char *src, unsigned char *target, size_t targsize) { - /* single character decode */ -#define DEC(c) pr2six[(unsigned char)c] -#define MAXVAL 63 - - static int first = 1; - int nbytesdecoded, j; - const char *bufin = bufcoded; - register unsigned char *bufout = bufplain; - register int nprbytes; + int len; + char *encoded, *p; - /* If this is the first call, initialize the mapping table. */ - if (first) { - first = 0; - for (j = 0; j < 256; j++) - pr2six[j] = MAXVAL + 1; - for (j = 0; j < 64; j++) - pr2six[(unsigned char) six2pr[j]] = (unsigned char) j; - } - /* Strip leading whitespace. */ - while (*bufcoded == ' ' || *bufcoded == '\t') - bufcoded++; - - /* - * Figure out how many characters are in the input buffer. If this - * would decode into more bytes than would fit into the output - * buffer, adjust the number of input bytes downwards. - */ - bufin = bufcoded; - while (DEC(*(bufin++)) <= MAXVAL) + /* copy the 'readonly' source */ + encoded = xstrdup(src); + /* skip whitespace and data */ + for (p = encoded; *p == ' ' || *p == '\t'; p++) ; - nprbytes = bufin - bufcoded - 1; - nbytesdecoded = ((nprbytes + 3) / 4) * 3; - if (nbytesdecoded > outbufsize) - nprbytes = (outbufsize * 4) / 3; - - bufin = bufcoded; - - while (nprbytes > 0) { - *(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4); - *(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2); - *(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3])); - bufin += 4; - nprbytes -= 4; - } - if (nprbytes & 03) { - if (DEC(bufin[-2]) > MAXVAL) - nbytesdecoded -= 2; - else - nbytesdecoded -= 1; - } - return (nbytesdecoded); + for (; *p != '\0' && *p != ' ' && *p != '\t'; p++) + ; + /* and remote trailing whitespace because __b64_pton needs this */ + *p = '\0'; + len = __b64_pton(encoded, target, targsize); + xfree(encoded); + return len; } void @@ -108,7 +38,7 @@ dump_base64(FILE *fp, unsigned char *data, int len) { unsigned char *buf = xmalloc(2*len); int i, n; - n = uuencode(data, len, buf); + n = uuencode(data, len, buf, 2*len); for (i = 0; i < n; i++) { fprintf(fp, "%c", buf[i]); if (i % 70 == 69) diff --git a/uuencode.h b/uuencode.h index d3f44628..c92c6274 100644 --- a/uuencode.h +++ b/uuencode.h @@ -1,6 +1,6 @@ #ifndef UUENCODE_H #define UUENCODE_H -int uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded); -int uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize); +int uuencode(unsigned char *src, unsigned int srclength, char *target, size_t targsize); +int uudecode(const char *src, unsigned char *target, size_t targsize); void dump_base64(FILE *fp, unsigned char *data, int len); #endif -- 2.45.1