mirror of
https://github.com/yrutschle/sslh.git
synced 2025-06-02 00:21:00 +03:00
add chroot support
This allows people to chroot sslh into a path to further harden it. We have to rework the user logic a bit because we need to look up the user details *before* we chroot (as we need to read /etc/passwd files), but do the actual priv dropping *after* we chroot (so we have permission to make the actual chroot call). Similarly, we need to open the syslog before we drop privs because /dev/log won't be available inside the chroot.
This commit is contained in:
parent
d9541392f8
commit
0fb4c6b2ad
@ -9,6 +9,7 @@ transparent: false;
|
|||||||
timeout: 2;
|
timeout: 2;
|
||||||
user: "nobody";
|
user: "nobody";
|
||||||
pidfile: "/var/run/sslh.pid";
|
pidfile: "/var/run/sslh.pid";
|
||||||
|
chroot: "/var/empty";
|
||||||
|
|
||||||
|
|
||||||
# Change hostname with your external address name.
|
# Change hostname with your external address name.
|
||||||
|
56
common.c
56
common.c
@ -41,7 +41,7 @@ int foreground = 0;
|
|||||||
int background = 0;
|
int background = 0;
|
||||||
int transparent = 0;
|
int transparent = 0;
|
||||||
int numeric = 0;
|
int numeric = 0;
|
||||||
const char *user_name, *pid_file, *facility = "auth";
|
const char *user_name, *pid_file, *chroot_path, *facility = "auth";
|
||||||
|
|
||||||
struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */
|
struct addrinfo *addr_listen = NULL; /* what addresses do we listen to? */
|
||||||
|
|
||||||
@ -719,33 +719,47 @@ void set_capabilities(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We don't want to run as root -- drop privileges if required */
|
/* We don't want to run as root -- drop privileges if required */
|
||||||
void drop_privileges(const char* user_name)
|
void drop_privileges(const char* user_name, const char* chroot_path)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct passwd *pw = getpwnam(user_name);
|
struct passwd *pw = NULL;
|
||||||
if (!pw) {
|
|
||||||
fprintf(stderr, "%s: not found\n", user_name);
|
if (user_name) {
|
||||||
exit(2);
|
pw = getpwnam(user_name);
|
||||||
|
if (!pw) {
|
||||||
|
fprintf(stderr, "%s: not found\n", user_name);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stderr, "turning into %s\n", user_name);
|
||||||
}
|
}
|
||||||
if (verbose)
|
|
||||||
fprintf(stderr, "turning into %s\n", user_name);
|
|
||||||
|
|
||||||
set_keepcaps(1);
|
if (chroot_path) {
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stderr, "chrooting into %s\n", chroot_path);
|
||||||
|
|
||||||
/* remove extraneous groups in case we belong to several extra groups that
|
res = chroot(chroot_path);
|
||||||
* may have unwanted rights. If non-root when calling setgroups(), it
|
CHECK_RES_DIE(res, "chroot");
|
||||||
* fails, which is fine because... we have no unwanted rights
|
}
|
||||||
* (see POS36-C for security context)
|
|
||||||
* */
|
|
||||||
setgroups(0, NULL);
|
|
||||||
|
|
||||||
res = setgid(pw->pw_gid);
|
if (user_name) {
|
||||||
CHECK_RES_DIE(res, "setgid");
|
set_keepcaps(1);
|
||||||
res = setuid(pw->pw_uid);
|
|
||||||
CHECK_RES_DIE(res, "setuid");
|
|
||||||
|
|
||||||
set_capabilities();
|
/* remove extraneous groups in case we belong to several extra groups
|
||||||
set_keepcaps(0);
|
* that may have unwanted rights. If non-root when calling setgroups(),
|
||||||
|
* it fails, which is fine because... we have no unwanted rights
|
||||||
|
* (see POS36-C for security context)
|
||||||
|
* */
|
||||||
|
setgroups(0, NULL);
|
||||||
|
|
||||||
|
res = setgid(pw->pw_gid);
|
||||||
|
CHECK_RES_DIE(res, "setgid");
|
||||||
|
res = setuid(pw->pw_uid);
|
||||||
|
CHECK_RES_DIE(res, "setuid");
|
||||||
|
|
||||||
|
set_capabilities();
|
||||||
|
set_keepcaps(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Writes my PID */
|
/* Writes my PID */
|
||||||
|
4
common.h
4
common.h
@ -102,7 +102,7 @@ void log_connection(struct connection *cnx);
|
|||||||
int check_access_rights(int in_socket, const char* service);
|
int check_access_rights(int in_socket, const char* service);
|
||||||
void setup_signals(void);
|
void setup_signals(void);
|
||||||
void setup_syslog(const char* bin_name);
|
void setup_syslog(const char* bin_name);
|
||||||
void drop_privileges(const char* user_name);
|
void drop_privileges(const char* user_name, const char* chroot_path);
|
||||||
void write_pid_file(const char* pidfile);
|
void write_pid_file(const char* pidfile);
|
||||||
void log_message(int type, char* msg, ...);
|
void log_message(int type, char* msg, ...);
|
||||||
void dump_connection(struct connection *cnx);
|
void dump_connection(struct connection *cnx);
|
||||||
@ -118,7 +118,7 @@ extern int probing_timeout, verbose, inetd, foreground,
|
|||||||
extern struct sockaddr_storage addr_ssl, addr_ssh, addr_openvpn;
|
extern struct sockaddr_storage addr_ssl, addr_ssh, addr_openvpn;
|
||||||
extern struct addrinfo *addr_listen;
|
extern struct addrinfo *addr_listen;
|
||||||
extern const char* USAGE_STRING;
|
extern const char* USAGE_STRING;
|
||||||
extern const char* user_name, *pid_file, *facility;
|
extern const char* user_name, *pid_file, *chroot_path, *facility;
|
||||||
extern const char* server_type;
|
extern const char* server_type;
|
||||||
|
|
||||||
/* sslh-fork.c */
|
/* sslh-fork.c */
|
||||||
|
@ -11,6 +11,7 @@ transparent: false;
|
|||||||
timeout: 2;
|
timeout: 2;
|
||||||
user: "nobody";
|
user: "nobody";
|
||||||
pidfile: "/var/run/sslh.pid";
|
pidfile: "/var/run/sslh.pid";
|
||||||
|
chroot: "/var/empty";
|
||||||
|
|
||||||
# Specify which syslog facility to use (names for your
|
# Specify which syslog facility to use (names for your
|
||||||
# system are usually defined in /usr/include/*/sys/syslog.h
|
# system are usually defined in /usr/include/*/sys/syslog.h
|
||||||
|
21
sslh-main.c
21
sslh-main.c
@ -40,7 +40,7 @@ const char* USAGE_STRING =
|
|||||||
"sslh " VERSION "\n" \
|
"sslh " VERSION "\n" \
|
||||||
"usage:\n" \
|
"usage:\n" \
|
||||||
"\tsslh [-v] [-i] [-V] [-f] [-n] [--transparent] [-F<file>]\n"
|
"\tsslh [-v] [-i] [-V] [-f] [-n] [--transparent] [-F<file>]\n"
|
||||||
"\t[-t <timeout>] [-P <pidfile>] -u <username> -p <add> [-p <addr> ...] \n" \
|
"\t[-t <timeout>] [-P <pidfile>] [-u <username>] [-C <chroot>] -p <add> [-p <addr> ...] \n" \
|
||||||
"%s\n\n" /* Dynamically built list of builtin protocols */ \
|
"%s\n\n" /* Dynamically built list of builtin protocols */ \
|
||||||
"\t[--on-timeout <addr>]\n" \
|
"\t[--on-timeout <addr>]\n" \
|
||||||
"-v: verbose\n" \
|
"-v: verbose\n" \
|
||||||
@ -48,6 +48,7 @@ const char* USAGE_STRING =
|
|||||||
"-f: foreground\n" \
|
"-f: foreground\n" \
|
||||||
"-n: numeric output\n" \
|
"-n: numeric output\n" \
|
||||||
"-u: specify under which user to run\n" \
|
"-u: specify under which user to run\n" \
|
||||||
|
"-C: specify under which chroot path to run\n" \
|
||||||
"--transparent: behave as a transparent proxy\n" \
|
"--transparent: behave as a transparent proxy\n" \
|
||||||
"-F: use configuration file (warning: no space between -F and file name!)\n" \
|
"-F: use configuration file (warning: no space between -F and file name!)\n" \
|
||||||
"--on-timeout: connect to specified address upon timeout (default: ssh address)\n" \
|
"--on-timeout: connect to specified address upon timeout (default: ssh address)\n" \
|
||||||
@ -71,6 +72,7 @@ static struct option const_options[] = {
|
|||||||
{ "user", required_argument, 0, 'u' },
|
{ "user", required_argument, 0, 'u' },
|
||||||
{ "config", optional_argument, 0, 'F' },
|
{ "config", optional_argument, 0, 'F' },
|
||||||
{ "pidfile", required_argument, 0, 'P' },
|
{ "pidfile", required_argument, 0, 'P' },
|
||||||
|
{ "chroot", required_argument, 0, 'C' },
|
||||||
{ "timeout", required_argument, 0, 't' },
|
{ "timeout", required_argument, 0, 't' },
|
||||||
{ "on-timeout", required_argument, 0, OPT_ONTIMEOUT },
|
{ "on-timeout", required_argument, 0, OPT_ONTIMEOUT },
|
||||||
{ "listen", required_argument, 0, 'p' },
|
{ "listen", required_argument, 0, 'p' },
|
||||||
@ -78,7 +80,7 @@ static struct option const_options[] = {
|
|||||||
};
|
};
|
||||||
static struct option* all_options;
|
static struct option* all_options;
|
||||||
static struct proto* builtins;
|
static struct proto* builtins;
|
||||||
static const char *optstr = "vt:T:p:VP:F::";
|
static const char *optstr = "vt:T:p:VP:C:F::";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -399,6 +401,7 @@ static int config_parse(char *filename, struct addrinfo **listen, struct proto *
|
|||||||
|
|
||||||
config_lookup_string(&config, "user", &user_name);
|
config_lookup_string(&config, "user", &user_name);
|
||||||
config_lookup_string(&config, "pidfile", &pid_file);
|
config_lookup_string(&config, "pidfile", &pid_file);
|
||||||
|
config_lookup_string(&config, "chroot", &chroot_path);
|
||||||
|
|
||||||
config_lookup_string(&config, "syslog_facility", &facility);
|
config_lookup_string(&config, "syslog_facility", &facility);
|
||||||
|
|
||||||
@ -561,6 +564,10 @@ next_arg:
|
|||||||
pid_file = optarg;
|
pid_file = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'C':
|
||||||
|
chroot_path = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose++;
|
verbose++;
|
||||||
break;
|
break;
|
||||||
@ -605,6 +612,7 @@ int main(int argc, char *argv[])
|
|||||||
/* Init defaults */
|
/* Init defaults */
|
||||||
pid_file = NULL;
|
pid_file = NULL;
|
||||||
user_name = NULL;
|
user_name = NULL;
|
||||||
|
chroot_path = NULL;
|
||||||
|
|
||||||
cmdline_config(argc, argv, &protocols);
|
cmdline_config(argc, argv, &protocols);
|
||||||
parse_cmdline(argc, argv, protocols);
|
parse_cmdline(argc, argv, protocols);
|
||||||
@ -643,13 +651,12 @@ int main(int argc, char *argv[])
|
|||||||
if (pid_file)
|
if (pid_file)
|
||||||
write_pid_file(pid_file);
|
write_pid_file(pid_file);
|
||||||
|
|
||||||
if (user_name)
|
/* Open syslog connection before we drop privs/chroot */
|
||||||
drop_privileges(user_name);
|
|
||||||
|
|
||||||
|
|
||||||
/* Open syslog connection */
|
|
||||||
setup_syslog(argv[0]);
|
setup_syslog(argv[0]);
|
||||||
|
|
||||||
|
if (user_name || chroot_path)
|
||||||
|
drop_privileges(user_name, chroot_path);
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printcaps();
|
printcaps();
|
||||||
|
|
||||||
|
6
sslh.pod
6
sslh.pod
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
sslh [B<-F>I<config file>] [ B<-t> I<num> ] [B<--transparent>] [B<-p> I<listening address> [B<-p> I<listening address> ...] [B<--ssl> I<target address for SSL>] [B<--tls> I<target address for TLS>] [B<--ssh> I<target address for SSH>] [B<--openvpn> I<target address for OpenVPN>] [B<--http> I<target address for HTTP>] [B<--xmpp> I<target address for XMPP>] [B<--tinc> I<target address for TINC>] [B<--anyprot> I<default target address>] [B<--on-timeout> I<protocol name>] [B<-u> I<username>] [B<-P> I<pidfile>] [-v] [-i] [-V] [-f] [-n]
|
sslh [B<-F>I<config file>] [B<-t> I<num>] [B<--transparent>] [B<-p> I<listening address> [B<-p> I<listening address> ...] [B<--ssl> I<target address for SSL>] [B<--tls> I<target address for TLS>] [B<--ssh> I<target address for SSH>] [B<--openvpn> I<target address for OpenVPN>] [B<--http> I<target address for HTTP>] [B<--xmpp> I<target address for XMPP>] [B<--tinc> I<target address for TINC>] [B<--anyprot> I<default target address>] [B<--on-timeout> I<protocol name>] [B<-u> I<username>] [B<-C> I<chroot>] [B<-P> I<pidfile>] [-v] [-i] [-V] [-f] [-n]
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
@ -184,6 +184,10 @@ Prints B<sslh> version.
|
|||||||
|
|
||||||
Requires to run under the specified username.
|
Requires to run under the specified username.
|
||||||
|
|
||||||
|
=item B<-C> I<chroot>, B<--chroot> I<chroot>
|
||||||
|
|
||||||
|
Requires to run under the specified chroot.
|
||||||
|
|
||||||
=item B<-P> I<pidfile>, B<--pidfile> I<pidfile>
|
=item B<-P> I<pidfile>, B<--pidfile> I<pidfile>
|
||||||
|
|
||||||
Specifies a file in which to write the PID of the main
|
Specifies a file in which to write the PID of the main
|
||||||
|
Loading…
x
Reference in New Issue
Block a user