diff -u -r ntp-4.0.99k/ntpd/Makefile.in ntp-4.0.99k-jh/ntpd/Makefile.in --- ntp-4.0.99k/ntpd/Makefile.in Thu Jul 20 07:10:40 2000 +++ ntp-4.0.99k-jh/ntpd/Makefile.in Fri Feb 23 12:31:54 2001 @@ -149,7 +149,7 @@ DEFS = @DEFS@ -I. -I$(srcdir) -I.. CPPFLAGS = @CPPFLAGS@ -LIBS = @LIBS@ +LIBS = @LIBS@ -lcap ANSI2KNR = ../util/ansi2knr check_y2k_SOURCES = check_y2k.c check_y2k_OBJECTS = check_y2k$U.o diff -u -r ntp-4.0.99k/ntpd/ntp_config.c ntp-4.0.99k-jh/ntpd/ntp_config.c --- ntp-4.0.99k/ntpd/ntp_config.c Wed Jul 19 04:38:54 2000 +++ ntp-4.0.99k-jh/ntpd/ntp_config.c Fri Feb 23 12:35:01 2001 @@ -480,7 +480,11 @@ int config_priority; #endif -static const char *ntp_options = "aAbc:dD:f:gk:l:LmnN:p:P:r:s:t:v:V:x"; +static const char *ntp_options = "aAbc:dD:f:gk:l:LmnN:p:P:r:s:t:v:V:x:U:T:"; + +/* Drop root patch */ +extern char *server_user; +extern char *chroot_dir; #ifdef HAVE_NETINFO /* @@ -667,7 +671,30 @@ ++errflg; break; - default: + case 'U': + if ( !ntp_optarg ) { + fprintf(stderr, "Error: Need username with 'U' option\n"); + exit(1); + } + else { + if ( !server_user ) { + server_user = strdup(ntp_optarg); + } + } + break; + + case 'T': + if ( !ntp_optarg ) { + fprintf(stderr, "Error: Need directory with 'T' option\n"); + exit(1); + } + else { + if ( !chroot_dir ) { + chroot_dir = strdup(ntp_optarg); + } + } + break; + default: break; } @@ -676,6 +703,7 @@ (void) fprintf(stderr, "\t\t[ -f freq_file ] [ -k key_file ] [ -l log_file ]\n"); (void) fprintf(stderr, "\t\t[ -p pid_file ] [ -r broad_delay ] [ -s statdir ]\n"); (void) fprintf(stderr, "\t\t[ -t trust_key ] [ -v sys_var ] [ -V default_sysvar ]\n"); + (void) fprintf(stderr, "\t\t[ -T chroot_dir ] [ -U server_user ]\n"); #if defined(HAVE_SCHED_SETSCHEDULER) (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); #endif @@ -911,6 +939,30 @@ allow_set_backward = FALSE; break; + case 'U': + if ( !ntp_optarg ) { + fprintf(stderr, "Error: Need username after 'U' option\n"); + exit(1); + } + else { + if ( !server_user ) { + server_user = strdup(ntp_optarg); + } + } + break; + + case 'T': + if ( !ntp_optarg ) { + fprintf(stderr, "Error: Need directory with 'T' option\n"); + exit(1); + } + else { + if ( !chroot_dir ) { + chroot_dir = strdup(ntp_optarg); + } + } + break; + default: errflg++; break; @@ -922,6 +974,7 @@ (void) fprintf(stderr, "\t\t[ -f freq_file ] [ -k key_file ] [ -l log_file ]\n"); (void) fprintf(stderr, "\t\t[ -p pid_file ] [ -r broad_delay ] [ -s statdir ]\n"); (void) fprintf(stderr, "\t\t[ -t trust_key ] [ -v sys_var ] [ -V default_sysvar ]\n"); + (void) fprintf(stderr, "\t\t[ -T chroot_dir ] [ -U server_user ]\n"); #if defined(HAVE_SCHED_SETSCHEDULER) (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); #endif diff -u -r ntp-4.0.99k/ntpd/ntpd.c ntp-4.0.99k-jh/ntpd/ntpd.c --- ntp-4.0.99k/ntpd/ntpd.c Tue Jul 18 06:20:53 2000 +++ ntp-4.0.99k-jh/ntpd/ntpd.c Fri Feb 23 12:37:21 2001 @@ -68,6 +68,11 @@ # include #endif /* SYS_DOMAINOS */ +#include +#include +#include +#include + #include "ntpd.h" #include "ntp_io.h" @@ -130,6 +135,11 @@ int priority_done = 2; +/* Username to run as */ +char *server_user; +/* Chroot to this dir */ +char *chroot_dir; + /* * Debugging flag */ @@ -185,10 +195,60 @@ char *argv[] ) { + server_user = NULL; + chroot_dir = NULL; return ntpdmain(argc, argv); } #endif +/* This patch is adapted (copied) from Chris Wings drop root patch + * for xntpd. + */ +void drop_root(uid_t server_uid, gid_t server_gid) +{ + cap_t caps; + + if (prctl(PR_SET_KEEPCAPS, 1)) { + msyslog(LOG_ERR, "prctl(PR_SET_KEEPCAPS, 1) failed"); + exit(1); + } + + if ( setgroups(0, NULL) == -1 ) { + msyslog(LOG_ERR, "setgroups failed."); + exit(1); + } + + if ( setegid(server_gid) == -1 || seteuid(server_uid) == -1 ) { + msyslog(LOG_ERR, "setegid/seteuid to uid=%d/gid=%d failed.", server_uid, + server_gid); + exit(1); + } + + caps = cap_from_text("cap_sys_time=epi"); + if (caps == NULL) { + msyslog(LOG_ERR, "cap_from_text failed."); + exit(1); + } + + if (cap_set_proc(caps) == -1) { + msyslog(LOG_ERR, "cap_set_proc failed."); + exit(1); + } + + /* Try to free the memory from cap_from_text */ + cap_free( caps ); + + if ( setregid(server_gid, server_gid) == -1 || + setreuid(server_uid, server_uid) == -1 ) { + msyslog(LOG_ERR, "setregid/setreuid to uid=%d/gid=%d failed.", server_uid, + server_gid); + exit(1); + } + + msyslog(LOG_DEBUG, "running as uid(%d)/gid(%d) euid(%d)/egid(%d).", + getuid(), getgid(), geteuid(), getegid()); +} + #ifdef _AIX /* * OK. AIX is different than solaris in how it implements plock(). @@ -352,6 +412,9 @@ #ifdef _AIX /* HMS: ifdef SIGDANGER? */ struct sigaction sa; #endif + struct passwd *pwd = NULL; + uid_t server_uid; + gid_t server_gid; initializing = 1; /* mark that we are initializing */ debug = 0; /* no debugging by default */ @@ -392,6 +455,29 @@ #endif getstartup(argc, argv); /* startup configuration, may set debug */ + /* Lookup server_user uid/gid before chroot/chdir */ + if ( server_user ) { + pwd = getpwnam( server_user ); + if ( pwd == NULL ) { + msyslog(LOG_ERR, "Failed to lookup user '%s'.", server_user); + exit(1); + } + server_uid = pwd->pw_uid; + server_gid = pwd->pw_gid; + } + + /* Try to chroot to chroot_dir. This probably makes sense only if + * the server drops root privileges. + */ + if ( chroot_dir ) { + if ( chroot(chroot_dir) == -1 || chdir("/") == -1 ) { + msyslog(LOG_ERR, "chroot/chdir to '%s' failed.", chroot_dir); + exit(1); + } + /* Close /dev/log */ + closelog(); + } + /* * Initialize random generator and public key pair */ @@ -756,6 +842,10 @@ #endif /* PUBKEY */ #endif /* AUTOKEY */ initializing = 0; + + if ( server_user ) { + drop_root( server_uid, server_gid ); + } #if defined(SYS_WINNT) && !defined(NODETACH) # if defined(DEBUG)