Subject: pkg/6392: buffer overflow in ssh 1.2.26
To: None <gnats-bugs@gnats.netbsd.org>
From: Wolfgang Rupprecht <wolfgang@wsrcc.com>
List: netbsd-bugs
Date: 11/02/1998 10:29:44
>Number:         6392
>Category:       pkg
>Synopsis:       buffer overflow in ssh 1.2.26
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Nov  2 10:35:01 1998
>Last-Modified:
>Originator:     Wolfgang Rupprecht
>Organization:
W S Rupprecht Computer Consulting, Fremont CA
>Release:        pkgsrc current
>Environment:
	
System: NetBSD capsicum.wsrcc.com 1.3H NetBSD 1.3H (WSRCC) #0: Fri Oct 23 17:52:50 PDT 1998 root@capsicum.wsrcc.com:/v/src/netbsd/NetBSD-current/usr/src/sys/arch/i386/compile/WSRCC i386


>Description:
	buffer overflow in ssh 1.2.26

>How-To-Repeat:
	inspect code

	Since this is a buffer overflow bug in security software I've
        flagged this as high/critical.  There is still some controversy 
	whether this is actually exploitable.

>Fix:
	put this patch file into the pkgsrc/security/ssh/patches directory
	with the name patch-vsprintf .
	make clean ; make ; su ; make install

	NB: This patch courtesy of:
	ftp://ftp.wibble.net/pub/ssh-patched/ssh-1.2.26-vsprintf.diff

patch-vsprintf:

diff -ruN ssh-1.2.26-clean/Makefile.in ssh-1.2.26/Makefile.in
--- ssh-1.2.26-clean/Makefile.in	Thu Jul  9 04:40:39 1998
+++ Makefile.in	Mon Nov  2 14:20:42 1998
@@ -315,7 +315,7 @@
 	rsa.o randoms.o md5.o buffer.o emulate.o packet.o compress.o \
 	xmalloc.o ttymodes.o newchannels.o bufaux.o authfd.o authfile.o \
 	crc32.o rsaglue.o cipher.o des.o match.o arcfour.o mpaux.o \
-	userfile.o signals.o blowfish.o deattack.o
+	userfile.o signals.o blowfish.o deattack.o snprintf.o
 SSHD_OBJS = sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o \
 	log-server.o login.o hostfile.o canohost.o servconf.o tildexpand.o \
 	serverloop.o $(COMMON_OBJS) $(KERBEROS_OBJS) $(SSHDCONFOBJS)
@@ -332,7 +332,7 @@
 	xmalloc.o bufaux.o authfd.o authfile.o cipher.o blowfish.o \
 	des.o arcfour.o mpaux.o userfile.o signals.o $(LIBOBJS) \
 	$(CONFOBJS)
-SCP_OBJS = scp.o xmalloc.o
+SCP_OBJS = scp.o xmalloc.o snprintf.o
 #ifdef F_SECURE_COMMERCIAL
 #
 #
@@ -359,7 +359,7 @@
 	randoms.h ttymodes.h authfd.h crc32.h includes.h \
 	readconf.h userfile.h blowfish.h des.h md5.h rsa.h version.h bufaux.h \
 	mpaux.h servconf.h xmalloc.h buffer.h emulate.h packet.h ssh.h \
-	deattack.h
+	deattack.h snprintf.h
 
 DISTFILES = $(srcdir)/COPYING $(srcdir)/README $(srcdir)/README.SECURID \
 	$(srcdir)/README.TIS $(srcdir)/README.SECURERPC \
diff -ruN ssh-1.2.26-clean/config.h.in ssh-1.2.26/config.h.in
--- ssh-1.2.26-clean/config.h.in	Thu Jul  9 04:41:12 1998
+++ config.h.in	Mon Nov  2 14:20:42 1998
@@ -443,6 +443,9 @@
 /* Define if you have the setsid function.  */
 #undef HAVE_SETSID
 
+/* Define if you have the snprintf function.  */
+#undef HAVE_SNPRINTF
+
 /* Define if you have the socketpair function.  */
 #undef HAVE_SOCKETPAIR
 
