From a408af7667dc3e5b745c961bd9ed33c31ec063b8 Mon Sep 17 00:00:00 2001 From: damien Date: Tue, 7 Dec 1999 04:38:31 +0000 Subject: [PATCH] - Merged more OpenBSD changes: - [atomicio.c authfd.c scp.c serverloop.c ssh.h sshconnect.c sshd.c] move atomicio into it's own file. wrap all socket write()s which were doing write(sock, buf, len) != len, with atomicio() calls. - [auth-skey.c] fd leak - [authfile.c] properly name fd variable - [channels.c] display great hatred towards strcpy - [pty.c pty.h sshd.c] use openpty() if it exists (it does on BSD4_4) - [tildexpand.c] check for ~ expansion past MAXPATHLEN - Modified helper.c to use new atomicio function. - Reformat Makefile a little - Moved RC4 routines from rc4.[ch] into helper.c - Added autoconf code to detect /dev/ptmx (Solaris) and /dev/ptc (AIX) --- ChangeLog | 18 ++++++++ Makefile.in | 28 ++++++++----- acconfig.h | 6 +++ atomicio.c | 57 +++++++++++++++++++++++++ auth-skey.c | 3 ++ authfd.c | 22 +++++----- authfile.c | 49 +++++++++++----------- channels.c | 5 ++- clientloop.c | 18 ++++---- configure.in | 5 ++- helper.c | 64 +++++++++++++++++++++++----- pty.c | 18 ++++---- pty.h | 2 +- rc4.c | 109 ------------------------------------------------ rc4.h | 115 --------------------------------------------------- scp.c | 24 ----------- serverloop.c | 6 +-- ssh.h | 7 +++- sshconnect.c | 17 ++++---- sshd.c | 17 ++++---- tildexpand.c | 8 +++- 21 files changed, 250 insertions(+), 348 deletions(-) create mode 100644 atomicio.c delete mode 100644 rc4.c delete mode 100644 rc4.h diff --git a/ChangeLog b/ChangeLog index f475f188..fc6b3f37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,24 @@ - Fixed default SSH_ASKPASS - Fix PAM account and session being called multiple times. Problem reported by Adrian Baugh + - Merged more OpenBSD changes: + - [atomicio.c authfd.c scp.c serverloop.c ssh.h sshconnect.c sshd.c] + move atomicio into it's own file. wrap all socket write()s which + were doing write(sock, buf, len) != len, with atomicio() calls. + - [auth-skey.c] + fd leak + - [authfile.c] + properly name fd variable + - [channels.c] + display great hatred towards strcpy + - [pty.c pty.h sshd.c] + use openpty() if it exists (it does on BSD4_4) + - [tildexpand.c] + check for ~ expansion past MAXPATHLEN + - Modified helper.c to use new atomicio function. + - Reformat Makefile a little + - Moved RC4 routines from rc4.[ch] into helper.c + - Added autoconf code to detect /dev/ptmx (Solaris) and /dev/ptc (AIX) 19991204 - Small cleanup of PAM code in sshd.c diff --git a/Makefile.in b/Makefile.in index c2c3261b..80b0a6d4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -23,25 +23,31 @@ LFLAGS=@LDFLAGS@ GNOME_CFLAGS=`gnome-config --cflags gnome gnomeui` GNOME_LIBS=`gnome-config --libs gnome gnomeui` -OBJS= authfd.o authfile.o auth-passwd.o auth-rhosts.o auth-rh-rsa.o \ - auth-rsa.o auth-skey.o bufaux.o buffer.o canohost.o channels.o \ - cipher.o clientloop.o compress.o crc32.o deattack.o helper.o \ - hostfile.o log-client.o login.o log-server.o match.o mpaux.o \ - packet.o pty.o readconf.o readpass.o rsa.o servconf.o serverloop.o \ - sshconnect.o tildexpand.o ttymodes.o uidswap.o xmalloc.o \ - helper.o bsd-mktemp.o bsd-strlcpy.o bsd-strlcat.o bsd-daemon.o \ - bsd-login.o bsd-snprintf.o rc4.o md5crypt.o - +OBJS= atomicio.o authfd.o authfile.o auth-passwd.o auth-rhosts.o \ + auth-rh-rsa.o auth-rsa.o auth-skey.o bsd-daemon.o bsd-login.o \ + bsd-mktemp.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o \ + buffer.o canohost.o channels.o cipher.o clientloop.o compress.o \ + crc32.o deattack.o helper.o helper.o hostfile.o log-client.o \ + login.o log-server.o match.o md5crypt.o mpaux.o packet.o pty.o \ + readconf.o readpass.o rsa.o servconf.o serverloop.o \ + sshconnect.o tildexpand.o ttymodes.o uidswap.o xmalloc.o all: $(OBJS) $(TARGETS) -libssh.a: authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o hostfile.o match.o mpaux.o nchan.o packet.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o helper.o rc4.o bsd-mktemp.o bsd-strlcpy.o bsd-strlcat.o bsd-snprintf.o bsd-daemon.o log.o fingerprint.o +libssh.a: atomicio.o authfd.o authfile.o bsd-daemon.o bsd-mktemp.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 fingerprint.o helper.o \ + hostfile.o log.o match.o mpaux.o nchan.o packet.o \ + readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o $(AR) rv $@ $^ $(RANLIB) $@ ssh: ssh.o sshconnect.o log-client.o readconf.o clientloop.o libssh.a $(CC) -o $@ $^ $(LFLAGS) $(LIBS) -sshd: sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o md5crypt.o libssh.a +sshd: sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ + pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o \ + md5crypt.o libssh.a $(CC) -o $@ $^ $(LFLAGS) $(LIBS) scp: scp.o libssh.a diff --git a/acconfig.h b/acconfig.h index 25f49141..29ec0782 100644 --- a/acconfig.h +++ b/acconfig.h @@ -64,6 +64,12 @@ #undef HAVE_U_INTXX_T #undef HAVE_UINTXX_T +/* Define if you have /dev/ptmx */ +#undef HAVE_DEV_PTMX + +/* Define if you have /dev/ptc */ +#undef HAVE_DEV_PTS_AND_PTC + @BOTTOM@ /* ******************* Shouldn't need to edit below this line ************** */ diff --git a/atomicio.c b/atomicio.c new file mode 100644 index 00000000..1b960e56 --- /dev/null +++ b/atomicio.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1999 Theo de Raadt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$Id$"); + +#include "xmalloc.h" +#include "ssh.h" + +/* + * ensure all of data on socket comes through. f==read || f==write + */ +int +atomicio(f, fd, s, n) + int (*f) (); + int fd; + void *s; + size_t n; +{ + int res, pos = 0; + + while (n > pos) { + res = (f) (fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + case 0: + return (res); + default: + pos += res; + } + } + return (pos); +} diff --git a/auth-skey.c b/auth-skey.c index ebe0483d..55f0780d 100644 --- a/auth-skey.c +++ b/auth-skey.c @@ -114,6 +114,7 @@ skey_fake_keyinfo(char *username) SEEK_SET) != -1 && read(fd, hseed, SKEY_MAX_SEED_LEN) == SKEY_MAX_SEED_LEN) { close(fd); + fd = -1; secret = hseed; secretlen = SKEY_MAX_SEED_LEN; flg = 0; @@ -123,6 +124,8 @@ skey_fake_keyinfo(char *username) secretlen = strlen(secret); flg = 0; } + if (fd != -1) + close(fd); } /* Put that in your pipe and smoke it */ diff --git a/authfd.c b/authfd.c index df5b16f6..e30eab8b 100644 --- a/authfd.c +++ b/authfd.c @@ -145,7 +145,7 @@ ssh_get_first_identity(AuthenticationConnection *auth, msg[2] = 0; msg[3] = 1; msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES; - if (write(auth->fd, msg, 5) != 5) { + if (atomicio(write, auth->fd, msg, 5) != 5) { error("write auth->fd: %.100s", strerror(errno)); return 0; } @@ -270,9 +270,9 @@ ssh_decrypt_challenge(AuthenticationConnection *auth, PUT_32BIT(buf, len); /* Send the length and then the packet to the agent. */ - if (write(auth->fd, buf, 4) != 4 || - write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != - buffer_len(&buffer)) { + if (atomicio(write, auth->fd, buf, 4) != 4 || + atomicio(write, auth->fd, buffer_ptr(&buffer), + buffer_len(&buffer)) != buffer_len(&buffer)) { error("Error writing to authentication socket."); error_cleanup: buffer_free(&buffer); @@ -369,9 +369,9 @@ ssh_add_identity(AuthenticationConnection *auth, PUT_32BIT(buf, len); /* Send the length and then the packet to the agent. */ - if (write(auth->fd, buf, 4) != 4 || - write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != - buffer_len(&buffer)) { + if (atomicio(write, auth->fd, buf, 4) != 4 || + atomicio(write, auth->fd, buffer_ptr(&buffer), + buffer_len(&buffer)) != buffer_len(&buffer)) { error("Error writing to authentication socket."); error_cleanup: buffer_free(&buffer); @@ -450,9 +450,9 @@ ssh_remove_identity(AuthenticationConnection *auth, RSA *key) PUT_32BIT(buf, len); /* Send the length and then the packet to the agent. */ - if (write(auth->fd, buf, 4) != 4 || - write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != - buffer_len(&buffer)) { + if (atomicio(write, auth->fd, buf, 4) != 4 || + atomicio(write, auth->fd, buffer_ptr(&buffer), + buffer_len(&buffer)) != buffer_len(&buffer)) { error("Error writing to authentication socket."); error_cleanup: buffer_free(&buffer); @@ -526,7 +526,7 @@ ssh_remove_all_identities(AuthenticationConnection *auth) buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES; /* Send the length and then the packet to the agent. */ - if (write(auth->fd, buf, 5) != 5) { + if (atomicio(write, auth->fd, buf, 5) != 5) { error("Error writing to authentication socket."); return 0; } diff --git a/authfile.c b/authfile.c index e26b8440..f2699708 100644 --- a/authfile.c +++ b/authfile.c @@ -46,7 +46,7 @@ save_private_key(const char *filename, const char *passphrase, { Buffer buffer, encrypted; char buf[100], *cp; - int f, i; + int fd, i; CipherContext cipher; int cipher_type; u_int32_t rand; @@ -117,19 +117,19 @@ save_private_key(const char *filename, const char *passphrase, memset(buf, 0, sizeof(buf)); buffer_free(&buffer); - f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (f < 0) + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) return 0; - if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) != + if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) != buffer_len(&encrypted)) { debug("Write to key file %.200s failed: %.100s", filename, strerror(errno)); buffer_free(&encrypted); - close(f); + close(fd); remove(filename); return 0; } - close(f); + close(fd); buffer_free(&encrypted); return 1; } @@ -144,28 +144,28 @@ int load_public_key(const char *filename, RSA * pub, char **comment_return) { - int f, i; + int fd, i; off_t len; Buffer buffer; char *cp; - f = open(filename, O_RDONLY); - if (f < 0) + fd = open(filename, O_RDONLY); + if (fd < 0) return 0; - len = lseek(f, (off_t) 0, SEEK_END); - lseek(f, (off_t) 0, SEEK_SET); + len = lseek(fd, (off_t) 0, SEEK_END); + lseek(fd, (off_t) 0, SEEK_SET); buffer_init(&buffer); buffer_append_space(&buffer, &cp, len); - if (read(f, cp, (size_t) len) != (size_t) len) { + if (read(fd, cp, (size_t) len) != (size_t) len) { debug("Read from key file %.200s failed: %.100s", filename, strerror(errno)); buffer_free(&buffer); - close(f); + close(fd); return 0; } - close(f); + close(fd); /* Check that it is at least big enought to contain the ID string. */ if (len < strlen(AUTHFILE_ID_STRING) + 1) { @@ -178,7 +178,7 @@ load_public_key(const char *filename, RSA * pub, * from the buffer. */ for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) - if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) { + if (buffer_get_char(&buffer) != (u_char) AUTHFILE_ID_STRING[i]) { debug("Bad key file %.200s.", filename); buffer_free(&buffer); return 0; @@ -213,7 +213,7 @@ int load_private_key(const char *filename, const char *passphrase, RSA * prv, char **comment_return) { - int f, i, check1, check2, cipher_type; + int fd, i, check1, check2, cipher_type; off_t len; Buffer buffer, decrypted; char *cp; @@ -222,14 +222,15 @@ load_private_key(const char *filename, const char *passphrase, BIGNUM *aux; struct stat st; - f = open(filename, O_RDONLY); - if (f < 0) + fd = open(filename, O_RDONLY); + if (fd < 0) return 0; /* check owner and modes */ - if (fstat(f, &st) < 0 || + if (fstat(fd, &st) < 0 || (st.st_uid != 0 && st.st_uid != getuid()) || (st.st_mode & 077) != 0) { + close(fd); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); @@ -238,20 +239,20 @@ load_private_key(const char *filename, const char *passphrase, error("It is recommended that your private key files are NOT accessible by others."); return 0; } - len = lseek(f, (off_t) 0, SEEK_END); - lseek(f, (off_t) 0, SEEK_SET); + len = lseek(fd, (off_t) 0, SEEK_END); + lseek(fd, (off_t) 0, SEEK_SET); buffer_init(&buffer); buffer_append_space(&buffer, &cp, len); - if (read(f, cp, (size_t) len) != (size_t) len) { + if (read(fd, cp, (size_t) len) != (size_t) len) { debug("Read from key file %.200s failed: %.100s", filename, strerror(errno)); buffer_free(&buffer); - close(f); + close(fd); return 0; } - close(f); + close(fd); /* Check that it is at least big enought to contain the ID string. */ if (len < strlen(AUTHFILE_ID_STRING) + 1) { diff --git a/channels.c b/channels.c index 8fe9c716..ad795152 100644 --- a/channels.c +++ b/channels.c @@ -921,7 +921,7 @@ channel_request_local_forwarding(u_short port, const char *host, /* Allocate a channel number for the socket. */ ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock, xstrdup("port listener")); - strcpy(channels[ch].path, host); + strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); channels[ch].host_port = host_port; channels[ch].listening_port = port; } @@ -1498,7 +1498,8 @@ auth_input_request_forwarding(struct passwd * pw) /* Allocate a channel for the authentication agent socket. */ newch = channel_allocate(SSH_CHANNEL_AUTH_SOCKET, sock, xstrdup("auth socket")); - strcpy(channels[newch].path, channel_forwarded_auth_socket_name); + strlcpy(channels[newch].path, channel_forwarded_auth_socket_name, + sizeof(channels[newch].path)); } /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ diff --git a/clientloop.c b/clientloop.c index 3eaad15a..6ae3c673 100644 --- a/clientloop.c +++ b/clientloop.c @@ -466,13 +466,11 @@ client_suspend_self() /* Flush stdout and stderr buffers. */ if (buffer_len(&stdout_buffer) > 0) - write(fileno(stdout), - buffer_ptr(&stdout_buffer), - buffer_len(&stdout_buffer)); + atomicio(write, fileno(stdout), buffer_ptr(&stdout_buffer), + buffer_len(&stdout_buffer)); if (buffer_len(&stderr_buffer) > 0) - write(fileno(stderr), - buffer_ptr(&stderr_buffer), - buffer_len(&stderr_buffer)); + atomicio(write, fileno(stderr), buffer_ptr(&stderr_buffer), + buffer_len(&stderr_buffer)); leave_raw_mode(); @@ -739,7 +737,7 @@ client_process_output(fd_set * writeset) if (FD_ISSET(fileno(stdout), writeset)) { /* Write as much data as possible. */ len = write(fileno(stdout), buffer_ptr(&stdout_buffer), - buffer_len(&stdout_buffer)); + buffer_len(&stdout_buffer)); if (len <= 0) { if (errno == EAGAIN) len = 0; @@ -762,7 +760,7 @@ client_process_output(fd_set * writeset) if (FD_ISSET(fileno(stderr), writeset)) { /* Write as much data as possible. */ len = write(fileno(stderr), buffer_ptr(&stderr_buffer), - buffer_len(&stderr_buffer)); + buffer_len(&stderr_buffer)); if (len <= 0) { if (errno == EAGAIN) len = 0; @@ -911,7 +909,7 @@ client_loop(int have_pty, int escape_char_arg) /* Output any buffered data for stdout. */ while (buffer_len(&stdout_buffer) > 0) { len = write(fileno(stdout), buffer_ptr(&stdout_buffer), - buffer_len(&stdout_buffer)); + buffer_len(&stdout_buffer)); if (len <= 0) { error("Write failed flushing stdout buffer."); break; @@ -922,7 +920,7 @@ client_loop(int have_pty, int escape_char_arg) /* Output any buffered data for stderr. */ while (buffer_len(&stderr_buffer) > 0) { len = write(fileno(stderr), buffer_ptr(&stderr_buffer), - buffer_len(&stderr_buffer)); + buffer_len(&stderr_buffer)); if (len <= 0) { error("Write failed flushing stderr buffer."); break; diff --git a/configure.in b/configure.in index 86f2dde7..62e68317 100644 --- a/configure.in +++ b/configure.in @@ -59,7 +59,7 @@ dnl Checks for header files. AC_CHECK_HEADERS(endian.h lastlog.h login.h maillock.h netgroup.h paths.h pty.h shadow.h util.h utmp.h sys/select.h sys/time.h) dnl Checks for library functions. -AC_CHECK_FUNCS(arc4random mkdtemp openpty setenv setlogin setproctitle snprintf strlcat strlcpy vsnprintf) +AC_CHECK_FUNCS(arc4random mkdtemp openpty _getpty setenv setlogin setproctitle snprintf strlcat strlcpy vsnprintf) AC_CHECK_FUNC(login, [AC_DEFINE(HAVE_LOGIN)], @@ -221,6 +221,9 @@ else AC_DEFINE_UNQUOTED(LASTLOG_LOCATION, "$lastlog") fi +AC_CHECK_FILE("/dev/ptmx", AC_DEFINE_UNQUOTED(HAVE_DEV_PTMX)) +AC_CHECK_FILE("/dev/ptc", AC_DEFINE_UNQUOTED(HAVE_DEV_PTS_AND_PTC)) + AC_MSG_CHECKING([whether libc defines __progname]) AC_TRY_LINK([], [extern char *__progname; printf("%s", __progname);], diff --git a/helper.c b/helper.c index 91a78b57..bf4e145b 100644 --- a/helper.c +++ b/helper.c @@ -45,7 +45,6 @@ #include #include -#include "rc4.h" #include "xmalloc.h" #include "ssh.h" #include "config.h" @@ -57,10 +56,58 @@ #ifndef HAVE_ARC4RANDOM +typedef struct +{ + unsigned int s[256]; + int i; + int j; +} rc4_t; + void get_random_bytes(unsigned char *buf, int len); +void rc4_key(rc4_t *r, unsigned char *key, int len); +void rc4_getbytes(rc4_t *r, unsigned char *buffer, int len); static rc4_t *rc4 = NULL; +void rc4_key(rc4_t *r, unsigned char *key, int len) +{ + int t; + + for(r->i = 0; r->i < 256; r->i++) + r->s[r->i] = r->i; + + r->j = 0; + for(r->i = 0; r->i < 256; r->i++) + { + r->j = (r->j + r->s[r->i] + key[r->i % len]) % 256; + t = r->s[r->i]; + r->s[r->i] = r->s[r->j]; + r->s[r->j] = t; + } + r->i = r->j = 0; +} + +void rc4_getbytes(rc4_t *r, unsigned char *buffer, int len) +{ + int t; + int c; + + c = 0; + while(c < len) + { + r->i = (r->i + 1) % 256; + r->j = (r->j + r->s[r->i]) % 256; + t = r->s[r->i]; + r->s[r->i] = r->s[r->j]; + r->s[r->j] = t; + + t = (r->s[r->i] + r->s[r->j]) % 256; + + buffer[c] = r->s[t]; + c++; + } +} + unsigned int arc4random(void) { unsigned int r; @@ -117,7 +164,8 @@ void get_random_bytes(unsigned char *buf, int len) /* Send blocking read request to EGD */ egd_message[1] = len; - c = write(random_pool, egd_message, sizeof(egd_message)); + + c = atomicio(write, random_pool, egd_message, sizeof(egd_message)); if (c == -1) fatal("Couldn't write to EGD socket \"%s\": %s", RANDOM_POOL, strerror(errno)); @@ -129,15 +177,9 @@ void get_random_bytes(unsigned char *buf, int len) #endif /* HAVE_EGD */ - do { - c = read(random_pool, buf, len); - - if ((c == -1) && (errno != EINTR)) - fatal("Couldn't read from random pool \"%s\": %s", RANDOM_POOL, strerror(errno)); - } while (c == -1); - - if (c != len) - fatal("Short read from random pool \"%s\"", RANDOM_POOL); + c = atomicio(read, random_pool, buf, len); + if (c <= 0) + fatal("Couldn't read from random pool \"%s\": %s", RANDOM_POOL, strerror(errno)); close(random_pool); } diff --git a/pty.c b/pty.c index 0675583d..455d4416 100644 --- a/pty.c +++ b/pty.c @@ -40,17 +40,19 @@ RCSID("$Id$"); */ int -pty_allocate(int *ptyfd, int *ttyfd, char *namebuf) +pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen) { -#ifdef HAVE_OPENPTY +#if defined(HAVE_OPENPTY) || defined(BSD4_4) /* openpty(3) exists in OSF/1 and some other os'es */ + char buf[64]; int i; - i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL); + i = openpty(ptyfd, ttyfd, buf, NULL, NULL); if (i < 0) { error("openpty: %.100s", strerror(errno)); return 0; } + strlcpy(namebuf, buf, namebuflen); /* possible truncation */ return 1; #else /* HAVE_OPENPTY */ #ifdef HAVE__GETPTY @@ -65,7 +67,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf) error("_getpty: %.100s", strerror(errno)); return 0; } - strcpy(namebuf, slave); + strlcpy(namebuf, slave, namebuflen); /* Open the slave side. */ *ttyfd = open(namebuf, O_RDWR | O_NOCTTY); if (*ttyfd < 0) { @@ -99,7 +101,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf) pts = ptsname(ptm); if (pts == NULL) error("Slave pty side name could not be obtained."); - strcpy(namebuf, pts); + strlcpy(namebuf, pts, namebuflen); *ptyfd = ptm; /* Open the slave side. */ @@ -130,7 +132,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf) name = ttyname(*ptyfd); if (!name) fatal("Open of /dev/ptc returns device for which ttyname fails."); - strcpy(namebuf, name); + strlcpy(namebuf, name, namebuflen); *ttyfd = open(name, O_RDWR | O_NOCTTY); if (*ttyfd < 0) { error("Could not open pty slave side %.100s: %.100s", @@ -154,8 +156,8 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf) *ptyfd = open(buf, O_RDWR | O_NOCTTY); if (*ptyfd < 0) continue; - snprintf(namebuf, sizeof buf, "/dev/tty%c%c", ptymajors[i / num_minors], - ptyminors[i % num_minors]); + snprintf(namebuf, sizeof namebuflen, "/dev/tty%c%c", + ptymajors[i / num_minors], ptyminors[i % num_minors]); /* Open the slave side. */ *ttyfd = open(namebuf, O_RDWR | O_NOCTTY); diff --git a/pty.h b/pty.h index 6d02121e..25668f01 100644 --- a/pty.h +++ b/pty.h @@ -24,7 +24,7 @@ * descriptors for the pty and tty sides and the name of the tty side are * returned (the buffer must be able to hold at least 64 characters). */ -int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname); +int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname, int ttynamelen); /* * Releases the tty. Its ownership is returned to root, and permissions to diff --git a/rc4.c b/rc4.c deleted file mode 100644 index 2ff6f37b..00000000 --- a/rc4.c +++ /dev/null @@ -1,109 +0,0 @@ -/*! \file rc4.c - \brief Source file for RC4 stream cipher routines - \author Damien Miller - \version 0.0.0 - \date 1999 - - A simple implementation of the RC4 stream cipher, based on the - description given in _Bruce Schneier's_ "Applied Cryptography" - 2nd edition. - - Copyright 1999 Damien Miller - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - AND NONINFRINGEMENT. IN NO EVENT SHALL DAMIEN MILLER BE LIABLE - FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - \warning None of these functions clears its memory after use. It - \warning is the responsability of the calling routines to ensure - \warning that any sensitive data (keystream, key or plaintext) is - \warning properly erased after use. - - \warning The name "RC4" is trademarked in the United States, - \warning you may need to use "RC4 compatible" or "ARC4" - \warning (Alleged RC4). -*/ - -/* $Id$ */ - -#include "config.h" - -#ifndef HAVE_ARC4RANDOM -#include "rc4.h" - - -void rc4_key(rc4_t *r, unsigned char *key, int len) -{ - int t; - - for(r->i = 0; r->i < 256; r->i++) - r->s[r->i] = r->i; - - r->j = 0; - for(r->i = 0; r->i < 256; r->i++) - { - r->j = (r->j + r->s[r->i] + key[r->i % len]) % 256; - t = r->s[r->i]; - r->s[r->i] = r->s[r->j]; - r->s[r->j] = t; - } - r->i = r->j = 0; -} - -void rc4_crypt(rc4_t *r, unsigned char *plaintext, int len) -{ - int t; - int c; - - c = 0; - while(c < len) - { - r->i = (r->i + 1) % 256; - r->j = (r->j + r->s[r->i]) % 256; - t = r->s[r->i]; - r->s[r->i] = r->s[r->j]; - r->s[r->j] = t; - - t = (r->s[r->i] + r->s[r->j]) % 256; - - plaintext[c] ^= r->s[t]; - c++; - } -} - -void rc4_getbytes(rc4_t *r, unsigned char *buffer, int len) -{ - int t; - int c; - - c = 0; - while(c < len) - { - r->i = (r->i + 1) % 256; - r->j = (r->j + r->s[r->i]) % 256; - t = r->s[r->i]; - r->s[r->i] = r->s[r->j]; - r->s[r->j] = t; - - t = (r->s[r->i] + r->s[r->j]) % 256; - - buffer[c] = r->s[t]; - c++; - } -} -#endif /* !HAVE_ARC4RANDOM */ diff --git a/rc4.h b/rc4.h deleted file mode 100644 index 680936a4..00000000 --- a/rc4.h +++ /dev/null @@ -1,115 +0,0 @@ -/*! \file rc4.h - \brief Header file for RC4 stream cipher routines - \author Damien Miller - \version 0.0.0 - \date 1999 - - A simple implementation of the RC4 stream cipher, based on the - description given in _Bruce Schneier's_ "Applied Cryptography" - 2nd edition. - - Copyright 1999 Damien Miller - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE - AND NONINFRINGEMENT. IN NO EVENT SHALL DAMIEN MILLER BE LIABLE - FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - \warning None of these functions clears its memory after use. It - \warning is the responsability of the calling routines to ensure - \warning that any sensitive data (keystream, key or plaintext) is - \warning properly erased after use. - - \warning The name "RC4" is trademarked in the United States, - \warning you may need to use "RC4 compatible" or "ARC4" - \warning (Alleged RC4). -*/ - -/* $Id$ */ - -#ifndef _RC4_H -#define _RC4_H - -#include "config.h" -#ifndef HAVE_ARC4RANDOM - -/*! \struct rc4_t - \brief RC4 stream cipher state object - \var s State array - \var i Monotonic index - \var j Randomised index - - \warning This structure should not be accessed directly. To - \warning initialise a rc4_t object, you should use the rc4_key() - \warning function - - This structure holds the current state of the RC4 algorithm. -*/ -typedef struct -{ - unsigned int s[256]; - int i; - int j; -} rc4_t; - -/*! \fn void rc4_key(rc4_t *r, unsigned char *key, int len); - \brief Set up key structure of RC4 stream cipher - \param r pointer to RC4 structure to be seeded - \param key pointer to buffer containing raw key - \param len length of key - - This function set the internal state of the RC4 data structure - pointed to by \a r using the specified \a key of length \a len. - - This function can use up to 256 bytes of key, any more are ignored. - - \warning Stream ciphers (such as RC4) can be insecure if the same - \warning key is used repeatedly. Ensure that any key specified has - \warning an reasonably sized Initialisation Vector component. -*/ -void rc4_key(rc4_t *r, unsigned char *key, int len); - -/*! \fn rc4_crypt(rc4_t *r, unsigned char *plaintext, int len); - \brief Crypt bytes using RC4 algorithm - \param r pointer to RC4 structure to be used - \param plaintext Pointer to bytes to encrypt - \param len number of bytes to crypt - - This function encrypts one or more bytes (pointed to by \a plaintext) - using the RC4 algorithm. \a r is a state structure that must be - initialiased using the rc4_key() function prior to use. - - Since RC4 XORs each byte of plaintext with a byte of keystream, - this function can be used for both encryption and decryption. -*/ -void rc4_crypt(rc4_t *r, unsigned char *plaintext, int len); - -/*! \fn rc4_getbytes(rc4_t *r, unsigned char *buffer, int len); - \brief Generate key stream using the RC4 stream cipher - \param r pointer to RC4 structure to be used - \param buffer pointer to buffer in which to deposit keystream - \param len number of bytes to deposit - - This function gives access to the raw RC4 key stream. In this - consiguration RC4 can be used as a fast, strong pseudo-random - number generator with a very long period. -*/ -void rc4_getbytes(rc4_t *r, unsigned char *buffer, int len); - -#endif /* !HAVE_ARC4RANDOM */ - -#endif /* _RC4_H */ diff --git a/scp.c b/scp.c index dc2bb4ed..593954d0 100644 --- a/scp.c +++ b/scp.c @@ -1065,30 +1065,6 @@ lostconn(signo) exit(1); } -/* - * ensure all of data on socket comes through. f==read || f==write - */ -int -atomicio(f, fd, s, n) - int (*f) (); - char *s; -{ - int res, pos = 0; - - while (n > pos) { - res = (f) (fd, s + pos, n - pos); - switch (res) { - case -1: - if (errno == EINTR || errno == EAGAIN) - continue; - case 0: - return (res); - default: - pos += res; - } - } - return (pos); -} void alarmtimer(int wait) diff --git a/serverloop.c b/serverloop.c index 94c21157..a5ecfe97 100644 --- a/serverloop.c +++ b/serverloop.c @@ -170,7 +170,7 @@ make_packets_from_stderr_data() /* Send buffered stderr data to the client. */ while (buffer_len(&stderr_buffer) > 0 && - packet_not_very_much_data_to_write()) { + packet_not_very_much_data_to_write()) { len = buffer_len(&stderr_buffer); if (packet_is_interactive()) { if (len > 512) @@ -199,7 +199,7 @@ make_packets_from_stdout_data() /* Send buffered stdout data to the client. */ while (buffer_len(&stdout_buffer) > 0 && - packet_not_very_much_data_to_write()) { + packet_not_very_much_data_to_write()) { len = buffer_len(&stdout_buffer); if (packet_is_interactive()) { if (len > 512) @@ -364,7 +364,7 @@ process_output(fd_set * writeset) /* Write buffered data to program stdin. */ if (fdin != -1 && FD_ISSET(fdin, writeset)) { len = write(fdin, buffer_ptr(&stdin_buffer), - buffer_len(&stdin_buffer)); + buffer_len(&stdin_buffer)); if (len <= 0) { #ifdef USE_PIPES close(fdin); diff --git a/ssh.h b/ssh.h index d72dcb4e..0ec608f0 100644 --- a/ssh.h +++ b/ssh.h @@ -702,9 +702,14 @@ struct envstring { struct envstring *next; char *s; }; + +/* + * Ensure all of data on socket comes through. f==read || f==write + */ +int atomicio(int (*f)(), int fd, void *s, size_t n); + #ifdef KRB4 #include - /* * Performs Kerberos v4 mutual authentication with the client. This returns 0 * if the client could not be authenticated, and 1 if authentication was diff --git a/sshconnect.c b/sshconnect.c index d64eafd9..3526cccc 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -537,7 +537,7 @@ try_rsa_authentication(const char *authfile) if (!load_private_key(authfile, "", private_key, NULL)) { char buf[300]; snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ", - comment); + comment); if (!options.batch_mode) passphrase = read_passphrase(buf, 0); else { @@ -1036,8 +1036,8 @@ ssh_exchange_identification() /* Send our own protocol version identification. */ snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", - PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); - if (write(connection_out, buf, strlen(buf)) != strlen(buf)) + PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); + if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf)) fatal("write: %.100s", strerror(errno)); } @@ -1292,10 +1292,10 @@ ssh_login(int host_key_valid, char prompt[1024]; char *fp = fingerprint(host_key->e, host_key->n); snprintf(prompt, sizeof(prompt), - "The authenticity of host '%.200s' can't be established.\n" - "Key fingerprint is %d %s.\n" - "Are you sure you want to continue connecting (yes/no)? ", - host, BN_num_bits(host_key->n), fp); + "The authenticity of host '%.200s' can't be established.\n" + "Key fingerprint is %d %s.\n" + "Are you sure you want to continue connecting (yes/no)? ", + host, BN_num_bits(host_key->n), fp); if (!read_yes_or_no(prompt, -1)) fatal("Aborted by user!\n"); } @@ -1599,8 +1599,9 @@ ssh_login(int host_key_valid, if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) && options.password_authentication && !options.batch_mode) { char prompt[80]; + snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", - server_user, host); + server_user, host); if (try_password_authentication(prompt)) return; } diff --git a/sshd.c b/sshd.c index 9b067770..1252f760 100644 --- a/sshd.c +++ b/sshd.c @@ -812,7 +812,7 @@ main(int ac, char **av) /* Send our protocol version identification. */ snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); - if (write(sock_out, buf, strlen(buf)) != strlen(buf)) + if (atomicio(write, sock_out, buf, strlen(buf)) != strlen(buf)) fatal("Could not write ident string to %s.", get_remote_ipaddr()); /* Read other side\'s version identification. */ @@ -838,9 +838,10 @@ main(int ac, char **av) * several versions and set appropriate flags to handle them. */ if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, - remote_version) != 3) { - const char *s = "Protocol mismatch.\n"; - (void) write(sock_out, s, strlen(s)); + remote_version) != 3) { + char *s = "Protocol mismatch.\n"; + + (void) atomicio(write, sock_out, s, strlen(s)); close(sock_in); close(sock_out); fatal("Bad protocol version identification '%.100s' from %s", @@ -849,8 +850,9 @@ main(int ac, char **av) debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); if (remote_major != PROTOCOL_MAJOR) { - const char *s = "Protocol major versions differ.\n"; - (void) write(sock_out, s, strlen(s)); + char *s = "Protocol major versions differ.\n"; + + (void) atomicio(write, sock_out, s, strlen(s)); close(sock_in); close(sock_out); fatal("Protocol major versions differ for %s: %d vs. %d", @@ -1737,7 +1739,8 @@ do_authenticated(struct passwd * pw) debug("Allocating pty."); /* Allocate a pty and open it. */ - if (!pty_allocate(&ptyfd, &ttyfd, ttyname)) { + if (!pty_allocate(&ptyfd, &ttyfd, ttyname, + sizeof(ttyname))) { error("Failed to allocate pty."); goto fail; } diff --git a/tildexpand.c b/tildexpand.c index 06f397c1..9fd430bd 100644 --- a/tildexpand.c +++ b/tildexpand.c @@ -23,6 +23,7 @@ tilde_expand_filename(const char *filename, uid_t my_uid) char *expanded; struct passwd *pw; char user[100]; + int len; /* Return immediately if no tilde. */ if (filename[0] != '~') @@ -56,7 +57,10 @@ tilde_expand_filename(const char *filename, uid_t my_uid) return xstrdup(pw->pw_dir); } /* Build a path combining the specified directory and path. */ - expanded = xmalloc(strlen(pw->pw_dir) + strlen(cp + 1) + 2); - sprintf(expanded, "%s/%s", pw->pw_dir, cp + 1); + len = strlen(pw->pw_dir) + strlen(cp + 1) + 2; + if (len > MAXPATHLEN) + fatal("Home directory too long (%d > %d", len-1, MAXPATHLEN-1); + expanded = xmalloc(len); + snprintf(expanded, len, "%s/%s", pw->pw_dir, cp + 1); return expanded; } -- 2.45.1