Index: log.c
===================================================================
RCS file: /cvs/openssh/log.c,v
retrieving revision 1.52
diff -u -r1.52 log.c
--- log.c	20 Aug 2006 07:55:55 -0000	1.52
+++ log.c	5 Apr 2007 07:54:34 -0000
@@ -53,6 +53,7 @@
 
 static LogLevel log_level = SYSLOG_LEVEL_INFO;
 static int log_on_stderr = 1;
+static int log_persistent = 0;
 static int log_facility = LOG_AUTH;
 static char *argv0;
 
@@ -150,6 +151,17 @@
 	_exit(1);
 }
 
+/* Log this message (information that usually should go to the log). */
+
+void
+logfatal(const char *fmt,...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	do_log(SYSLOG_LEVEL_FATAL, fmt, args);
+	va_end(args);
+}
 
 /* Log this message (information that usually should go to the log). */
 
@@ -209,10 +221,15 @@
 
 /*
  * Initialize the log.
+ * 
+ * The persistent parameter has been added to avoid problems with
+ * chroot environments where it's necessary to hold open any file
+ * descriptors. Default operation is 0, but set to 1 if closelog()
+ * should be avoided.
  */
 
 void
-log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
+log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr, int persistent)
 {
 #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
 	struct syslog_data sdata = SYSLOG_DATA_INIT;
@@ -237,6 +254,7 @@
 		exit(1);
 	}
 
+        log_persistent = persistent;
 	log_on_stderr = on_stderr;
 	if (on_stderr)
 		return;
@@ -291,13 +309,21 @@
 	 * If an external library (eg libwrap) attempts to use syslog
 	 * immediately after reexec, syslog may be pointing to the wrong
 	 * facility, so we force an open/close of syslog here.
+	 *
+	 * Don't close syslog if permanent operation is required.
 	 */
 #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
 	openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
-	closelog_r(&sdata);
+	if (!log_persistent) {
+		closelog_r(&sdata);
+	}
+        
 #else
 	openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
-	closelog();
+	if (!log_persistent) {
+		closelog();
+	}
+        
 #endif
 }
 
@@ -364,13 +390,23 @@
 		write(STDERR_FILENO, msgbuf, strlen(msgbuf));
 	} else {
 #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
-		openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
+		if (!log_persistent) {
+			openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
+		}
 		syslog_r(pri, &sdata, "%.500s", fmtbuf);
-		closelog_r(&sdata);
+		if (!log_persistent) {
+			closelog_r(&sdata);
+		}
+                
 #else
-		openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
+		if (!log_persistent) {
+			openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
+		}
 		syslog(pri, "%.500s", fmtbuf);
-		closelog();
+		if (!log_persistent) {
+			closelog();
+		}
+                
 #endif
 	}
 }
Index: log.h
===================================================================
RCS file: /cvs/openssh/log.h,v
retrieving revision 1.19
diff -u -r1.19 log.h
--- log.h	18 Aug 2006 14:32:21 -0000	1.19
+++ log.h	5 Apr 2007 07:54:34 -0000
@@ -46,7 +46,7 @@
 	SYSLOG_LEVEL_NOT_SET = -1
 }       LogLevel;
 
-void     log_init(char *, LogLevel, SyslogFacility, int);
+void     log_init(char *, LogLevel, SyslogFacility, int, int);
 
 SyslogFacility	log_facility_number(char *);
 LogLevel log_level_number(char *);
@@ -54,6 +54,7 @@
 void     fatal(const char *, ...) __dead __attribute__((format(printf, 1, 2)));
 void     error(const char *, ...) __attribute__((format(printf, 1, 2)));
 void     sigdie(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     logfatal(const char *, ...) __attribute__((format(printf, 1, 2)));
 void     logit(const char *, ...) __attribute__((format(printf, 1, 2)));
 void     verbose(const char *, ...) __attribute__((format(printf, 1, 2)));
 void     debug(const char *, ...) __attribute__((format(printf, 1, 2)));
Index: servconf.c
===================================================================
RCS file: /cvs/openssh/servconf.c,v
retrieving revision 1.162
diff -u -r1.162 servconf.c
--- servconf.c	21 Mar 2007 09:38:53 -0000	1.162
+++ servconf.c	5 Apr 2007 07:54:34 -0000
@@ -47,6 +47,42 @@
 extern int use_privsep;
 extern Buffer cfg;
 
+rtype_map_t rtypemap_global_req[] = {
+	{"tcpip-forward", RTYPE_GR_TCPIP_FORWARD},
+	{"cancel-tcpip-forward", RTYPE_GR_CANCEL_TCPIP_FORWARD},
+	{"direct-tcpip", RTYPE_GR_DIRECT_TCPIP},
+	{NULL, 0}
+};
+
+rtype_map_t rtypemap_channel_open[] = {
+	{"session", RTYPE_CO_SESSION},
+	{"x11", RTYPE_CO_X11},
+	{NULL, 0}
+};
+
+rtype_map_t rtypemap_channel_req[] = {
+	{"pty-req", RTYPE_CR_PTY_REQ},
+	{"x11-req", RTYPE_CR_X11_REQ},
+	{"env", RTYPE_CR_ENV},
+	{"shell", RTYPE_CR_SHELL},
+	{"exec", RTYPE_CR_EXEC},
+	{"subsystem", RTYPE_CR_SUBSYSTEM},
+	{NULL, 0}
+};
+
+int
+get_reqtype_channel_req(const rtype_map_t *map, const char *reqname)
+{
+/*	for (int i = 0; i < (sizeof(rtypemap_channel_req) / sizeof(rtype_map_t)); i++) {
+		if (!strcasecmp(reqname, map[i].name)) {
+			return map[i].type;
+		}
+	}*/
+	
+	/* none */
+	return 0;
+}
+
 /* Initializes the server options to their default values. */
 
 void
@@ -293,6 +329,7 @@
 	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
 	sMatch, sPermitOpen, sForceCommand,
 	sUsePrivilegeSeparation,
+	sGlobalReqDeny, sChannelDeny, sChannelReqDeny,
 	sDeprecated, sUnsupported
 } ServerOpCodes;
 