@@ -469,6 +472,9 @@
 
 /* Define if you have the vhangup function.  */
 #undef HAVE_VHANGUP
+
+/* Define if you have the vsnprintf function.  */
+#undef HAVE_VSNPRINTF
 
 /* Define if you have the waitpid function.  */
 #undef HAVE_WAITPID
diff -ruN ssh-1.2.26-clean/configure ssh-1.2.26/configure
--- ssh-1.2.26-clean/configure	Thu Jul  9 04:41:14 1998
+++ configure	Mon Nov  2 14:20:42 1998
@@ -4464,7 +4464,7 @@
 fi
 done
 
-for ac_func in setpgid daemon waitpid ttyslot authenticate
+for ac_func in setpgid daemon waitpid ttyslot authenticate snprintf vsnprintf
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
 echo "configure:4471: checking for $ac_func" >&5
diff -ruN ssh-1.2.26-clean/configure.in ssh-1.2.26/configure.in
--- ssh-1.2.26-clean/configure.in	Thu Jul  9 04:41:10 1998
+++ configure.in	Mon Nov  2 14:20:42 1998
@@ -438,7 +438,7 @@
 AC_CHECK_FUNCS(gettimeofday times getrusage ftruncate revoke makeutx)
 AC_CHECK_FUNCS(strchr memcpy setlogin openpty _getpty clock fchmod ulimit)
 AC_CHECK_FUNCS(gethostname getdtablesize umask innetgr initgroups setpgrp)
-AC_CHECK_FUNCS(setpgid daemon waitpid ttyslot authenticate)
+AC_CHECK_FUNCS(setpgid daemon waitpid ttyslot authenticate snprintf vsnprintf)
 
 AC_REPLACE_FUNCS(strerror memmove remove random putenv crypt socketpair)
 
diff -ruN ssh-1.2.26-clean/includes.h ssh-1.2.26/includes.h
--- ssh-1.2.26-clean/includes.h	Thu Jul  9 04:40:36 1998
+++ includes.h	Mon Nov  2 14:21:04 1998
@@ -306,6 +306,10 @@
 #include <paths.h>
 #endif
 
+#if (!defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF))
+#include "snprintf.h"
+#endif
+
 #if HAVE_DIRENT_H
 #include <dirent.h>
 #define NAMLEN(dirent) strlen((dirent)->d_name)
diff -ruN ssh-1.2.26-clean/log-server.c ssh-1.2.26/log-server.c
--- ssh-1.2.26-clean/log-server.c	Thu Jul  9 04:40:36 1998
+++ log-server.c	Mon Nov  2 14:20:42 1998
@@ -134,7 +134,7 @@
   if (log_quiet)
     return;
   va_start(args, fmt);
-  vsprintf(buf, fmt, args);
+  vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);
   if (log_on_stderr)
     fprintf(stderr, "log: %s\n", buf);
@@ -175,7 +175,7 @@
   if (log_quiet)
     return;
   va_start(args, fmt);
-  vsprintf(buf, fmt, args);
+  vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);
   if (log_on_stderr)
     fprintf(stderr, "log: %s\n", buf);
@@ -191,7 +191,7 @@
   if (!log_debug || log_quiet)
     return;
   va_start(args, fmt);
-  vsprintf(buf, fmt, args);
+  vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);
   if (log_on_stderr)
     fprintf(stderr, "debug: %s\n", buf);
@@ -207,7 +207,7 @@
   if (log_quiet)
     return;
   va_start(args, fmt);
-  vsprintf(buf, fmt, args);
+  vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);
   if (log_on_stderr)
     fprintf(stderr, "error: %s\n", buf);
@@ -302,7 +302,7 @@
   if (log_quiet)
     exit(1);
   va_start(args, fmt);
-  vsprintf(buf, fmt, args);
+  vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);
   if (log_on_stderr)
     fprintf(stderr, "fatal: %s\n", buf);
@@ -321,7 +321,7 @@
   if (log_quiet)
     exit(1);
   va_start(args, fmt);
