--- sftp-server.org.c	2004-07-28 21:34:43.000000000 +0200
+++ sftp-server.c	2004-07-30 10:19:41.000000000 +0200
@@ -54,6 +54,33 @@
 	Attrib attrib;
 };
 
+#include <pwd.h>
+
+static char	*_home = 0;
+static int	_max_upp = 0;
+static int	_cur_upp = 0;
+static int	_max_down = 0;
+static int	_cur_down = 0;
+
+#define	SET_TIMEOUT(_TM, _TSEC, _TUSEC)		_TM .tv_sec = _TSEC; _TM .tv_usec = _TUSEC
+
+static void	parse_conf(int ac, char **av)
+{
+  struct passwd	*info = 0;
+  int		i;
+
+  for (i = 1; i < ac; i++)
+  {
+    if (!strcmp(av[i], "--stay-in-home"))
+      if ((info = getpwuid(getuid())))
+	_home = info->pw_dir;
+    if (!strcmp(av[i], "--max-uppload") && av[i + 1])
+      _max_upp = atoi(av[i + 1]);
+    if (!strcmp(av[i], "--max-download") && av[i + 1])
+      _max_down = atoi(av[i + 1]);
+  }
+}
+
 static int
 errno_to_portable(int unixerrno)
 {
@@ -671,19 +698,25 @@
 	id = get_int();
 	path = get_string(NULL);
 	TRACE("opendir id %u path %s", id, path);
-	dirp = opendir(path);
-	if (dirp == NULL) {
-		status = errno_to_portable(errno);
-	} else {
-		handle = handle_new(HANDLE_DIR, path, 0, dirp);
-		if (handle < 0) {
-			closedir(dirp);
-		} else {
-			send_handle(id, handle);
-			status = SSH2_FX_OK;
-		}
-
-	}
+	if (!_home || (!strncmp(path, _home, strlen(_home))
+		       && (strlen(path) < 3 || strcmp(path + strlen(path) - 3, "/.."))))
+	  {
+	    dirp = opendir(path);
+	    if (dirp == NULL) {
+	      status = errno_to_portable(errno);
+	    } else {
+	      handle = handle_new(HANDLE_DIR, path, 0, dirp);
+	      if (handle < 0) {
+		closedir(dirp);
+	      } else {
+		send_handle(id, handle);
+		status = SSH2_FX_OK;
+	      }
+	      
+	    }
+	  }
+	else
+	  status = SSH2_FX_PERMISSION_DENIED;
 	if (status != SSH2_FX_OK)
 		send_status(id, status);
 	xfree(path);
@@ -1017,13 +1050,15 @@
 main(int ac, char **av)
 {
 	fd_set *rset, *wset;
-	int in, out, max;
+	int in, out, max, ret;
 	ssize_t len, olen, set_size;
+	struct timeval tm;
 
 	/* XXX should use getopt */
 
 	__progname = ssh_get_progname(av[0]);
 	handle_init();
+	parse_conf(ac, av);
 
 #ifdef DEBUG_SFTP_SERVER
 	log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
@@ -1050,46 +1085,69 @@
 	rset = (fd_set *)xmalloc(set_size);
 	wset = (fd_set *)xmalloc(set_size);
 
+	SET_TIMEOUT(tm, 1, 0);
 	for (;;) {
 		memset(rset, 0, set_size);
 		memset(wset, 0, set_size);
 
-		FD_SET(in, rset);
+		if (!_max_upp || (_cur_upp < _max_upp))
+		  FD_SET(in, rset);
+		
 		olen = buffer_len(&oqueue);
-		if (olen > 0)
-			FD_SET(out, wset);
+		if (olen > 0 && (!_max_down || (_cur_down < _max_down)))
+		  FD_SET(out, wset);
 
-		if (select(max+1, rset, wset, NULL, NULL) < 0) {
+		if ((ret = select(max+1, rset, wset, NULL, &tm)) < 0) {
 			if (errno == EINTR)
 				continue;
 			exit(2);
 		}
-
-		/* copy stdin to iqueue */
-		if (FD_ISSET(in, rset)) {
+		if (!ret)
+		  {
+		    _cur_upp = 0;
+		    _cur_down = 0;
+		    SET_TIMEOUT(tm, 1, 0);
+		  }
+		else
+		  {
+		    /* copy stdin to iqueue */
+		    if (FD_ISSET(in, rset)) {
 			char buf[4*4096];
-			len = read(in, buf, sizeof buf);
+			int todo;
+			
+			if (_max_upp)
+			  todo = sizeof(buf) < (_max_upp - _cur_upp) ? sizeof(buf) : (_max_upp - _cur_upp);
+			else
+			  todo = sizeof(buf);
+			len = read(in, buf, todo);
 			if (len == 0) {
-				debug("read eof");
-				exit(0);
+			  debug("read eof");
+			  exit(0);
 			} else if (len < 0) {
-				error("read error");
-				exit(1);
+			  error("read error");
+			  exit(1);
 			} else {
-				buffer_append(&iqueue, buf, len);
+			  buffer_append(&iqueue, buf, len);
+			  _cur_upp += len;
 			}
-		}
-		/* send oqueue to stdout */
-		if (FD_ISSET(out, wset)) {
-			len = write(out, buffer_ptr(&oqueue), olen);
-			if (len < 0) {
-				error("write error");
-				exit(1);
-			} else {
-				buffer_consume(&oqueue, len);
-			}
-		}
-		/* process requests from client */
-		process();
+		    }
+		    /* send oqueue to stdout */
+		    if (FD_ISSET(out, wset)) {
+		      if (_max_down)
+			len = olen < (_max_down - _cur_down) ? olen : (_max_down - _cur_down);
+		      else
+			len = olen;
+		      len = write(out, buffer_ptr(&oqueue), len);
+		      if (len < 0) {
+			error("write error");
+			exit(1);
+		      } else {
+			buffer_consume(&oqueue, len);
+			_cur_down += len;
+		      }
+		    }
+		    /* process requests from client */
+		    process();
+		  }
 	}
 }