@@ -382,11 +419,14 @@
 	{ "denyusers", sDenyUsers, SSHCFG_GLOBAL },
 	{ "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
 	{ "denygroups", sDenyGroups, SSHCFG_GLOBAL },
+	{ "globalreqdeny", sGlobalReqDeny, SSHCFG_ALL },
+	{ "channeldeny", sChannelDeny, SSHCFG_ALL },
+	{ "channelreqdeny", sChannelReqDeny, SSHCFG_ALL },
 	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
 	{ "macs", sMacs, SSHCFG_GLOBAL },
 	{ "protocol", sProtocol, SSHCFG_GLOBAL },
 	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
-	{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
+	{ "subsystem", sSubsystem, SSHCFG_ALL },
 	{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
 	{ "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL },
 	{ "banner", sBanner, SSHCFG_ALL },
@@ -625,7 +665,7 @@
 	ServerOpCodes opcode;
 	u_short port;
 	u_int i, flags = 0;
-	size_t len;
+	size_t len, can_redefine = 0;
 
 	cp = line;
 	if ((arg = strdelim(&cp)) == NULL)
@@ -650,10 +690,12 @@
 			fatal("%s line %d: Directive '%s' is not allowed "
 			    "within a Match block", filename, linenum, arg);
 		} else { /* this is a directive we have already processed */
-			while (arg)
-				arg = strdelim(&cp);
+			while (strdelim(&cp));
 			return 0;
 		}
+		
+		/* Allow overriding of already set directives */
+		can_redefine = 1;
 	}
 
 	switch (opcode) {
@@ -1044,6 +1086,22 @@
 			options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
 		}
 		break;
+        
+        case sChannelReqDeny:
+		/* ChannelReqDeny <rtype> */
+		arg = strdelim(&cp);
+		if (!arg) {
+			fatal("%s line %d: Missing argument.", filename, linenum);
+		}
+		
+		i = get_reqtype_channel_req(rtypemap_channel_req, arg);
+/*		if (i == 0) {
+			fatal("%s line %d: unknown request type.", filename, linenum);
+		}*/
+		
+		options->channel_req_deny &= i;
+
+		break;
 
 	case sCiphers:
 		arg = strdelim(&cp);
@@ -1081,30 +1139,51 @@
 		break;
 
 	case sSubsystem:
-		if (options->num_subsystems >= MAX_SUBSYSTEMS) {
-			fatal("%s line %d: too many subsystems defined.",
-			    filename, linenum);
-		}
 		arg = strdelim(&cp);
 		if (!arg || *arg == '\0')
 			fatal("%s line %d: Missing subsystem name.",
 			    filename, linenum);
 		if (!*activep) {
+			debug("sSubsys syntax");
+			/* Check syntax only - usually when server starts */
 			arg = strdelim(&cp);
+			if (arg == NULL || *arg == '\0')
+				fatal("%s line %d: Missing subsystem command.",
+				      filename, linenum);
+			while (strdelim(&cp));
 			break;
 		}
-		for (i = 0; i < options->num_subsystems; i++)
-			if (strcmp(arg, options->subsystem_name[i]) == 0)
-				fatal("%s line %d: Subsystem '%s' already defined.",
-				    filename, linenum, arg);
-		options->subsystem_name[options->num_subsystems] = xstrdup(arg);
+		for (i = 0; i < options->num_subsystems; i++) {
+			if (strcmp(arg, options->subsystem_name[i]) == 0) {
+				if (can_redefine == 0) {
+					fatal("%s line %d: Subsystem '%s' already defined.",
+					      filename, linenum, arg);
+				}
+				
+				break;
+			}
+		}
+		if (i >= MAX_SUBSYSTEMS) {
+			fatal("%s line %d: too many subsystems defined.",
+			    filename, linenum);
+		} else if (i >= options->num_subsystems) {
+			/* Allocating new subsystem */
+			options->subsystem_name[i] = xstrdup(arg);
+		}
+		
 		arg = strdelim(&cp);
 		if (!arg || *arg == '\0')
 			fatal("%s line %d: Missing subsystem command.",
 			    filename, linenum);
-		options->subsystem_command[options->num_subsystems] = xstrdup(arg);
-
+		if (options->subsystem_command[i]) {
+			xfree(options->subsystem_command[i]);
+		}
+		options->subsystem_command[i] = xstrdup(arg);
+		
 		/* Collect arguments (separate to executable) */
+		if (options->subsystem_args[i]) {
+			xfree(options->subsystem_args[i]);
+		}
 		p = xstrdup(arg);
 		len = strlen(p) + 1;
 		while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
@@ -1113,8 +1192,9 @@
 			strlcat(p, " ", len);
 			strlcat(p, arg, len);
 		}
-		options->subsystem_args[options->num_subsystems] = p;
+		options->subsystem_args[i] = p;
 		options->num_subsystems++;
+		
 		break;
 
 	case sMaxStartups:
@@ -1329,7 +1409,7 @@
 	if (src->n != NULL) { \
 		if (dst->n != NULL) \
 			xfree(dst->n); \
-		dst->n = src->n; \
+		dst->n = xstrdup(src->n); \
 	} \
 } while(0)
 
