From: Juergen Perlinger Date: Sat, 14 Apr 2018 06:18:38 +0000 (+0200) Subject: [Bug 3121] Drop root privileges for the forked DNS worker X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ef980bd0a72bde20c7bef0838333c1fe999322ac;p=thirdparty%2Fntp.git [Bug 3121] Drop root privileges for the forked DNS worker bk: 5ad19d3eFgYJ5hqK3V8RCuVU28F74w --- diff --git a/ChangeLog b/ChangeLog index 6558787a9..323c27b8a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -27,6 +27,8 @@ - initial patch by Hal Murray; also fixed refclock_report() trouble * [Bug 3456] Use uintptr_t rather than size_t to store an integer in a pointer - According to Brooks Davis, there was only one location +* [Bug 3121] Drop root privileges for the forked DNS worker + - integrated patch by Reinhard Max * [Bug 2821] minor build issues - applied patches by Christos Zoulas, including real bug fixes diff --git a/libntp/work_fork.c b/libntp/work_fork.c index 2aa2d5cd3..cce686f23 100644 --- a/libntp/work_fork.c +++ b/libntp/work_fork.c @@ -89,6 +89,8 @@ netwrite( } +int set_user_group_ids(void); + /* === functions === */ /* * exit_worker() @@ -592,6 +594,8 @@ fork_blocking_child( init_logging("ntp_intres", 0, FALSE); setup_logfile(NULL); + (void) set_user_group_ids(); + /* * And now back to the portable code */ diff --git a/ntpd/ntpd.c b/ntpd/ntpd.c index d4204efd8..242d9f19e 100644 --- a/ntpd/ntpd.c +++ b/ntpd/ntpd.c @@ -182,7 +182,6 @@ char *group; /* group to switch to */ const char *chrootdir; /* directory to chroot to */ uid_t sw_uid; gid_t sw_gid; -char *endp; struct group *gr; struct passwd *pw; #endif /* HAVE_DROPROOT */ @@ -523,6 +522,217 @@ set_process_priority(void) } #endif /* !SIM */ +#ifndef SIM +/* + * Detach from terminal (much like daemon()) + * Nothe that this function calls exit() + */ +static void +detach_from_terminal( + int pipe_fds[2], + long wait_sync, + const char *logfilename + ) +{ + int rc; + int exit_code; +# if !defined(HAVE_SETSID) && !defined (HAVE_SETPGID) && defined(TIOCNOTTY) + int fid; +# endif +# ifdef _AIX + struct sigaction sa; +# endif + + rc = fork(); + if (-1 == rc) { + exit_code = (errno) ? errno : -1; + msyslog(LOG_ERR, "fork: %m"); + exit(exit_code); + } + if (rc > 0) { + /* parent */ + exit_code = wait_child_sync_if(pipe_fds[0], + wait_sync); + exit(exit_code); + } + + /* + * child/daemon + * close all open files excepting waitsync_fd_to_close. + * msyslog() unreliable until after init_logging(). + */ + closelog(); + if (syslog_file != NULL) { + fclose(syslog_file); + syslog_file = NULL; + syslogit = TRUE; + } + close_all_except(waitsync_fd_to_close); + INSIST(0 == open("/dev/null", 0) && 1 == dup2(0, 1) \ + && 2 == dup2(0, 2)); + + init_logging(progname, 0, TRUE); + /* we lost our logfile (if any) daemonizing */ + setup_logfile(logfilename); + +# ifdef SYS_DOMAINOS + { + uid_$t puid; + status_$t st; + + proc2_$who_am_i(&puid); + proc2_$make_server(&puid, &st); + } +# endif /* SYS_DOMAINOS */ +# ifdef HAVE_SETSID + if (setsid() == (pid_t)-1) + msyslog(LOG_ERR, "setsid(): %m"); +# elif defined(HAVE_SETPGID) + if (setpgid(0, 0) == -1) + msyslog(LOG_ERR, "setpgid(): %m"); +# else /* !HAVE_SETSID && !HAVE_SETPGID follows */ +# ifdef TIOCNOTTY + fid = open("/dev/tty", 2); + if (fid >= 0) { + ioctl(fid, (u_long)TIOCNOTTY, NULL); + close(fid); + } +# endif /* TIOCNOTTY */ + ntp_setpgrp(0, getpid()); +# endif /* !HAVE_SETSID && !HAVE_SETPGID */ +# ifdef _AIX + /* Don't get killed by low-on-memory signal. */ + sa.sa_handler = catch_danger; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGDANGER, &sa, NULL); +# endif /* _AIX */ + + return; +} + +/* + * Map user name/number to user ID +*/ +static int +map_user( + ) +{ + char *endp; + + if (isdigit((unsigned char)*user)) { + sw_uid = (uid_t)strtoul(user, &endp, 0); + if (*endp != '\0') + goto getuser; + + if ((pw = getpwuid(sw_uid)) != NULL) { + free(user); + user = estrdup(pw->pw_name); + sw_gid = pw->pw_gid; + } else { + errno = 0; + msyslog(LOG_ERR, "Cannot find user ID %s", user); + return 0; + } + + } else { +getuser: + errno = 0; + if ((pw = getpwnam(user)) != NULL) { + sw_uid = pw->pw_uid; + sw_gid = pw->pw_gid; + } else { + if (errno) + msyslog(LOG_ERR, "getpwnam(%s) failed: %m", user); + else + msyslog(LOG_ERR, "Cannot find user `%s'", user); + return 0; + } + } + + return 1; +} + +/* + * Map group name/number to group ID +*/ +static int +map_group( + ) +{ + char *endp; + + if (isdigit((unsigned char)*group)) { + sw_gid = (gid_t)strtoul(group, &endp, 0); + if (*endp != '\0') + goto getgroup; + } else { +getgroup: + if ((gr = getgrnam(group)) != NULL) { + sw_gid = gr->gr_gid; + } else { + errno = 0; + msyslog(LOG_ERR, "Cannot find group `%s'", group); + return 0; + } + } + + return 1; +} + +/* + * Change (effective) user and group IDs, also initialize the supplementary group access list + */ +int +set_user_group_ids( + ) +{ + /* If the the user was already mapped, no need to map it again */ + if ((NULL != user) && (0 == sw_uid)) { + if (0 == map_user()) + exit (-1); + } + /* same applies for the group */ + if ((NULL != group) && (0 == sw_gid)) { + if (0 == map_group()) + exit (-1); + } + + if (user && initgroups(user, sw_gid)) { + msyslog(LOG_ERR, "Cannot initgroups() to user `%s': %m", user); + return 0; + } + if (group && setgid(sw_gid)) { + msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group); + return 0; + } + if (group && setegid(sw_gid)) { + msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group); + return 0; + } + if (group) { + if (0 != setgroups(1, &sw_gid)) { + msyslog(LOG_ERR, "setgroups(1, %d) failed: %m", sw_gid); + return 0; + } + } + else if (pw) + if (0 != initgroups(pw->pw_name, pw->pw_gid)) { + msyslog(LOG_ERR, "initgroups(<%s>, %d) filed: %m", pw->pw_name, pw->pw_gid); + return 0; + } + if (user && setuid(sw_uid)) { + msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user); + return 0; + } + if (user && seteuid(sw_uid)) { + msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user); + return 0; + } + + return 1; +} +#endif /* !SIM */ /* * Main program. Initialize us, disconnect us from the tty if necessary, @@ -549,12 +759,6 @@ ntpdmain( int pipe_fds[2]; int rc; int exit_code; -# ifdef _AIX - struct sigaction sa; -# endif -# if !defined(HAVE_SETSID) && !defined (HAVE_SETPGID) && defined(TIOCNOTTY) - int fid; -# endif # endif /* HAVE_WORKING_FORK*/ # ifdef SCO5_CLOCK int fd; @@ -736,70 +940,7 @@ ntpdmain( if (!nofork) { # ifdef HAVE_WORKING_FORK - rc = fork(); - if (-1 == rc) { - exit_code = (errno) ? errno : -1; - msyslog(LOG_ERR, "fork: %m"); - exit(exit_code); - } - if (rc > 0) { - /* parent */ - exit_code = wait_child_sync_if(pipe_fds[0], - wait_sync); - exit(exit_code); - } - - /* - * child/daemon - * close all open files excepting waitsync_fd_to_close. - * msyslog() unreliable until after init_logging(). - */ - closelog(); - if (syslog_file != NULL) { - fclose(syslog_file); - syslog_file = NULL; - syslogit = TRUE; - } - close_all_except(waitsync_fd_to_close); - INSIST(0 == open("/dev/null", 0) && 1 == dup2(0, 1) \ - && 2 == dup2(0, 2)); - - init_logging(progname, 0, TRUE); - /* we lost our logfile (if any) daemonizing */ - setup_logfile(logfilename); - -# ifdef SYS_DOMAINOS - { - uid_$t puid; - status_$t st; - - proc2_$who_am_i(&puid); - proc2_$make_server(&puid, &st); - } -# endif /* SYS_DOMAINOS */ -# ifdef HAVE_SETSID - if (setsid() == (pid_t)-1) - msyslog(LOG_ERR, "setsid(): %m"); -# elif defined(HAVE_SETPGID) - if (setpgid(0, 0) == -1) - msyslog(LOG_ERR, "setpgid(): %m"); -# else /* !HAVE_SETSID && !HAVE_SETPGID follows */ -# ifdef TIOCNOTTY - fid = open("/dev/tty", 2); - if (fid >= 0) { - ioctl(fid, (u_long)TIOCNOTTY, NULL); - close(fid); - } -# endif /* TIOCNOTTY */ - ntp_setpgrp(0, getpid()); -# endif /* !HAVE_SETSID && !HAVE_SETPGID */ -# ifdef _AIX - /* Don't get killed by low-on-memory signal. */ - sa.sa_handler = catch_danger; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction(SIGDANGER, &sa, NULL); -# endif /* _AIX */ + detach_from_terminal(pipe_fds, wait_sync, logfilename); # endif /* HAVE_WORKING_FORK */ } @@ -972,51 +1113,12 @@ ntpdmain( # endif /* HAVE_LINUX_CAPABILITIES || HAVE_SOLARIS_PRIVS */ if (user != NULL) { - if (isdigit((unsigned char)*user)) { - sw_uid = (uid_t)strtoul(user, &endp, 0); - if (*endp != '\0') - goto getuser; - - if ((pw = getpwuid(sw_uid)) != NULL) { - free(user); - user = estrdup(pw->pw_name); - sw_gid = pw->pw_gid; - } else { - errno = 0; - msyslog(LOG_ERR, "Cannot find user ID %s", user); - exit (-1); - } - - } else { -getuser: - errno = 0; - if ((pw = getpwnam(user)) != NULL) { - sw_uid = pw->pw_uid; - sw_gid = pw->pw_gid; - } else { - if (errno) - msyslog(LOG_ERR, "getpwnam(%s) failed: %m", user); - else - msyslog(LOG_ERR, "Cannot find user `%s'", user); - exit (-1); - } - } + if (0 == map_user()) + exit (-1); } if (group != NULL) { - if (isdigit((unsigned char)*group)) { - sw_gid = (gid_t)strtoul(group, &endp, 0); - if (*endp != '\0') - goto getgroup; - } else { -getgroup: - if ((gr = getgrnam(group)) != NULL) { - sw_gid = gr->gr_gid; - } else { - errno = 0; - msyslog(LOG_ERR, "Cannot find group `%s'", group); - exit (-1); - } - } + if (0 == map_group()) + exit (-1); } if (chrootdir ) { @@ -1050,37 +1152,8 @@ getgroup: exit(-1); } # endif /* HAVE_SOLARIS_PRIVS */ - if (user && initgroups(user, sw_gid)) { - msyslog(LOG_ERR, "Cannot initgroups() to user `%s': %m", user); - exit (-1); - } - if (group && setgid(sw_gid)) { - msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group); - exit (-1); - } - if (group && setegid(sw_gid)) { - msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group); - exit (-1); - } - if (group) { - if (0 != setgroups(1, &sw_gid)) { - msyslog(LOG_ERR, "setgroups(1, %d) failed: %m", sw_gid); - exit (-1); - } - } - else if (pw) - if (0 != initgroups(pw->pw_name, pw->pw_gid)) { - msyslog(LOG_ERR, "initgroups(<%s>, %d) filed: %m", pw->pw_name, pw->pw_gid); - exit (-1); - } - if (user && setuid(sw_uid)) { - msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user); - exit (-1); - } - if (user && seteuid(sw_uid)) { - msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user); - exit (-1); - } + if (0 == set_user_group_ids()) + exit(-1); # if !defined(HAVE_LINUX_CAPABILITIES) && !defined(HAVE_SOLARIS_PRIVS) /* diff --git a/sntp/main.c b/sntp/main.c index 098a69694..f0a7650ac 100644 --- a/sntp/main.c +++ b/sntp/main.c @@ -1608,3 +1608,10 @@ gettimeofday_cached( #endif } +/* Dummy function to satisfy libntp/work_fork.c */ +int +set_user_group_ids( + ) +{ + return 1; +}