Browse Source

Teach ntpd(8) how to fork+exec.

ok reyk@, bcook@
OPENBSD_6_1
rzalamena 7 years ago
parent
commit
1305c0d5de
6 changed files with 142 additions and 57 deletions
  1. +2
    -2
      src/usr.sbin/ntpd/control.c
  2. +16
    -22
      src/usr.sbin/ntpd/ntp.c
  3. +5
    -18
      src/usr.sbin/ntpd/ntp_dns.c
  4. +29
    -11
      src/usr.sbin/ntpd/ntpd.c
  5. +10
    -3
      src/usr.sbin/ntpd/ntpd.h
  6. +80
    -1
      src/usr.sbin/ntpd/util.c

+ 2
- 2
src/usr.sbin/ntpd/control.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: control.c,v 1.10 2016/03/27 11:16:12 krw Exp $ */
/* $OpenBSD: control.c,v 1.11 2016/09/14 13:20:16 rzalamena Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -43,7 +43,7 @@ control_init(char *path)
int fd;
mode_t old_umask;
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) {
log_warn("control_init: socket");
return (-1);
}


+ 16
- 22
src/usr.sbin/ntpd/ntp.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: ntp.c,v 1.142 2016/09/03 11:52:06 reyk Exp $ */
/* $OpenBSD: ntp.c,v 1.143 2016/09/14 13:20:16 rzalamena Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -66,17 +66,16 @@ ntp_sighdlr(int sig)
}
}
pid_t
ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
struct passwd *pw)
void
ntp_main(struct ntpd_conf *nconf, struct passwd *pw, int argc, char **argv)
{
int a, b, nfds, i, j, idx_peers, timeout;
int nullfd, pipe_dns[2], idx_clients;
int ctls;
int fd_ctl;
u_int pfd_elms = 0, idx2peer_elms = 0;
u_int listener_cnt, new_cnt, sent_cnt, trial_cnt;
u_int ctl_cnt;
pid_t pid;
struct pollfd *pfd = NULL;
struct servent *se;
struct listen_addr *la;
@ -90,15 +89,11 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
time_t nextaction, last_sensor_scan = 0, now;
void *newp;
switch (pid = fork()) {
case -1:
fatal("cannot fork");
break;
case 0:
break;
default:
return (pid);
}
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNSPEC,
pipe_dns) == -1)
fatal("socketpair");
start_child(NTPDNS_PROC_NAME, pipe_dns[1], argc, argv);
/* in this case the parent didn't init logging and didn't daemonize */
if (nconf->settime && !nconf->debug) {
@ -111,15 +106,14 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
if ((se = getservbyname("ntp", "udp")) == NULL)
fatal("getservbyname");
/* Start control socket. */
if ((fd_ctl = control_init(CTLSOCKET)) == -1)
fatalx("control socket init failed");
if (control_listen(fd_ctl) == -1)
fatalx("control socket listen failed");
if ((nullfd = open("/dev/null", O_RDWR, 0)) == -1)
fatal(NULL);
close(pipe_prnt[0]);
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_dns) == -1)
fatal("socketpair");
ntp_dns(pipe_dns, nconf, pw);
close(pipe_dns[1]);
if (stat(pw->pw_dir, &stb) == -1) {
fatal("privsep dir %s could not be opened", pw->pw_dir);
}
@ -163,7 +157,7 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
fatal(NULL);
imsg_init(ibuf_main, pipe_prnt[1]);
imsg_init(ibuf_main, PARENT_SOCK_FILENO);
if ((ibuf_dns = malloc(sizeof(struct imsgbuf))) == NULL)
fatal(NULL);
imsg_init(ibuf_dns, pipe_dns[0]);
@ -422,7 +416,7 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
free(ibuf_dns);
log_info("ntp engine exiting");
_exit(0);
exit(0);
}
int