@@ -1343,6 +1423,8 @@
 void
 copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
 {
+	size_t b = 0;
+	
 	M_CP_INTOPT(password_authentication);
 	M_CP_INTOPT(gss_authentication);
 	M_CP_INTOPT(rsa_authentication);
@@ -1358,6 +1440,44 @@
 	M_CP_INTOPT(x11_use_localhost);
 
 	M_CP_STROPT(banner);
+	if (src->channel_req_deny) {
+		dst->channel_req_deny = src->channel_req_deny;
+	}
+	
+	if (src->num_subsystems) {
+		for (size_t a = 0; a < src->num_subsystems; a++) {
+			/* Ensure that any entries already defined are
+			 * overwritten. This avoids the need to free
+			 * all entries, which might get rid of one of
+			 * the global options.
+			 */
+			for (b = 0; b < dst->num_subsystems; b++) {
+				if (strcmp(dst->subsystem_name[b], src->subsystem_name[a]) == 0) {
+					break;
+				}
+			}
+			if (b >= MAX_SUBSYSTEMS) {
+				/* TODO: figure out what to do here */
+				break;
+			}
+			
+			if (b >= dst->num_subsystems) {
+				if (dst->subsystem_name[b]) {
+					xfree(dst->subsystem_name[b]);
+				}
+				dst->subsystem_name[b] = xstrdup(src->subsystem_name[a]);
+			}
+			
+			xfree(dst->subsystem_command[b]);
+			xfree(dst->subsystem_args[b]);
+			dst->subsystem_command[b] = xstrdup(src->subsystem_command[a]);
+			dst->subsystem_args[b] = xstrdup(src->subsystem_args[a]);
+			
+			if (b >= dst->num_subsystems) {
+				dst->num_subsystems++;
+			}
+		}
+	}
 	if (preauth)
 		return;
 	M_CP_STROPT(adm_forced_command);
Index: servconf.h
===================================================================
RCS file: /cvs/openssh/servconf.h,v
retrieving revision 1.72
diff -u -r1.72 servconf.h
--- servconf.h	19 Feb 2007 11:25:38 -0000	1.72
+++ servconf.h	5 Apr 2007 07:54:35 -0000
@@ -36,6 +36,29 @@
 
 #define DEFAULT_AUTH_FAIL_MAX	6	/* Default for MaxAuthTries */
 
+#define	RTYPE_GR_TCPIP_FORWARD	 	1
+#define	RTYPE_GR_CANCEL_TCPIP_FORWARD	2
+#define	RTYPE_GR_DIRECT_TCPIP		4
+
+#define	RTYPE_CO_SESSION		1
+#define	RTYPE_CO_X11			2
+
+#define	RTYPE_CR_PTY_REQ		1
+#define	RTYPE_CR_X11_REQ		2
+#define	RTYPE_CR_X11			4
+#define	RTYPE_CR_ENV			8
+#define	RTYPE_CR_SHELL			16
+#define	RTYPE_CR_EXEC			32
+#define	RTYPE_CR_SUBSYSTEM		64
+
+typedef struct { const char *name; u_int type; } rtype_map_t;
+
+extern rtype_map_t rtypemap_global_req[];
+extern rtype_map_t rtypemap_channel_open[];
+extern rtype_map_t rtypemap_channel_req[];
+
+int get_reqtype(const rtype_map_t *map, const char *);
+
 typedef struct {
 	u_int num_ports;
 	u_int ports_from_cmdline;
@@ -106,7 +129,11 @@
 	char   *allow_groups[MAX_ALLOW_GROUPS];
 	u_int num_deny_groups;
 	char   *deny_groups[MAX_DENY_GROUPS];
-
+	
+	u_int global_req_deny;
+	u_int channel_deny;
+	u_int channel_req_deny;
+	
 	u_int num_subsystems;
 	char   *subsystem_name[MAX_SUBSYSTEMS];
 	char   *subsystem_command[MAX_SUBSYSTEMS];
Index: session.c
===================================================================
RCS file: /cvs/openssh/session.c,v
retrieving revision 1.351
diff -u -r1.351 session.c
--- session.c	26 Mar 2007 16:35:28 -0000	1.351
+++ session.c	5 Apr 2007 07:54:35 -0000
@@ -87,6 +87,7 @@
 #include "session.h"
 #include "kex.h"
 #include "monitor_wrap.h"
+#include "groupaccess.h"
 
 #if defined(KRB5) && defined(USE_AFS)
 #include <kafs.h>
@@ -432,7 +433,7 @@
 		is_child = 1;
 
 		/* Child.  Reinitialize the log since the pid has changed. */
-		log_init(__progname, options.log_level, options.log_facility, log_stderr);
+		log_init(__progname, options.log_level, options.log_facility, log_stderr, 0);
 
 		/*
 		 * Create a new session and process group since the 4.4BSD
@@ -570,7 +571,7 @@
 		is_child = 1;
 
 		/* Child.  Reinitialize the log because the pid has changed. */
-		log_init(__progname, options.log_level, options.log_facility, log_stderr);
+		log_init(__progname, options.log_level, options.log_facility, log_stderr, 0);
 		/* Close the master side of the pseudo tty. */
 		close(ptyfd);
 
@@ -1861,10 +1862,9 @@
 session_subsystem_req(Session *s)
 {
 	struct stat st;
-	u_int len;
+	u_int len, i;
 	int success = 0;
-	char *prog, *cmd, *subsys = packet_get_string(&len);
-	u_int i;
+	char *cmd, *subsys = packet_get_string(&len), *prog;
 
 	packet_check_eom();
 	logit("subsystem request for %.100s", subsys);
@@ -2008,6 +2008,7 @@
 session_input_channel_req(Channel *c, const char *rtype)
 {
 	int success = 0;
+	u_int reqtype = 0;
 	Session *s;
 
 	if ((s = session_by_channel(c->self)) == NULL) {
@@ -2016,7 +2017,16 @@
 		return 0;
 	}
 	debug("session_input_channel_req: session %d req %s", s->self, rtype);
-
+        
+//	if (reqtype = get_reqtype_channel_req(NULL, rtype)) {
+//		/* Controlled request type, check for deny flag */
+/*		if ((options.channel_req_deny & reqtype) == reqtype) {
+			logit("Channel request for type '%s' denied by configuration", rtype);
+			packet_send_debug("Channel request denied by configuration.");
+			return 0;
+		}
+	}*/
+	
 	/*
 	 * a session is in LARVAL state until a shell, a command
 	 * or a subsystem is executed
Index: sftp-common.c
===================================================================
RCS file: /cvs/openssh/sftp-common.c,v
retrieving revision 1.20
diff -u -r1.20 sftp-common.c
--- sftp-common.c	5 Aug 2006 02:39:40 -0000	1.20
+++ sftp-common.c	5 Apr 2007 07:54:35 -0000
@@ -182,6 +182,10 @@
 
 /*
  * drwxr-xr-x    5 markus   markus       1024 Jan 13 18:39 .ssh
+ * 
+ * TODO: make this work under chroot(). Either open connection to
+ * passwd provider beforehand and make it persistent, or cache passwd
+ * file entries.
  */
 char *
 ls_file(const char *name, const struct stat *st, int remote)
Index: sftp-server.c
===================================================================
RCS file: /cvs/openssh/sftp-server.c,v
retrieving revision 1.82
diff -u -r1.82 sftp-server.c
--- sftp-server.c	5 Jan 2007 05:31:03 -0000	1.82
+++ sftp-server.c	5 Apr 2007 07:54:35 -0000
@@ -36,6 +36,9 @@
 #include <unistd.h>
 #include <stdarg.h>
 
+#define _GNU_SRC
+#include <getopt.h>
+
 #include "xmalloc.h"
 #include "buffer.h"
 #include "log.h"
@@ -51,7 +54,7 @@
 #define get_string(lenp)		buffer_get_string(&iqueue, lenp);
 
 /* Our verbosity */
-LogLevel log_level = SYSLOG_LEVEL_ERROR;
+LogLevel log_level = SYSLOG_LEVEL_INFO;
 
 /* Our client */
 struct passwd *pw = NULL;
@@ -316,14 +319,11 @@
 handle_log_close(int handle, char *emsg)
 {
 	if (handle_is_ok(handle, HANDLE_FILE)) {
-		logit("%s%sclose \"%s\" bytes read %llu written %llu",
-		    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
+		verbose("Closed file '%s' (bytes read %llu, written %llu%s%s)",
 		    handle_to_name(handle),
-		    handle_bytes_read(handle), handle_bytes_write(handle));
-	} else {
-		logit("%s%sclosedir \"%s\"",
-		    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
-		    handle_to_name(handle));
+		    handle_bytes_read(handle), handle_bytes_write(handle),
+		    emsg ? ", " : "",
+		    emsg ? emsg : "");
 	}
 }
 
@@ -389,7 +389,7 @@
 	debug3("request %u: sent status %u", id, status);
 	if (log_level > SYSLOG_LEVEL_VERBOSE ||
 	    (status != SSH2_FX_OK && status != SSH2_FX_EOF))
-		logit("sent status %s", status_to_message(status));
+		debug("sent status %s", status_to_message(status));
 	buffer_init(&msg);
 	buffer_put_char(&msg, SSH2_FXP_STATUS);
 	buffer_put_int(&msg, id);
@@ -475,7 +475,7 @@
 	Buffer msg;
 
 	version = get_int();
-	verbose("received client version %d", version);
+	debug("received client version %d", version);
 	buffer_init(&msg);
 	buffer_put_char(&msg, SSH2_FXP_VERSION);
 	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
@@ -494,12 +494,9 @@
 	id = get_int();
 	name = get_string(NULL);
 	pflags = get_int();		/* portable flags */
-	debug3("request %u: open flags %d", id, pflags);
 	a = get_attrib();
 	flags = flags_from_portable(pflags);
 	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
-	logit("open \"%s\" flags %s mode 0%o",
-	    name, string_from_portable(pflags), mode);
 	fd = open(name, flags, mode);
 	if (fd < 0) {
 		status = errno_to_portable(errno);
@@ -511,6 +508,10 @@
 			send_handle(id, handle);
 			status = SSH2_FX_OK;
 		}
+		verbose(
+		        "Opened file '%s' with (flags = %s, mode = 0%o)",
+			name, string_from_portable(pflags), mode
+		);
 	}
 	if (status != SSH2_FX_OK)
 		send_status(id, status);
@@ -624,7 +625,6 @@
 	id = get_int();
 	name = get_string(NULL);
 	debug3("request %u: %sstat", id, do_lstat ? "l" : "");
-	verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
 	ret = do_lstat ? lstat(name, &st) : stat(name, &st);
 	if (ret < 0) {
 		status = errno_to_portable(errno);
@@ -700,36 +700,42 @@
 	id = get_int();
 	name = get_string(NULL);
 	a = get_attrib();
-	debug("request %u: setstat name \"%s\"", id, name);
 	if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
-		logit("set \"%s\" size %llu", name, a->size);
 		ret = truncate(name, a->size);
 		if (ret == -1)
 			status = errno_to_portable(errno);
+		else {
+			verbose("Resized '%s' to %llu byte%s", name, a->size, a->size == 1 ? "" : "s");
+		}
 	}
 	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
-		logit("set \"%s\" mode %04o", name, a->perm);
 		ret = chmod(name, a->perm & 0777);
 		if (ret == -1)
 			status = errno_to_portable(errno);
+		else {
+			verbose("Changed mode on '%s' to %04o", name, a->perm);
+		}
 	}
 	if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
 		char buf[64];
 		time_t t = a->mtime;
 
-		strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
-		    localtime(&t));
-		logit("set \"%s\" modtime %s", name, buf);
 		ret = utimes(name, attrib_to_tv(a));
 		if (ret == -1)
 			status = errno_to_portable(errno);
+		else {
+			strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
+				 localtime(&t));
+			verbose("Modified time on '%s' to %s", name, buf);
+		}
 	}
 	if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
-		logit("set \"%s\" owner %lu group %lu", name,
-		    (u_long)a->uid, (u_long)a->gid);
 		ret = chown(name, a->uid, a->gid);
 		if (ret == -1)
 			status = errno_to_portable(errno);
+		else {
+			verbose("Modified ownership of '%s' to uid %lu gid %lu", name, (u_long)a->uid, (u_long)a->gid);
+		}
 	}
 	send_status(id, status);
 	xfree(name);
@@ -754,13 +760,14 @@
 		char *name = handle_to_name(handle);
 
 		if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
-			logit("set \"%s\" size %llu", name, a->size);
 			ret = ftruncate(fd, a->size);
 			if (ret == -1)
 				status = errno_to_portable(errno);
+			else {
+				verbose("Resized '%s' to %llu byte%s", name, a->size, a->size == 1 ? "" : "s");
+			}
 		}
 		if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
-			logit("set \"%s\" mode %04o", name, a->perm);
 #ifdef HAVE_FCHMOD
 			ret = fchmod(fd, a->perm & 0777);
 #else
@@ -768,14 +775,14 @@
 #endif
 			if (ret == -1)
 				status = errno_to_portable(errno);
+			else {
+				verbose("Changed mode on '%s' to %04o", name, a->perm & 0777);
+			}
 		}
 		if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
 			char buf[64];
 			time_t t = a->mtime;
 
-			strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
-			    localtime(&t));
-			logit("set \"%s\" modtime %s", name, buf);
 #ifdef HAVE_FUTIMES
 			ret = futimes(fd, attrib_to_tv(a));
 #else
@@ -783,10 +790,13 @@
 #endif
 			if (ret == -1)
 				status = errno_to_portable(errno);
+			else {
+				strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
+					 localtime(&t));
+				verbose("Modified time on '%s' to %s", name, buf);
+			}
 		}
 		if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
-			logit("set \"%s\" owner %lu group %lu", name,
-			    (u_long)a->uid, (u_long)a->gid);
 #ifdef HAVE_FCHOWN
 			ret = fchown(fd, a->uid, a->gid);
 #else
@@ -794,6 +804,7 @@
 #endif
 			if (ret == -1)
 				status = errno_to_portable(errno);
+			verbose("Modified ownership of '%s' to uid %lu gid %lu", name, (u_long)a->uid, (u_long)a->gid);
 		}
 	}
 	send_status(id, status);
@@ -810,7 +821,7 @@
 	id = get_int();
 	path = get_string(NULL);
 	debug3("request %u: opendir", id);
-	logit("opendir \"%s\"", path);
+
 	dirp = opendir(path);
 	if (dirp == NULL) {
 		status = errno_to_portable(errno);
@@ -895,9 +906,10 @@
 
 	id = get_int();
 	name = get_string(NULL);
-	debug3("request %u: remove", id);
-	logit("remove name \"%s\"", name);
 	ret = unlink(name);
+	if (ret == 0) {
+		verbose("Removed file '%s'", name);
+	}
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
 	send_status(id, status);
 	xfree(name);
@@ -916,9 +928,10 @@
 	a = get_attrib();
 	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
 	    a->perm & 0777 : 0777;
-	debug3("request %u: mkdir", id);
-	logit("mkdir name \"%s\" mode 0%o", name, mode);
 	ret = mkdir(name, mode);
+	if (ret == 0) {
+		verbose("Created directory '%s' mode 0%o", name, mode);
+	}
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
 	send_status(id, status);
 	xfree(name);
@@ -933,9 +946,10 @@
 
 	id = get_int();
 	name = get_string(NULL);
-	debug3("request %u: rmdir", id);
-	logit("rmdir name \"%s\"", name);
 	ret = rmdir(name);
+	if (ret == 0) {
+		verbose("Removed directory '%s'", name);
+	}
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
 	send_status(id, status);
 	xfree(name);
@@ -955,7 +969,6 @@
 		path = xstrdup(".");
 	}
 	debug3("request %u: realpath", id);