-  vsprintf(buf, fmt, args);
+  vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);
   if (log_on_stderr)
     fprintf(stderr, "fatal: %s\n", buf);
diff -ruN ssh-1.2.26-clean/packet.c ssh-1.2.26/packet.c
--- ssh-1.2.26-clean/packet.c	Thu Jul  9 04:40:37 1998
+++ packet.c	Mon Nov  2 14:20:42 1998
@@ -693,7 +693,7 @@
   va_list args;
   
   va_start(args, fmt);
-  vsprintf(buf, fmt, args);
+  vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);
   
   packet_start(SSH_MSG_DEBUG);
@@ -719,7 +719,7 @@
   /* Format the message.  Note that the caller must make sure the message
      is of limited size. */
   va_start(args, fmt);
-  vsprintf(buf, fmt, args);
+  vsnprintf(buf, sizeof(buf), fmt, args);
   va_end(args);
 
   /* Send the disconnect message to the other side, and wait for it to get 
diff -ruN ssh-1.2.26-clean/scp.c ssh-1.2.26/scp.c
--- ssh-1.2.26-clean/scp.c	Thu Jul  9 04:40:38 1998
+++ scp.c	Mon Nov  2 14:20:42 1998
@@ -332,7 +332,7 @@
   char buf[1024];
 
   va_start(ap, fmt);
-  vsprintf(buf, fmt, ap);
+  vsnprintf(buf, sizeof(buf), fmt, ap);
   va_end(ap);
   fprintf(stderr, "%s\n", buf);
   exit(255);
diff -ruN ssh-1.2.26-clean/snprintf.c ssh-1.2.26/snprintf.c
--- ssh-1.2.26-clean/snprintf.c	Thu Jan  1 12:00:00 1970
+++ snprintf.c	Mon Nov  2 14:20:42 1998
@@ -0,0 +1,566 @@
+/*
+
+  Author: Tomi Salo <ttsalo@ssh.fi>
+
+  Copyright (C) 1996 SSH Communications Security Oy, Espoo, Finland
+  All rights reserved.
+
+  Implementation of functions snprintf() and vsnprintf()
+
+  */
+
+/*
+ * $Id: snprintf.c,v 1.19 1998/06/03 00:45:30 ylo Exp $
+ * $Log: snprintf.c,v $
+ * $EndLog$
+ */
+
+#include "includes.h"
+#include "snprintf.h"
+#include "xmalloc.h"
+
+#define MINUS_FLAG 0x1
+#define PLUS_FLAG 0x2
+#define SPACE_FLAG 0x4
+#define HASH_FLAG 0x8
+#define CONV_TO_SHORT 0x10
+#define IS_LONG_INT 0x20
+#define IS_LONG_DOUBLE 0x40
+#define X_UPCASE 0x80
+#define IS_NEGATIVE 0x100
+#define UNSIGNED_DEC 0x200
+#define ZERO_PADDING 0x400
+
+#undef sprintf
+
+/* Extract a formatting directive from str. Str must point to a '%'. 
+   Returns number of characters used or zero if extraction failed. */
+
+int
+snprintf_get_directive(const char *str, int *flags, int *width,
+		       int *precision, char *format_char, va_list *ap)
+{
+  int length, n;
+  const char *orig_str = str;
+
+  *flags = 0; 
+  *width = 0;
+  *precision = 0;
+  *format_char = (char)0;
+
+  if (*str == '%')
+    {
+      /* Get the flags */
+      str++;
+      while (*str == '-' || *str == '+' || *str == ' ' 
+	     || *str == '#' || *str == '0')
+	{
+	  switch (*str)
+	    {
+	    case '-':
+	      *flags |= MINUS_FLAG;
+	      break;
+	    case '+':
+	      *flags |= PLUS_FLAG;
+	      break;
+	    case ' ':
+	      *flags |= SPACE_FLAG;
+	      break;
+	    case '#':
+	      *flags |= HASH_FLAG;
+	      break;
+	    case '0':
+	      *flags |= ZERO_PADDING;
+	      break;
+	    }
+	  str++;
+	}
+
+      /* Don't pad left-justified numbers withs zeros */
+      if ((*flags & MINUS_FLAG) && (*flags & ZERO_PADDING))
+	*flags &= ~ZERO_PADDING;
+      
+      /* Is width field present? */
+      if (isdigit(*str))
+	{
+	  n = sscanf(str, "%d", width);
+	  if (n == 0)
+	    return 0;
+
+	  /* Step through the field */
+	  while (isdigit(*str))
+	    str++;
+	}
+      else
+	if (*str == '*')
+	  {
+	    *width = va_arg(*ap, int);
+	    str++;
+	  }
+
+      /* Is the precision field present? */
+      if (*str == '.')
+	{
+	  str++;
+	  if (isdigit(*str))
+	    {
+	      n = sscanf(str, "%d", precision);
+	      if (n == 0)
+		return 0;
+	  
+	      /* Step through the field */
+	      while (isdigit(*str))
+		str++;
+	    }
+	  else
+	    if (*str == '*')
+	      {
+		*precision = va_arg(*ap, int);
+		str++;
+	      }
+	    else
+	      *precision = 0;
+	}
+
+      /* Get the optional type character */
+      if (*str == 'h')
+	{
+	  *flags |= CONV_TO_SHORT;
+	  str++;
+	}
+      else
+	{
+	  if (*str == 'l')
+	    {
+	      *flags |= IS_LONG_INT;
+	      str++;
+	    }
+	  else
+	    {
+	      if (*str == 'L')
+		{
+		  *flags |= IS_LONG_DOUBLE;
+		  str++;
+		}
+	    }
+	}
+
+      /* Get and check the formatting character */
+
+      *format_char = *str;
+      str++;
+      length = str - orig_str;
+
+      switch (*format_char)
+	{
+	case 'i': case 'd': case 'o': case 'u': case 'x': case 'X': 
+	case 'f': case 'e': case 'E': case 'g': case 'G': 
+	case 'c': case 's': case 'p': case 'n':
+	  if (*format_char == 'X')
+	    *flags |= X_UPCASE;
+	  if (*format_char == 'o')
+	    *flags |= UNSIGNED_DEC;
+	  return length;
+
+	default:
+	  return 0;
+	}
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+/* Convert a integer from unsigned long int representation 
+   to string representation. This will insert prefixes if needed 
+   (leading zero for octal and 0x or 0X for hexadecimal) and
+   will write at most buf_size characters to buffer.
+   tmp_buf is used because we want to get correctly truncated
+   results.
+   */
+
+int
+snprintf_convert_ulong(char *buffer, size_t buf_size, int base, char *digits,
+		       unsigned long int ulong_val, int flags, int width,
+		       int precision)
+{
+  int tmp_buf_len = 100 + width, len;
+  char *tmp_buf, *tmp_buf_ptr, prefix[2];
+  tmp_buf = xmalloc(tmp_buf_len);
+
+  prefix[0] = '\0';
+  prefix[1] = '\0';
+  
+  /* Make tmp_buf_ptr point just past the last char of buffer */
+  tmp_buf_ptr = tmp_buf + tmp_buf_len;
+
+  /* Main conversion loop */
+  do 
+    {
+      *--tmp_buf_ptr = digits[ulong_val % base];
+      ulong_val /= base;
+      precision--;
+    } 
+  while ((ulong_val != 0 || precision > 0) && tmp_buf_ptr > tmp_buf);
+ 
+  /* Get the prefix */
+  if (!(flags & IS_NEGATIVE))
+    {
+      if (base == 16 && (flags & HASH_FLAG))
+	  if (flags && X_UPCASE)
+	    {
+	      prefix[0] = 'x';
+	      prefix[1] = '0';
+	    }
+	  else
+	    {
+	      prefix[0] = 'X';
+	      prefix[1] = '0';
+	    }
+      
+      if (base == 8 && (flags & HASH_FLAG))
+	  prefix[0] = '0';
+      
+      if (base == 10 && !(flags & UNSIGNED_DEC) && (flags & PLUS_FLAG))
+	  prefix[0] = '+';
+      else
+	if (base == 10 && !(flags & UNSIGNED_DEC) && (flags & SPACE_FLAG))
+	  prefix[0] = ' ';
+    }
+  else
+      prefix[0] = '-';
+
+  if (prefix[0] != '\0' && tmp_buf_ptr > tmp_buf)
+    {
+      *--tmp_buf_ptr = prefix[0];
+      if (prefix[1] != '\0' && tmp_buf_ptr > tmp_buf)
+	*--tmp_buf_ptr = prefix[1];
+    }
+  
+  len = (tmp_buf + tmp_buf_len) - tmp_buf_ptr;
+
+  if (len <= buf_size)
+    {
+      if (len < width)
+	{
+	  if (width > (tmp_buf_ptr - tmp_buf))
+	    width = (tmp_buf_ptr - tmp_buf);
+	  if (flags & MINUS_FLAG)
+	    {
+	      memcpy(buffer, tmp_buf_ptr, len);
+	      memset(buffer + len, (flags & ZERO_PADDING)?'0':' ',
+		     width - len);
+	      len = width;
+	    }
+	  else
+	    {
+	      memset(buffer, (flags & ZERO_PADDING)?'0':' ',
+		     width - len);
+	      memcpy(buffer + width - len, tmp_buf_ptr, len);
+	      len = width;
+	    }
+	}
+      else
+	{
+	  memcpy(buffer, tmp_buf_ptr, len);
+	}
+      xfree(tmp_buf);
+      return len;
+    }
+  else
+    {
+      memcpy(buffer, tmp_buf_ptr, buf_size);
+      xfree(tmp_buf);
+      return buf_size;
+    }
+}
+
+int
+snprintf_convert_float(char *buffer, size_t buf_size,
+		       double dbl_val, int flags, int width,
+		       int precision, char format_char)
+{
+  char print_buf[160], print_buf_len = 0;
+  char format_str[80], *format_str_ptr;
+
+  format_str_ptr = format_str;
+
+  if (width > 155) width = 155;
+  if (precision <= 0)
+    precision = 6;
+  if (precision > 120)
+    precision = 120;
+
+  /* Construct the formatting string and let system's sprintf
+     do the real work. */
+  
+  *format_str_ptr++ = '%';
+
+  if (flags & MINUS_FLAG)
+    *format_str_ptr++ = '-';
+  if (flags & PLUS_FLAG)
+    *format_str_ptr++ = '+';
+  if (flags & SPACE_FLAG)
+    *format_str_ptr++ = ' ';
+  if (flags & ZERO_PADDING)
+    *format_str_ptr++ = '0';
+  if (flags & HASH_FLAG)
+    *format_str_ptr++ = '#';
+    
+  format_str_ptr += sprintf(format_str_ptr, "%d.%d", width, precision);
+  if (flags & IS_LONG_DOUBLE)
+    *format_str_ptr++ = 'L';
+  *format_str_ptr++ = format_char;
+  *format_str_ptr++ = '\0';
+
+  print_buf_len = sprintf(print_buf, format_str, dbl_val);
+
+  if (print_buf_len > buf_size) print_buf_len = buf_size;
+  strncpy(buffer, print_buf, print_buf_len);
+  return print_buf_len;
+}
+
+#ifndef HAVE_SNPRINTF
+
+int
+snprintf(char *str, size_t size, const char *format, ...)
+{
+  int ret;
+  va_list ap;
+  va_start(ap, format);
+  ret = vsnprintf(str, size, format, ap);
+  va_end(ap);
+
+  return ret;
+}
+#endif	/* !HAVE_SNPRINTF */
+
+#ifndef HAVE_VSNPRINTF
+
+int
+vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+  int status, left = (int)size - 1;
+  const char *format_ptr = format;
+  int flags, width, precision, i;
+  char format_char, *orig_str = str;
+  int *int_ptr;
+  long int long_val;
+  unsigned long int ulong_val;
+  char *str_val;
+  double dbl_val;
+
+  flags = 0;
+  while (format_ptr < format + strlen(format))
+    {
+      if (*format_ptr == '%')
+	{
+	  if (format_ptr[1] == '%' && left > 0)
+	    {
+	      *str++ = '%';
+	      left--;
+	      format_ptr += 2;
+	    }
+	  else
+	    {
+	      if (left <= 0)
+		{
+		  *str = '\0';
+		  return size;
+		}
+	      else
+		{
+		  status = snprintf_get_directive(format_ptr, &flags, &width,
+						  &precision, &format_char, 
+						  &ap);
+		  if (status == 0)
+		    {
+		      *str = '\0';
+		      return 0;
+		    }
+		  else
+		    {
+		      format_ptr += status;
+		      /* Print a formatted argument */
+		      switch (format_char)
+			{
+			case 'i': case 'd':
+			  /* Convert to unsigned long int before
+			     actual conversion to string */
+			  if (flags & IS_LONG_INT)
+			    long_val = va_arg(ap, long int);
+			  else
+			    long_val = (long int) va_arg(ap, int);
+			  
+			  if (long_val < 0)
+			    {
+			      ulong_val = (unsigned long int) -long_val;
+			      flags |= IS_NEGATIVE;
+			    }
+			  else
+			    {
+			      ulong_val = (unsigned long int) long_val;
+			    }
+			  status = snprintf_convert_ulong(str, left, 10,
+							  "0123456789",
+							  ulong_val, flags,
+							  width, precision);
+			  str += status;
+			  left -= status;
+			  break;
+
+			case 'x':
+			  if (flags & IS_LONG_INT)
+			    ulong_val = va_arg(ap, unsigned long int);
+			  else
+			    ulong_val = 
+			      (unsigned long int) va_arg(ap, unsigned int);
+
+			  status = snprintf_convert_ulong(str, left, 16,
+							  "0123456789abcdef",
+							  ulong_val, flags,
+							  width, precision);
+			  str += status;
+			  left -= status;
+			  break;
+
+			case 'X':
+			  if (flags & IS_LONG_INT)
+			    ulong_val = va_arg(ap, unsigned long int);
+			  else
+			    ulong_val = 
+			      (unsigned long int) va_arg(ap, unsigned int);
+
+			  status = snprintf_convert_ulong(str, left, 16,
+							  "0123456789ABCDEF",
+							  ulong_val, flags,
+							  width, precision);
+			  str += status;
+			  left -= status;
+			  break;
+
+			case 'o':
+			  if (flags & IS_LONG_INT)
+			    ulong_val = va_arg(ap, unsigned long int);
+			  else
+			    ulong_val = 
+			      (unsigned long int) va_arg(ap, unsigned int);
+
+			  status = snprintf_convert_ulong(str, left, 8,
+							  "01234567",
+							  ulong_val, flags,
+							  width, precision);
+			  str += status;
+			  left -= status;
+			  break;
+
+			case 'u':
+			  if (flags & IS_LONG_INT)
+			    ulong_val = va_arg(ap, unsigned long int);
+			  else
+			    ulong_val = 
+			      (unsigned long int) va_arg(ap, unsigned int);
+
+			  status = snprintf_convert_ulong(str, left, 10,
+							  "0123456789",
+							  ulong_val, flags,
+							  width, precision);
+			  str += status;
+			  left -= status;
+			  break;
+
+			case 'p':
+			  break;
+			  
+			case 'c':
+			  if (flags & IS_LONG_INT)
+			    ulong_val = va_arg(ap, unsigned long int);
+			  else
+			    ulong_val = 
+			      (unsigned long int) va_arg(ap, unsigned int);
+			  *str++ = (unsigned char)ulong_val;
+			  left--;
+			  break;
+
+			case 's':
+			  str_val = va_arg(ap, char *);
+
+			  if (str_val == NULL)
+			    str_val = "(null)";
+			  
+			  if (precision == 0)
+			    precision = strlen(str_val);
+			  else
+			    {
+			      if (memchr(str_val, 0, precision) != NULL)
+				precision = strlen(str_val);
+			    }
+			  if (precision > left)
+			    precision = left;
+
+			  if (width > left)
+			    width = left;
+			  if (width < precision)
+			    width = precision;
+			  i = width - precision;
+
+			  if (flags & MINUS_FLAG)
+			    {
+			      strncpy(str, str_val, precision);
+			      memset(str + precision,
+				     (flags & ZERO_PADDING)?'0':' ', i);
+			    }
+			  else
+			    {
+			      memset(str, (flags & ZERO_PADDING)?'0':' ', i);
+			      strncpy(str + i, str_val, precision);
+			    }
+			  str += width;
+			  left -= width;
+			  break;
+
+			case 'n':
+			  int_ptr = va_arg(ap, int *);
+			  *int_ptr = str - orig_str;
+			  break;
+
+			case 'f': case 'e': case 'E': case 'g': case 'G':
+			  if (flags & IS_LONG_DOUBLE)
+			    dbl_val = (double) va_arg(ap, long double);
+			  else
+			    dbl_val = va_arg(ap, double);
+			  status =
+			    snprintf_convert_float(str, left, dbl_val, flags,
+						   width, precision,
+						   format_char);
+			  str += status;
+			  left -= status;
+			  break;
+			  
+			default:
+			  break;
+			}
+		    }
+		}
+	    }
+	}
+      else
+	{
+	  if (left > 0)
+	    {
+	      *str++ = *format_ptr++;
+	      left--;
+	    }
+	  else
+	    {
+	      *str = '\0';
+	      return size;
+	    }
+	}
+    }
+  *str = '\0';
+  return size - left - 1;
+}
+
+#endif	/* !HAVE_VSNPRINTF */
diff -ruN ssh-1.2.26-clean/snprintf.h ssh-1.2.26/snprintf.h
--- ssh-1.2.26-clean/snprintf.h	Thu Jan  1 12:00:00 1970
+++ snprintf.h	Mon Nov  2 14:20:42 1998
@@ -0,0 +1,52 @@
+/*
+
+  Author: Tomi Salo <ttsalo@ssh.fi>
+
+  Copyright (C) 1996 SSH Communications Security Oy, Espoo, Finland
+  All rights reserved.
+
+  Header file for snprintf.c
+
+  */
+
+/*
+ * $Id:
+ * $Log: snprintf.h,v $
+ * $EndLog$
+ */
+
+#ifndef SNPRINTF_H
+#define SNPRINTF_H
+
+#include "includes.h"
+
+/* Write formatted text to buffer 'str', using format string 'format'.
+   Returns number of characters written, or negative if error
+   occurred. SshBuffer's size is given in 'size'. Format string is
+   understood as defined in ANSI C.
+
+   NOTE: This does NOT work identically with BDS's snprintf.
+
+   Integers: Ansi C says that precision specifies the minimun
+   number of digits to print. BSD's version however counts the
+   prefixes (+, -, ' ', '0x', '0X', octal prefix '0'...) as
+   'digits'.
+
+   Also, BSD implementation does not permit padding integers
+   to specified width with zeros on left (in front of the prefixes),
+   it uses spaces instead, even when Ansi C only forbids padding
+   with zeros on the right side of numbers.
+   
+   */
+
+#ifndef HAVE_SNPRINTF
+int
+snprintf(char *str, size_t size, const char *format, ...);
+#endif
+
+#ifndef HAVE_VSNPRINTF
+int
+vsnprintf(char *str, size_t size, const char *format, va_list ap);
+#endif
+
+#endif /* SNPRINTF_H */
diff -ruN ssh-1.2.26-clean/version.h ssh-1.2.26/version.h
--- ssh-1.2.26-clean/version.h	Thu Jul  9 04:40:39 1998
+++ version.h	Mon Nov  2 14:20:42 1998
@@ -1 +1 @@
-#define SSH_VERSION	"1.2.26"
+#define SSH_VERSION	"1.2.26-vsnprintf-patched"
>Audit-Trail:
>Unformatted: