- Fixed default SSH_ASKPASS
- Fix PAM account and session being called multiple times. Problem
reported by Adrian Baugh <adrian@merlin.keble.ox.ac.uk>
+ - 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
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
#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 ************** */
--- /dev/null
+/*
+ * 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);
+}
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;
secretlen = strlen(secret);
flg = 0;
}
+ if (fd != -1)
+ close(fd);
}
/* Put that in your pipe and smoke it */
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;
}
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);
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);
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);
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;
}
{
Buffer buffer, encrypted;
char buf[100], *cp;
- int f, i;
+ int fd, i;
CipherContext cipher;
int cipher_type;
u_int32_t rand;
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;
}
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) {
* 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;
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;
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("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
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) {
/* 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;
}
/* 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. */
/* 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();
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;
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;
/* 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;
/* 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;
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)],
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);],
#include <sys/un.h>
#include <fcntl.h>
-#include "rc4.h"
#include "xmalloc.h"
#include "ssh.h"
#include "config.h"
#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;
/* 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));
#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);
}
*/
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
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) {
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. */
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",
*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);
* 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
+++ /dev/null
-/*! \file rc4.c
- \brief Source file for RC4 stream cipher routines
- \author Damien Miller <djm@mindrot.org>
- \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 */
+++ /dev/null
-/*! \file rc4.h
- \brief Header file for RC4 stream cipher routines
- \author Damien Miller <djm@mindrot.org>
- \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 */
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)
/* 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)
/* 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)
/* 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);
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 <krb.h>
-
/*
* Performs Kerberos v4 mutual authentication with the client. This returns 0
* if the client could not be authenticated, and 1 if authentication was
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 {
/* 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));
}
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");
}
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;
}
/* 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. */
* 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",
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",
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;
}
char *expanded;
struct passwd *pw;
char user[100];
+ int len;
/* Return immediately if no tilde. */
if (filename[0] != '~')
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;
}