+ 5
- 18
src/usr.sbin/ntpd/ntp_dns.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: ntp_dns.c,v 1.17 2016/09/03 11:52:06 reyk Exp $ */
/* $OpenBSD: ntp_dns.c,v 1.18 2016/09/14 13:20:16 rzalamena Exp $ */
/*
* Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org>
@ -49,23 +49,12 @@ sighdlr_dns(int sig)
}
}
pid_t
ntp_dns(int pipe_ntp[2], struct ntpd_conf *nconf, struct passwd *pw)
void
ntp_dns(struct ntpd_conf *nconf, struct passwd *pw)
{
pid_t pid;
struct pollfd pfd[1];
int nfds, nullfd;
switch (pid = fork()) {
case -1:
fatal("cannot fork");
break;
case 0:
break;
default:
return (pid);
}
if (setpriority(PRIO_PROCESS, 0, 0) == -1)
log_warn("could not set priority");
@ -89,8 +78,6 @@ ntp_dns(int pipe_ntp[2], struct ntpd_conf *nconf, struct passwd *pw)
setproctitle("dns engine");
close(pipe_ntp[0]);
if (setgroups(1, &pw->pw_gid) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
@ -102,7 +89,7 @@ ntp_dns(int pipe_ntp[2], struct ntpd_conf *nconf, struct passwd *pw)
if ((ibuf_dns = malloc(sizeof(struct imsgbuf))) == NULL)
fatal(NULL);
imsg_init(ibuf_dns, pipe_ntp[1]);
imsg_init(ibuf_dns, PARENT_SOCK_FILENO);
if (pledge("stdio dns", NULL) == -1)
err(1, "pledge");
@ -135,7 +122,7 @@ ntp_dns(int pipe_ntp[2], struct ntpd_conf *nconf, struct passwd *pw)
msgbuf_clear(&ibuf_dns->w);
free(ibuf_dns);
_exit(0);
exit(0);
}
int


+ 29
- 11
src/usr.sbin/ntpd/ntpd.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: ntpd.c,v 1.108 2016/09/03 11:52:06 reyk Exp $ */
/* $OpenBSD: ntpd.c,v 1.109 2016/09/14 13:20:16 rzalamena Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -112,7 +112,7 @@ main(int argc, char *argv[])
struct pollfd *pfd = NULL;
pid_t chld_pid = 0, pid;
const char *conffile;
int fd_ctl, ch, nfds, i, j;
int ch, nfds, i, j;
int pipe_chld[2];
extern char *__progname;
u_int pfd_elms = 0, new_cnt;
@ -122,6 +122,9 @@ main(int argc, char *argv[])
uid_t pw_uid;
gid_t pw_gid;
void *newp;
int argc0 = argc;
char **argv0 = argv;
char *pname = NULL;
if (strcmp(__progname, "ntpctl") == 0) {
ctl_main(argc, argv);
@ -132,7 +135,7 @@ main(int argc, char *argv[])
memset(&lconf, 0, sizeof(lconf));
while ((ch = getopt(argc, argv, "df:nsSv")) != -1) {
while ((ch = getopt(argc, argv, "df:nP:sSv")) != -1) {
switch (ch) {
case 'd':
lconf.debug = 2;
@ -144,6 +147,9 @@ main(int argc, char *argv[])
lconf.debug = 2;
lconf.noaction = 1;
break;
case 'P':
pname = optarg;
break;
case 's':
lconf.settime = 1;
break;
@ -181,6 +187,22 @@ main(int argc, char *argv[])
if ((pw = getpwnam(NTPD_USER)) == NULL)
errx(1, "unknown user %s", NTPD_USER);
if (pname != NULL) {
/* Remove our proc arguments, so child doesn't need to. */
if (sanitize_argv(&argc0, &argv0) == -1)
fatalx("sanitize_argv");
if (strcmp(NTP_PROC_NAME, pname) == 0)
ntp_main(&lconf, pw, argc0, argv0);
else if (strcmp(NTPDNS_PROC_NAME, pname) == 0)
ntp_dns(&lconf, pw);
else
fatalx("%s: invalid process name '%s'", __func__,
pname);
fatalx("%s: process '%s' failed", __func__, pname);
}
pw_dir = strdup(pw->pw_dir);
pw_uid = pw->pw_uid;
pw_gid = pw->pw_gid;
@ -198,17 +220,14 @@ main(int argc, char *argv[])
} else
timeout = SETTIME_TIMEOUT * 1000;
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_chld) == -1)
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNSPEC,
pipe_chld) == -1)
fatal("socketpair");
if ((fd_ctl = control_init(CTLSOCKET)) == -1)
fatalx("control socket init failed");
if (control_listen(fd_ctl) == -1)
fatalx("control socket listen failed");
signal(SIGCHLD, sighdlr);
/* fork child process */
chld_pid = ntp_main(pipe_chld, fd_ctl, &lconf, pw);
chld_pid = start_child(NTP_PROC_NAME, pipe_chld[1], argc0, argv0);
log_procinit("[priv]");
readfreq();
@ -217,7 +236,6 @@ main(int argc, char *argv[])
signal(SIGINT, sighdlr);
signal(SIGHUP, sighdlr);
close(pipe_chld[1]);
constraint_purge();
if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)


