diff --git a/kdc/config.c b/kdc/config.c index a7c7c80f4..c2c2a19e5 100644 --- a/kdc/config.c +++ b/kdc/config.c @@ -64,6 +64,10 @@ static struct getarg_strings addresses_str; /* addresses to listen on */ static char *v4_realm; +char *runas_string; +char *chroot_string; + + static struct getargs args[] = { { "config-file", 'c', arg_string, &config_file, @@ -118,6 +122,12 @@ static struct getargs args[] = { "disable DES" }, { "builtin-hdb", 0, arg_flag, &builtin_hdb_flag, "list builtin hdb backends"}, + { "runas-user", 0, arg_string, &runas_string, + "run as this user when connected to network" + }, + { "chroot", 0, arg_string, &chroot_string, + "chroot directory to run in" + }, { "help", 'h', arg_flag, &help_flag }, { "version", 'v', arg_flag, &version_flag } }; diff --git a/kdc/kdc_locl.h b/kdc/kdc_locl.h index daf155839..024937e76 100644 --- a/kdc/kdc_locl.h +++ b/kdc/kdc_locl.h @@ -67,6 +67,9 @@ extern const struct units _kdc_digestunits[]; extern struct timeval _kdc_now; #define kdc_time (_kdc_now.tv_sec) +extern char *runas_string; +extern char *chroot_string; + void loop(krb5_context context, krb5_kdc_configuration *config); diff --git a/kdc/main.c b/kdc/main.c index 062c1d8cd..e5dd4788d 100644 --- a/kdc/main.c +++ b/kdc/main.c @@ -48,6 +48,41 @@ sigterm(int sig) exit_flag = sig; } +/* + * Allow dropping root bit, since heimdal reopens the database all the + * time the database needs to be owned by the user you are switched + * too. A better solution is to split the kdc in to more processes and + * run the network facing part with very low privilege. + */ + +static void +switch_environment(void) +{ + if ((runas_string || chroot_string) && geteuid() != 0) + errx(1, "no running as root, can't switch user/chroot"); + + if (chroot_string && chroot(chroot_string) != 0) + errx(1, "chroot(%s)", "chroot_string failed"); + + if (runas_string) { + struct passwd *pw; + + pw = getpwnam(runas_string); + if (pw == NULL) + errx(1, "unknown user %s", runas_string); + + if (initgroups(pw->pw_name, pw->pw_gid) < 0) + err(1, "initgroups failed"); + + if (setgid(pw->pw_gid) < 0) + err(1, "setgid(%s) failed", runas_string); + + if (setuid(pw->pw_uid) < 0) + err(1, "setuid(%s)", runas_string); + } +} + + int main(int argc, char **argv) { @@ -95,6 +130,9 @@ main(int argc, char **argv) daemon(0, 0); #endif pidfile(NULL); + + switch_environment(); + loop(context, config); krb5_free_context(context); return 0;