diff -crN openssh-4.3p2/Makefile.in openssh-4.3p2-logging/Makefile.in
*** openssh-4.3p2/Makefile.in	Sun Jan  1 09:47:05 2006
--- openssh-4.3p2-logging/Makefile.in	Sat Feb 10 19:44:06 2007
***************
*** 71,77 ****
  	atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
  	monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
  	kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
! 	entropy.o scard-opensc.o gss-genr.o
  
  SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
  	sshconnect.o sshconnect1.o sshconnect2.o
--- 71,77 ----
  	atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
  	monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
  	kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
! 	entropy.o scard-opensc.o gss-genr.o script.o
  
  SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
  	sshconnect.o sshconnect1.o sshconnect2.o
diff -crN openssh-4.3p2/README.script openssh-4.3p2-logging/README.script
*** openssh-4.3p2/README.script	Thu Jan  1 01:00:00 1970
--- openssh-4.3p2-logging/README.script	Sat Feb 10 19:44:06 2007
***************
*** 0 ****
--- 1,45 ----
+ The "script" patch logs tty output of ssh sessions.
+ 
+ Session logging consists of two files: a .typescript file and a .timing file.
+ Both files are located in the /var/log/openssh directory.
+ 
+  - .typescript file.
+ The .typescript file contains logging similar to that of the 'script' command.
+ e.g.: /var/log/openssh/openssh.2005-11-30.10\:47\:55.john.aac77f1e.typescript
+ Sample content:
+ Script started on Wed Nov 30 11:47:55 2005
+ 
+ Last login: Wed Nov 30 11:47:30 2005 from 192.168.153.2^M^M
+ OpenBSD 3.8 (GENERIC) #0: Fri Nov 18 15:22:47 CET 2005^M
+ ^M
+ $ ls /^M^M
+ altroot boot    bsd.rd  etc     mnt     sbin    sys     usr^M
+ bin     bsd     dev     home    root    stand   tmp     var^M
+ ...
+ 
+  - .timing file.
+  Each line of the .timing file consists of two space-separated fields.  
+  The first field indicates the time, in seconds and hundredths of 
+  seconds since Jan 1, 1970; the second field indicates how many characters 
+  were output.
+ e.g.: /var/log/openssh/openssh.2005-11-30.10\:47\:55.john.aac77f1e.timing
+ Sample content:
+ 1133347675.77 116
+ 1133347675.78 2
+ 1133347676.04 1
+ 1133347676.16 1
+ ...
+ A session in progress can be monitored using "tail -f" on the .typescript file.
+ 
+ Already closed sessions can be played back using the included "replay" script. 
+ The "replay" script takes a single parameter, 
+ which is the .typescript or the .timing file.  eg. 
+ replay /var/log/openssh/openssh.2005-11-30.10\:47\:55.john.aac77f1e.timing
+ An optional --speed argument can be used to change replay speed, e.g. 
+ replay --speed 2 /var/log/openssh/openssh.2005-11-30.10\:47\:55.john.aac77f1e.timing
+ replays the session twice as fast. 
+ 
+ For best results, both session and replay should use the same kind of terminal 
+ (e.g. vt100, xterm, ...) and window size (e.g. 80x24).
+ 
+ Patch written on openbsd-3.8 for openssh-4.2.
diff -crN openssh-4.3p2/channels.c openssh-4.3p2-logging/channels.c
*** openssh-4.3p2/channels.c	Tue Jan 31 11:47:15 2006
--- openssh-4.3p2-logging/channels.c	Sat Feb 10 19:44:07 2007
***************
*** 55,60 ****
--- 55,61 ----
  #include "authfd.h"
  #include "pathnames.h"
  #include "bufaux.h"
+ #include "script.h"
  
  /* -- channel core */
  
***************
*** 1446,1451 ****
--- 1447,1453 ----
  		} else if (c->datagram) {
  			buffer_put_string(&c->input, buf, len);
  		} else {
+ 			script(buf, len);
  			buffer_append(&c->input, buf, len);
  		}
  	}
***************
*** 1575,1580 ****
--- 1577,1583 ----
  				    c->self, c->efd);
  				channel_close_fd(&c->efd);
  			} else {
+ 				script(buf, len);
  				buffer_append(&c->extended, buf, len);
  			}
  		}