+ 10
- 3
src/usr.sbin/ntpd/ntpd.h View File

@ -1,4 +1,4 @@
/* $OpenBSD: ntpd.h,v 1.131 2016/09/03 11:52:06 reyk Exp $ */
/* $OpenBSD: ntpd.h,v 1.132 2016/09/14 13:20:16 rzalamena Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -82,6 +82,11 @@
#define CONSTRAINT_PASSFD (STDERR_FILENO + 1)
#define CONSTRAINT_CA "/etc/ssl/cert.pem"
#define PARENT_SOCK_FILENO 3
#define NTP_PROC_NAME "ntp_main"
#define NTPDNS_PROC_NAME "ntp_dns"
enum client_state {
STATE_NONE,
STATE_DNS_INPROGRESS,
@ -302,7 +307,7 @@ enum ctl_actions {
/* prototypes */
/* ntp.c */
pid_t ntp_main(int[2], int, struct ntpd_conf *, struct passwd *);
void ntp_main(struct ntpd_conf *, struct passwd *, int, char **);
int priv_adjtime(void);
void priv_settime(double);
void priv_dns(int, char *, u_int32_t);
@ -372,6 +377,8 @@ double sfp_to_d(struct s_fixedpt);
struct s_fixedpt d_to_sfp(double);
char *print_rtable(int);
const char *log_sockaddr(struct sockaddr *);
pid_t start_child(char *, int, int, char **);
int sanitize_argv(int *, char ***);
/* sensors.c */
void sensor_init(void);
@ -379,7 +386,7 @@ int sensor_scan(void);
void sensor_query(struct ntp_sensor *);
/* ntp_dns.c */
pid_t ntp_dns(int[2], struct ntpd_conf *, struct passwd *);
void ntp_dns(struct ntpd_conf *, struct passwd *);
/* control.c */
int control_init(char *);


+ 80
- 1
src/usr.sbin/ntpd/util.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: util.c,v 1.21 2016/09/14 08:24:08 reyk Exp $ */
/* $OpenBSD: util.c,v 1.22 2016/09/14 13:20:16 rzalamena Exp $ */
/*
* Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org>
@ -18,7 +18,9 @@
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "ntpd.h"
@ -151,3 +153,80 @@ log_sockaddr(struct sockaddr *sa)
else
return (buf);
}
pid_t
start_child(char *pname, int cfd, int argc, char **argv)
{
char **nargv;
int nargc, i;
pid_t pid;
/* Prepare the child process new argv. */
nargv = calloc(argc + 3, sizeof(char *));
if (nargv == NULL)
fatal("%s: calloc", __func__);
/* Copy the program name first. */
nargc = 0;
nargv[nargc++] = argv[0];
/* Set the process name and copy the original args. */
nargv[nargc++] = "-P";
nargv[nargc++] = pname;
for (i = 1; i < argc; i++)
nargv[nargc++] = argv[i];
nargv[nargc] = 0;
switch (pid = fork()) {
case -1:
fatal("%s: fork", __func__);
break;
case 0:
/* Prepare the parent socket and execute. */
dup2(cfd, PARENT_SOCK_FILENO);
execvp(argv[0], nargv);
fatal("%s: execvp", __func__);
break;
default:
/* Close child's socket end. */
close(cfd);
break;
}
free(nargv);
return (pid);
}
int
sanitize_argv(int *argc, char ***argv)
{
char **nargv;
int nargc;
int i;
/*
* We need at least three arguments:
* Example: '/usr/sbin/ntpd' '-P' 'foobar'.
*/
if (*argc < 3)
return (-1);
*argc -= 2;
/* Allocate new arguments vector and copy pointers. */
nargv = calloc((*argc) + 1, sizeof(char *));
if (nargv == NULL)
return (-1);
nargc = 0;
nargv[nargc++] = (*argv)[0];
for (i = 1; i < *argc; i++)
nargv[nargc++] = (*argv)[i + 2];
nargv[nargc] = NULL;
*argv = nargv;
return (0);
}

Loading…
Cancel
Save