-	verbose("realpath \"%s\"", path);
 	if (realpath(path, resolvedname) == NULL) {
 		send_status(id, errno_to_portable(errno));
 	} else {
@@ -979,7 +992,6 @@
 	oldpath = get_string(NULL);
 	newpath = get_string(NULL);
 	debug3("request %u: rename", id);
-	logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
 	status = SSH2_FX_FAILURE;
 	if (lstat(oldpath, &sb) == -1)
 		status = errno_to_portable(errno);
@@ -1019,6 +1031,9 @@
 		else
 			status = SSH2_FX_OK;
 	}
+	if (status == SSH2_FX_OK) {
+		verbose("Renamed '%s' to '%s'", oldpath, newpath);
+	}
 	send_status(id, status);
 	xfree(oldpath);
 	xfree(newpath);
@@ -1035,7 +1050,6 @@
 	id = get_int();
 	path = get_string(NULL);
 	debug3("request %u: readlink", id);
-	verbose("readlink \"%s\"", path);
 	if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
 		send_status(id, errno_to_portable(errno));
 	else {
@@ -1059,10 +1073,11 @@
 	id = get_int();
 	oldpath = get_string(NULL);
 	newpath = get_string(NULL);
-	debug3("request %u: symlink", id);
-	logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
 	/* this will fail if 'newpath' exists */
 	ret = symlink(oldpath, newpath);
+	if (ret == 0) {
+		verbose("Created symlink '%s' to '%s'", newpath, oldpath);
+	}
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
 	send_status(id, status);
 	xfree(oldpath);
@@ -1208,10 +1223,16 @@
 main(int argc, char **argv)
 {
 	fd_set *rset, *wset;
-	int in, out, max, ch, skipargs = 0, log_stderr = 0;
+	int in, out, max, ch, skipargs = 0, log_stderr = 0, option_index = 0,
+		do_chroot = 0;
 	ssize_t len, olen, set_size;
 	SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
 	char *cp;
+	static struct option long_options[] = {
+		{"chroot", 0, 0, 0}
+	};
+	uid_t target_uid = getuid();
+	char cwd[256];
 
 	extern char *optarg;
 	extern char *__progname;
@@ -1220,10 +1241,15 @@
 	sanitise_stdfd();
 
 	__progname = ssh_get_progname(argv[0]);
-	log_init(__progname, log_level, log_facility, log_stderr);
+	log_init(__progname, log_level, log_facility, log_stderr, 1);
 
-	while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {
+	while (!skipargs && (ch = getopt_long(argc, argv, "C:f:l:che", long_options, &option_index)) != -1) {
 		switch (ch) {
+		case 0:
+			if (!strcmp(long_options[option_index].name, "chroot")) {
+				do_chroot = 1;
+			}
+			break;
 		case 'c':
 			/*
 			 * Ignore all arguments if we are invoked as a
@@ -1235,7 +1261,7 @@
 			log_stderr = 1;
 			break;
 		case 'l':
-			log_level = log_level_number(optarg);
+			log_level = log_level_number(optarg ? optarg : "VERBOSE");
 			if (log_level == SYSLOG_LEVEL_NOT_SET)
 				error("Invalid log level \"%s\"", optarg);
 			break;
@@ -1250,7 +1276,7 @@
 		}
 	}
 
-	log_init(__progname, log_level, log_facility, log_stderr);
+	log_init(__progname, log_level, log_facility, log_stderr, 1);
 
 	if ((cp = getenv("SSH_CONNECTION")) != NULL) {
 		client_addr = xstrdup(cp);
@@ -1264,12 +1290,64 @@
 	if ((pw = getpwuid(getuid())) == NULL)
 		fatal("No user found for uid %lu", (u_long)getuid());
 	pw = pwcopy(pw);
-
-	logit("session opened for local user %s from [%s]",
-	    pw->pw_name, client_addr);
-
+		
 	handle_init();
 
+	/* Log entry must be written before chroot() to ensure that
+	 * the resources are opened.
+	 */
+ 	logit(
+	      "session opened for local user %s (%d) from [%s]%s",
+	      pw->pw_name, target_uid, client_addr,
+	      do_chroot ? ", to be placed in chroot jail" : ""
+	);
+
+	/* The entire concept of a SUID version of this daemon should
+	 * be rethought, as any arbitrary code execution
+	 * vulnerabilities would allow an attacker to change the euid
+	 * back to root. Perhaps a better option would be to use a
+	 * basic SUID-wrapper process which execs sftp-server after
+	 * chroot() and dropping privileges.
+	 */
+	if (do_chroot) {
+		/* chroot to cwd if suid. It's important to exit the
+		 * program if this cannot be done - "fail safe, fail
+		 * secure". The cwd is usually set by the caller (sshd)
+		 * to be the user's home directory.
+		 */
+		if (!getcwd(cwd, sizeof cwd)) {
+			fatal("failed to getcwd()");
+		}
+		
+		if (chroot(cwd)) {
+			fatal("failed to chroot(%s) (%u: %s)", cwd, errno, strerror(errno));
+		}
+		
+		if (chdir("/")) {
+			fatal("failed to change directory to root of jail (%u: %s)", errno, strerror(errno));
+		}
+		
+		if (seteuid(target_uid) != 0) {
+			fatal("failed to seteuid(%u) (%u: %s)", target_uid, errno, strerror(errno));
+		}
+	} else {
+		/* Drop any unnecessary privileges */
+       	        if (target_uid != geteuid()) {
+			if (seteuid(target_uid) != 0) {
+				fatal("failed to shed extra privileges, seteuid(%u) (%u: %s)", target_uid, errno, strerror(errno));
+			} else {
+				debug2("changed effective uid to %u", target_uid);
+			}
+		}
+		if (getgid() != getegid()) {
+			if (setegid(getgid()) != 0) {
+				fatal("failed to shed extra privileges, setegid(%u) (%u: %s)", target_uid, errno, strerror(errno));
+			} else {
+				debug2("changed effective gid to %u", getgid());
+			}
+		}
+	}
+
 	in = dup(STDIN_FILENO);
 	out = dup(STDOUT_FILENO);
 
@@ -1277,7 +1355,7 @@
 	setmode(in, O_BINARY);
 	setmode(out, O_BINARY);
 #endif
-
+	
 	max = 0;
 	if (in > max)
 		max = in;
Index: sftp.c
===================================================================
RCS file: /cvs/openssh/sftp.c,v
retrieving revision 1.102
diff -u -r1.102 sftp.c
--- sftp.c	5 Jan 2007 05:30:41 -0000	1.102
+++ sftp.c	5 Apr 2007 07:54:35 -0000
@@ -1551,7 +1551,7 @@
 	if (!isatty(STDERR_FILENO))
 		showprogress = 0;
 
-	log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
+	log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1, 0);
 
 	if (sftp_direct == NULL) {
 		if (optind == argc || argc > (optind + 2))
Index: ssh-agent.c
===================================================================
RCS file: /cvs/openssh/ssh-agent.c,v
retrieving revision 1.171
diff -u -r1.171 ssh-agent.c
--- ssh-agent.c	21 Mar 2007 09:45:07 -0000	1.171
+++ ssh-agent.c	5 Apr 2007 07:54:35 -0000
@@ -1184,7 +1184,7 @@
 	 * the socket data.  The child continues as the authentication agent.
 	 */
 	if (d_flag) {
-		log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1);
+		log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1, 0);
 		format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
 		printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
 		    SSH_AUTHSOCKET_ENV_NAME);
@@ -1218,7 +1218,7 @@
 		exit(1);
 	}
 	/* child */
-	log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
+	log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0, 0);
 
 	if (setsid() == -1) {
 		error("setsid: %s", strerror(errno));
Index: ssh-keygen.c
===================================================================
RCS file: /cvs/openssh/ssh-keygen.c,v
retrieving revision 1.172
diff -u -r1.172 ssh-keygen.c
--- ssh-keygen.c	19 Feb 2007 11:10:25 -0000	1.172
+++ ssh-keygen.c	5 Apr 2007 07:54:35 -0000
@@ -1073,7 +1073,7 @@
 	__progname = ssh_get_progname(argv[0]);
 
 	SSLeay_add_all_algorithms();
-	log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
+	log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1, 0);
 
 	init_rng();
 	seed_rng();
@@ -1222,7 +1222,7 @@
 	}
 
 	/* reinit */