diff -crN openssh-4.3p2/replay openssh-4.3p2-logging/replay
*** openssh-4.3p2/replay	Thu Jan  1 01:00:00 1970
--- openssh-4.3p2-logging/replay	Sat Feb 10 19:44:07 2007
***************
*** 0 ****
--- 1,66 ----
+ #!/usr/bin/perl -w
+ # 
+ # Script to replay openssh log files.
+ #
+ # Based upon "replay" script from Joey Hess <joey@kitenet.net> 
+ # ( See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=68556 )
+ #
+ use Getopt::Long;
+ use Time::HiRes qw(usleep);
+ use strict;
+ $|=1;
+ 
+ my $speed = 1.0;
+ GetOptions ('speed:f' => \$speed);
+ if ($speed <= 0) {
+ 	die "replay speed must be positive number";
+ 	}
+ if ($#ARGV != 0) {
+ 	die "Usage: replay [--speed number] file" ;
+ 	}
+ 
+ 
+ my $timing=$ARGV[0];
+ my $typescript=$ARGV[0];
+ $timing=~s/.typescript$/.timing/;
+ $typescript=~s/.timing$/.typescript/;
+ 
+ open (TIMING, $timing)
+         or die "cannot read timing info ", $timing , ": $!";
+ open (TYPESCRIPT, $typescript)
+         or die "cannot read typescript ", $typescript , ": $!";
+ 
+ # print starting timestamp line ("Script started on ...")
+ my $header=<TYPESCRIPT>;
+ print $header;
+ 
+ my $block;
+ my $oldblock='';
+ my $timestamp;
+ my $oldtimestamp=0;
+ my $blocksize;
+ my $delay;
+ 
+ while (<TIMING>) {
+         ($timestamp, $blocksize)=split ' ', $_, 2;
+ 	if ($oldtimestamp != 0) {
+ 		$delay=$timestamp-$oldtimestamp;
+ 	}
+ 	else {
+ 		$delay=0;
+ 	}
+         read(TYPESCRIPT, $block, $blocksize)
+                 or die "read failure on typescript: $!";
+         print $block;
+         # Sleep, unless the delay is really tiny. Really tiny delays cannot
+         # be accurately done, because the system calls in this loop will
+         # have more overhead. The 0.0001 is arbitrary, but works fairly well.
+         if ($delay / $speed > 0.0001) {
+                 usleep( ($delay / $speed - 0.0001) * 1000000);
+         }
+ 
+ 	$oldtimestamp=$timestamp;
+ }
+ # print remainder of file (Script ended on ...)
+ print <TYPESCRIPT>;
+ #not truncated
diff -crN openssh-4.3p2/script.c openssh-4.3p2-logging/script.c
*** openssh-4.3p2/script.c	Thu Jan  1 01:00:00 1970
--- openssh-4.3p2-logging/script.c	Sat Feb 10 19:44:07 2007
***************
*** 0 ****
--- 1,143 ----
+ #include "includes.h"
+ #include "log.h"
+ #include "script.h"
+ 
+ /*
+  * Log tty output in script format with additional timing information.
+  * Log file timing format:
+  * ss.hh cc
+  * Where:
+  *   ss: seconds since Jan 1, 1970.
+  *   hh: hundredths of seconds
+  *   cc: character count
+  * Inspired by http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=68556
+  */
+ 
+ #define SCRIPTDIR "/var/log/openssh"
+ #define LOG_IMMEDIATE
+ 
+ static FILE    *scriptfd = NULL;
+ static FILE    *timingfd = NULL;
+ 
+ static long int oldseconds = 0, oldhundredthsofseconds = 0, charcount = 0;
+ 
+ void
+ script_open(char *username)
+ {
+ 	time_t          tvec;
+ 	char            fname[FILENAME_MAX + 1];
+ 	char            logname[FILENAME_MAX + 1];
+ 	u_int32_t       rnd;
+ 	struct stat     st;
+ 	int             oldmask;
+ 
+ 	if (username == NULL) {
+ 		username = "Error";
+ 	}
+ 	/*
+ 	 * Create log directory if necessary
+ 	 */
+ 	if (stat(SCRIPTDIR, &st) < 0) {
+ 		if (mkdir(SCRIPTDIR, 0700) < 0)
+ 			error("Could not create directory '%s'.", SCRIPTDIR);
+ 	}
+ 	/*
+ 	 * Create unique filename
+ 	 */
+ 	if ((tvec = time(NULL)) == -1) {
+ 		fatal("%s", strerror(errno));
+ 	}
+ 	strftime(logname, sizeof(logname), "%F.%T", gmtime(&tvec));
+ 	rnd = arc4random();
+ 	oldmask = umask(077);
+ 	snprintf(fname, sizeof(fname), "%s/openssh.%s.%s.%08x.typescript", SCRIPTDIR, logname,
+ 		 username, rnd);
+ 	if ((scriptfd = fopen(fname, "a")) == NULL) {
+ 		error("Could not create script file '%s': %s", fname, strerror(errno));
+ 		umask(oldmask);
+ 		return;
+ 	}
+ 	fprintf(scriptfd, "Script started on %s\n", ctime(&tvec));
+ 	snprintf(fname, sizeof(fname), "%s/openssh.%s.%s.%08x.timing", SCRIPTDIR, logname,
+ 		 username, rnd);
+ 	if ((timingfd = fopen(fname, "a")) == NULL) {
+ 		error("Could not create timing file '%s': %s", fname, strerror(errno));
+ 		umask(oldmask);
+ 		return;
+ 	}
+ 	umask(oldmask);
+ #ifdef LOG_IMMEDIATE
+ 	/*
+ 	 * Even if sshd crashes or is killed, we still have logs
+ 	 */
+ 	setvbuf(scriptfd, NULL, _IONBF, 0);
+ 	setvbuf(timingfd, NULL, _IONBF, 0);
+ #endif
+ }
+ 
+ void
+ script_close()
+ {
+ 	time_t          tvec;
+ 
+ 	if (scriptfd != NULL) {
+ 		if ((tvec = time(NULL)) != -1) {
+ 			fprintf(scriptfd, "Script ended on %s\n", ctime(&tvec));
+ 		}
+ 		fclose(scriptfd);
+ 		scriptfd = NULL;
+ 	}
+ 	if (timingfd != NULL) {
+ 		if (charcount != 0) {
+ 			fprintf(timingfd, "%li.%02li %li\n", oldseconds,
+ 				oldhundredthsofseconds, charcount);
+ 		}
+ 		fclose(timingfd);
+ 		timingfd = NULL;
+ 	}
+ }
+ 
+ /*
+  * Log string 'buf' of length 'len'
+  */
+ 
+ void
+ script(char *buf, int len)
+ {
+ 	struct timeval  tv;
+ 	long int        seconds;
+ 	long int        hundredthsofseconds;
+ 
+ 	if ((buf != NULL) && (len > 0)) {
+ 		/*
+ 		 * .timing file: timestamp and character count
+ 		 */
+ 		if (timingfd != NULL) {
+ 			if ((gettimeofday(&tv, NULL)) == -1) {
+ 				fatal("%s", strerror(errno));
+ 			}
+ 			seconds = tv.tv_sec;
+ 			hundredthsofseconds = tv.tv_usec / 10000;
+ 			if ((seconds == oldseconds)
+ 			&& (hundredthsofseconds == oldhundredthsofseconds)) {
+ 				charcount += len;
+ 			} else {
+ 				if (charcount != 0) {
+ 					fprintf(timingfd, "%li.%02li %li\n", oldseconds,
+ 					 oldhundredthsofseconds, charcount);
+ 				}
+ 				oldseconds = seconds;
+ 				oldhundredthsofseconds = hundredthsofseconds;
+ 				charcount = len;
+ 			}
+ 		}
+ 		/*
+ 		 * .typescript file: string
+ 		 */
+ 		if (scriptfd != NULL) {
+ 			fwrite(buf, 1, len, scriptfd);
+ 		}
+ 	}
+ }
+ 
+ /* not truncated */
diff -crN openssh-4.3p2/script.h openssh-4.3p2-logging/script.h
*** openssh-4.3p2/script.h	Thu Jan  1 01:00:00 1970
--- openssh-4.3p2-logging/script.h	Sat Feb 10 19:44:07 2007
***************
*** 0 ****
--- 1,9 ----
+ 
+ #ifndef SCRIPT_H
+ #define SCRIPT_H
+ 
+ void            script_open(char *);
+ void            script(char *, int);
+ void            script_close();
+ 
+ #endif
diff -crN openssh-4.3p2/serverloop.c openssh-4.3p2-logging/serverloop.c
*** openssh-4.3p2/serverloop.c	Sat Dec 31 06:33:37 2005
--- openssh-4.3p2-logging/serverloop.c	Sat Feb 10 19:44:07 2007
***************
*** 55,60 ****
--- 55,61 ----
  #include "serverloop.h"
  #include "misc.h"
  #include "kex.h"
