Package: httptunnel
Version: 3.3+dfsg-1
Severity: normal
Tags: security,patch,upstream
hts (httptunnel server side program) provides no way to downgrade
privileges after all sockets are open.
That means some hacks (ie: capabilities) need to be done to bind
privileged port (ie: 80) when using unprivileged user (ie: nobody).
Furthermore no privilege are needed once the tunnel is created.
The attached patch add 2 more arguments to hts command line:
-C, --chroot LOCATION
-u, --user USERNAME
Privileges are downgraded after tunnel_new_server() call
(chroot,getpwnam+setgid+setuid)
Patch tested and working on 1 Debian testing + 1 Debian unstable (both x86).
-- System Information:
Debian Release: 4.0
APT prefers unstable
APT policy: (500, 'unstable')
Architecture: i386 (i686)
Kernel: Linux 2.6.18.3-crazy
Versions of packages file depends on:
ii libc6 2.6.1-1 GNU C Library: Shared libraries
diff -Nur httptunnel-3.3+dfsg/hts.1 httptunnel-3.3.new/hts.1
--- httptunnel-3.3+dfsg/hts.1 2008-04-22 22:30:25.000000000 +0200
+++ httptunnel-3.3.new/hts.1 2008-04-22 22:32:57.000000000 +0200
@@ -44,6 +44,12 @@
.TP
.B \-p, \-\-pid\-file LOCATION
write a PID file to LOCATION
+.TP
+.B \-C, \-\-chroot LOCATION
+chroot to LOCATION before serving clients
+.TP
+.B \-u, \-\-user USER
+change user and group identities before serving clients
.SH AUTHOR
This manual page was contributed by Teemu Hukkanen <[EMAIL PROTECTED]>,
and was originally written for the Debian GNU/Linux system.
diff -Nur httptunnel-3.3+dfsg/hts.c httptunnel-3.3.new/hts.c
--- httptunnel-3.3+dfsg/hts.c 2001-02-25 12:56:37.000000000 +0100
+++ httptunnel-3.3.new/hts.c 2008-04-22 01:42:43.000000000 +0200
@@ -13,6 +13,8 @@
#include <signal.h>
#include <sys/poll_.h>
#include <sys/time.h>
+#include <time.h>
+#include <pwd.h>
#include "common.h"
@@ -31,6 +33,8 @@
int strict_content_length;
int keep_alive;
int max_connection_age;
+ char *chroot_path;
+ char *user;
} Arguments;
int debug_level = 0;
@@ -67,6 +71,8 @@
" -V, --version output version information and exit\n"
" -w, --no-daemon don't fork into the background\n"
" -p, --pid-file LOCATION write a PID file to LOCATION\n"
+" -C, --chroot LOCATION chroot to LOCATION before serving clients\n"
+" -u, --user USERNAME change user id before serving clients\n"
"\n"
"Report bugs to %s.\n",
me, DEFAULT_HOST_PORT, DEFAULT_KEEP_ALIVE,
@@ -93,6 +99,8 @@
arg->strict_content_length = FALSE;
arg->keep_alive = DEFAULT_KEEP_ALIVE;
arg->max_connection_age = DEFAULT_CONNECTION_MAX_TIME;
+ arg->chroot_path = NULL;
+ arg->user = NULL;
for (;;)
{
@@ -114,10 +122,12 @@
{ "forward-port", required_argument, 0, 'F' },
{ "content-length", required_argument, 0, 'c' },
{ "max-connection-age", required_argument, 0, 'M' },
+ { "chroot", required_argument, 0, 'C' },
+ { "user", required_argument, 0, 'u' },
{ 0, 0, 0, 0 }
};
- static const char *short_options = "c:d:F:hk:M:p:sSVw"
+ static const char *short_options = "c:C:d:F:hk:M:p:sSu:Vw"
#ifdef DEBUG_MODE
"D:l:"
#endif
@@ -140,6 +150,10 @@
case 'c':
arg->content_length = atoi_with_postfix (optarg);
break;
+
+ case 'C':
+ arg->chroot_path = optarg;
+ break;
case 'd':
arg->device = optarg;
@@ -203,6 +217,10 @@
case 'p':
arg->pid_filename = optarg;
break;
+
+ case 'u':
+ arg->user = optarg;
+ break;
case 'w':
arg->use_daemon = FALSE;
@@ -278,6 +296,8 @@
Arguments arg;
Tunnel *tunnel;
FILE *pid_file;
+ uid_t uid;
+ gid_t gid;
parse_arguments (argc, argv, &arg);
@@ -307,6 +327,10 @@
log_notice (" debug_level = %d", debug_level);
log_notice (" pid_filename = %s",
arg.pid_filename ? arg.pid_filename : "(null)");
+ log_notice (" chroot_path = %s",
+ arg.chroot_path ? arg.chroot_path : "(null)");
+ log_notice (" user = %s",
+ arg.user ? arg.user : "(null)");
tunnel = tunnel_new_server (arg.host, arg.port, arg.content_length);
if (tunnel == NULL)
@@ -315,6 +339,36 @@
log_exit (1);
}
+ if (arg.user)
+ {
+ struct passwd *pwd;
+ pwd = getpwnam(arg.user);
+ if (!pwd)
+ {
+ log_error ("couldn't chroot to %s", arg.chroot_path);
+ log_exit (1);
+ }
+ uid = pwd->pw_uid;
+ gid = pwd->pw_gid;
+ endpwent();
+ }
+
+ if (arg.chroot_path && chroot(arg.chroot_path))
+ {
+ log_error ("couldn't chroot to %s", arg.chroot_path);
+ log_exit (1);
+ }
+
+ if (arg.user)
+ {
+ if (setgid(gid) || setuid(uid))
+ {
+ log_error ("couldn't change identity to %u:%u", uid, gid);
+ log_exit (1);
+ }
+ }
+
+
if (tunnel_setopt (tunnel, "strict_content_length",
&arg.strict_content_length) == -1)
log_debug ("tunnel_setopt strict_content_length error: %s",