-	log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
+	log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1, 0);
 
 	if (optind < argc) {
 		printf("Too many arguments.\n");
Index: ssh-keyscan.c
===================================================================
RCS file: /cvs/openssh/ssh-keyscan.c,v
retrieving revision 1.91
diff -u -r1.91 ssh-keyscan.c
--- ssh-keyscan.c	23 Oct 2006 17:01:16 -0000	1.91
+++ ssh-keyscan.c	5 Apr 2007 07:54:35 -0000
@@ -809,7 +809,7 @@
 	if (optind == argc && !fopt_count)
 		usage();
 
-	log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
+	log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1, 0);
 
 	maxfd = fdlim_get(1);
 	if (maxfd < 0)
Index: ssh-rand-helper.c
===================================================================
RCS file: /cvs/openssh/ssh-rand-helper.c,v
retrieving revision 1.41
diff -u -r1.41 ssh-rand-helper.c
--- ssh-rand-helper.c	12 Mar 2007 20:35:39 -0000	1.41
+++ ssh-rand-helper.c	5 Apr 2007 07:54:36 -0000
@@ -821,7 +821,7 @@
 	LogLevel ll;
 
 	__progname = ssh_get_progname(argv[0]);
-	log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
+	log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1, 0);
 
 	ll = SYSLOG_LEVEL_INFO;
 	debug_level = output_hex = 0;