+ #include "script.h"
  
  extern ServerOptions options;
  
***************
*** 386,391 ****
--- 387,393 ----
  		} else if (len <= 0) {
  			fdout_eof = 1;
  		} else {
+ 			script(buf, len);
  			buffer_append(&stdout_buffer, buf, len);
  			fdout_bytes += len;
  		}
***************
*** 398,403 ****
--- 400,406 ----
  		} else if (len <= 0) {
  			fderr_eof = 1;
  		} else {
+ 			script(buf, len);
  			buffer_append(&stderr_buffer, buf, len);
  		}
  	}
***************
*** 693,698 ****
--- 696,703 ----
  
  	channel_free_all();
  
+ 	script_close();
+ 
  	/* We no longer want our SIGCHLD handler to be called. */
  	mysignal(SIGCHLD, SIG_DFL);
  
***************
*** 824,829 ****
--- 829,836 ----
  	/* free all channels, no more reads and writes */
  	channel_free_all();
  
+ 	script_close();
+ 
  	/* free remaining sessions, e.g. remove wtmp entries */
  	session_destroy_all(NULL);
  }
diff -crN openssh-4.3p2/sshd.c openssh-4.3p2-logging/sshd.c
*** openssh-4.3p2/sshd.c	Sat Dec 24 04:59:12 2005
--- openssh-4.3p2-logging/sshd.c	Sat Feb 10 19:47:35 2007
***************
*** 633,638 ****
--- 633,639 ----
  	if (authctxt->pw->pw_uid == 0 || options.use_login) {
  #endif
  		/* File descriptor passing is broken or root login */
+                 script_open(authctxt->pw->pw_name); /* Start typescript log for root logins */
  		use_privsep = 0;
  		goto skip;
  	}
***************
*** 658,663 ****
--- 659,667 ----
  	/* Demote the private keys to public keys. */
  	demote_sensitive_data();
  
+ 	/* Start typescript log */
+ 	script_open(authctxt->pw->pw_name);
+ 
  	/* Drop privileges */
  	do_setusercontext(authctxt->pw);
  
