1 /* $OpenBSD: ntp_dns.c,v 1.16 2015/12/19 17:55:29 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/resource.h> 21 #include <sys/time.h> 22 23 #include <err.h> 24 #include <errno.h> 25 #include <poll.h> 26 #include <fcntl.h> 27 #include <signal.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <syslog.h> 31 #include <unistd.h> 32 33 #include "ntpd.h" 34 35 volatile sig_atomic_t quit_dns = 0; 36 struct imsgbuf *ibuf_dns; 37 38 void sighdlr_dns(int); 39 int dns_dispatch_imsg(void); 40 41 void 42 sighdlr_dns(int sig) 43 { 44 switch (sig) { 45 case SIGTERM: 46 case SIGINT: 47 quit_dns = 1; 48 break; 49 } 50 } 51 52 pid_t 53 ntp_dns(int pipe_ntp[2], struct ntpd_conf *nconf, struct passwd *pw) 54 { 55 pid_t pid; 56 struct pollfd pfd[1]; 57 int nfds, nullfd; 58 59 switch (pid = fork()) { 60 case -1: 61 fatal("cannot fork"); 62 break; 63 case 0: 64 break; 65 default: 66 return (pid); 67 } 68 69 if (setpriority(PRIO_PROCESS, 0, 0) == -1) 70 log_warn("could not set priority"); 71 72 /* in this case the parent didn't init logging and didn't daemonize */ 73 if (nconf->settime && !nconf->debug) { 74 log_init(nconf->debug, LOG_DAEMON); 75 if (setsid() == -1) 76 fatal("setsid"); 77 } 78 log_procinit("dns"); 79 80 if ((nullfd = open("/dev/null", O_RDWR, 0)) == -1) 81 fatal(NULL); 82 83 if (!nconf->debug) { 84 dup2(nullfd, STDIN_FILENO); 85 dup2(nullfd, STDOUT_FILENO); 86 dup2(nullfd, STDERR_FILENO); 87 } 88 close(nullfd); 89 90 setproctitle("dns engine"); 91 92 close(pipe_ntp[0]); 93 94 if (setgroups(1, &pw->pw_gid) || 95 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 96 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 97 fatal("can't drop privileges"); 98 99 signal(SIGTERM, sighdlr_dns); 100 signal(SIGINT, sighdlr_dns); 101 signal(SIGHUP, SIG_IGN); 102 103 if ((ibuf_dns = malloc(sizeof(struct imsgbuf))) == NULL) 104 fatal(NULL); 105 imsg_init(ibuf_dns, pipe_ntp[1]); 106 107 if (pledge("stdio dns", NULL) == -1) 108 err(1, "pledge"); 109 110 while (quit_dns == 0) { 111 pfd[0].fd = ibuf_dns->fd; 112 pfd[0].events = POLLIN; 113 if (ibuf_dns->w.queued) 114 pfd[0].events |= POLLOUT; 115 116 if ((nfds = poll(pfd, 1, INFTIM)) == -1) 117 if (errno != EINTR) { 118 log_warn("poll error"); 119 quit_dns = 1; 120 } 121 122 if (nfds > 0 && (pfd[0].revents & POLLOUT)) 123 if (msgbuf_write(&ibuf_dns->w) <= 0 && 124 errno != EAGAIN) { 125 log_warn("pipe write error (to ntp engine)"); 126 quit_dns = 1; 127 } 128 129 if (nfds > 0 && pfd[0].revents & POLLIN) { 130 nfds--; 131 if (dns_dispatch_imsg() == -1) 132 quit_dns = 1; 133 } 134 } 135 136 msgbuf_clear(&ibuf_dns->w); 137 free(ibuf_dns); 138 _exit(0); 139 } 140 141 int 142 dns_dispatch_imsg(void) 143 { 144 struct imsg imsg; 145 int n, cnt; 146 char *name; 147 struct ntp_addr *h, *hn; 148 struct ibuf *buf; 149 const char *str; 150 151 if ((n = imsg_read(ibuf_dns)) == -1 && errno != EAGAIN) 152 return (-1); 153 154 if (n == 0) { /* connection closed */ 155 log_warnx("dispatch_imsg in main: pipe closed"); 156 return (-1); 157 } 158 159 for (;;) { 160 if ((n = imsg_get(ibuf_dns, &imsg)) == -1) 161 return (-1); 162 163 if (n == 0) 164 break; 165 166 switch (imsg.hdr.type) { 167 case IMSG_HOST_DNS: 168 case IMSG_CONSTRAINT_DNS: 169 if (imsg.hdr.type == IMSG_HOST_DNS) 170 str = "IMSG_HOST_DNS"; 171 else 172 str = "IMSG_CONSTRAINT_DNS"; 173 name = imsg.data; 174 if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE) 175 fatalx("invalid %s received", str); 176 imsg.hdr.len -= 1 + IMSG_HEADER_SIZE; 177 if (name[imsg.hdr.len] != '\0' || 178 strlen(name) != imsg.hdr.len) 179 fatalx("invalid %s received", str); 180 if ((cnt = host_dns(name, &hn)) == -1) 181 break; 182 buf = imsg_create(ibuf_dns, imsg.hdr.type, 183 imsg.hdr.peerid, 0, 184 cnt * sizeof(struct sockaddr_storage)); 185 if (cnt > 0) { 186 if (buf) { 187 for (h = hn; h != NULL; h = h->next) 188 if (imsg_add(buf, &h->ss, 189 sizeof(h->ss)) == -1) { 190 buf = NULL; 191 break; 192 } 193 } 194 host_dns_free(hn); 195 hn = NULL; 196 } 197 if (buf) 198 imsg_close(ibuf_dns, buf); 199 break; 200 default: 201 break; 202 } 203 imsg_free(&imsg); 204 } 205 return (0); 206 } 207