@@ -856,7 +856,7 @@
 		}
 	}
 
-	log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
+	log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1, 0);
 
 #ifdef USE_SEED_FILES
 	prng_read_seedfile();
Index: ssh.c
===================================================================
RCS file: /cvs/openssh/ssh.c,v
retrieving revision 1.286
diff -u -r1.286 ssh.c
--- ssh.c	5 Jan 2007 05:30:17 -0000	1.286
+++ ssh.c	5 Apr 2007 07:54:36 -0000
@@ -604,7 +604,7 @@
 	 * actually goes to stderr.
 	 */
 	log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
-	    SYSLOG_FACILITY_USER, 1);
+	    SYSLOG_FACILITY_USER, 1, 0);
 
 	/*
 	 * Read per-user configuration file.  Ignore the system wide config
@@ -630,7 +630,7 @@
 	channel_set_af(options.address_family);
 
 	/* reinit */
-	log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1);
+	log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1, 0);
 
 	seed_rng();
 
Index: sshd.c
===================================================================
RCS file: /cvs/openssh/sshd.c,v
retrieving revision 1.363
diff -u -r1.363 sshd.c
--- sshd.c	21 Mar 2007 09:38:53 -0000	1.363
+++ sshd.c	5 Apr 2007 07:54:36 -0000
@@ -1171,7 +1171,7 @@
 				log_init(__progname,
 				    options.log_level,
 				    options.log_facility,
-				    log_stderr);
+				    log_stderr, 0);
 				if (rexec_flag)
 					close(config_s[0]);
 				break;
@@ -1385,7 +1385,7 @@
 	    SYSLOG_LEVEL_INFO : options.log_level,
 	    options.log_facility == SYSLOG_FACILITY_NOT_SET ?
 	    SYSLOG_FACILITY_AUTH : options.log_facility,
-	    log_stderr || !inetd_flag);
+	    log_stderr || !inetd_flag, 0);
 
 	/*
 	 * Unset KRB5CCNAME, otherwise the user's session may inherit it from
@@ -1561,7 +1561,7 @@
 	/* Initialize the log (it is reinitialized below in case we forked). */
 	if (debug_flag && (!inetd_flag || rexeced_flag))
 		log_stderr = 1;
-	log_init(__progname, options.log_level, options.log_facility, log_stderr);
+	log_init(__progname, options.log_level, options.log_facility, log_stderr, 0);
 
 	/*
 	 * If not in debugging mode, and not started from inetd, disconnect
@@ -1585,7 +1585,7 @@
 #endif /* TIOCNOTTY */
 	}
 	/* Reinitialize the log (because of the fork above). */
-	log_init(__progname, options.log_level, options.log_facility, log_stderr);
+	log_init(__progname, options.log_level, options.log_facility, log_stderr, 0);
 
 	/* Initialize the random number generator. */
 	arc4random_stir();
@@ -1677,7 +1677,7 @@
 		error("rexec of %s failed: %s", rexec_argv[0], strerror(errno));
 		recv_rexec_state(REEXEC_CONFIG_PASS_FD, NULL);
 		log_init(__progname, options.log_level,
-		    options.log_facility, log_stderr);
+		    options.log_facility, log_stderr, 0);
 
 		/* Clean up fds */
 		startup_pipe = REEXEC_STARTUP_PIPE_FD;
