ypldap_dns.c revision 290931
1169689Skan/* $OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */ 2169689Skan/* $FreeBSD: head/usr.sbin/ypldap/ypldap_dns.c 290931 2015-11-16 16:48:43Z rodrigc $ */ 3169689Skan 4169689Skan/* 5169689Skan * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org> 6169689Skan * 7169689Skan * Permission to use, copy, modify, and distribute this software for any 8169689Skan * purpose with or without fee is hereby granted, provided that the above 9169689Skan * copyright notice and this permission notice appear in all copies. 10169689Skan * 11169689Skan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12169689Skan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13169689Skan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14169689Skan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15169689Skan * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 16169689Skan * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 17169689Skan * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18169689Skan */ 19169689Skan 20169689Skan#include <sys/types.h> 21169689Skan#include <sys/socket.h> 22169689Skan#include <sys/stat.h> 23169689Skan#include <sys/time.h> 24169689Skan#include <sys/tree.h> 25169689Skan#include <sys/queue.h> 26169689Skan 27169689Skan#include <netinet/in.h> 28169689Skan#include <arpa/nameser.h> 29169689Skan 30169689Skan#include <netdb.h> 31169689Skan#include <pwd.h> 32169689Skan#include <errno.h> 33169689Skan#include <event.h> 34169689Skan#include <resolv.h> 35169689Skan#include <poll.h> 36169689Skan#include <signal.h> 37169689Skan#include <stdlib.h> 38169689Skan#include <string.h> 39169689Skan#include <unistd.h> 40169689Skan#include <limits.h> 41169689Skan 42169689Skan#include "ypldap.h" 43169689Skan 44169689Skanvolatile sig_atomic_t quit_dns = 0; 45169689Skanstruct imsgev *iev_dns; 46169689Skan 47169689Skanvoid dns_dispatch_imsg(int, short, void *); 48169689Skanvoid dns_sig_handler(int, short, void *); 49169689Skanvoid dns_shutdown(void); 50169689Skanint host_dns(const char *s, struct ypldap_addr **hn); 51169689Skan 52169689Skanvoid 53169689Skandns_sig_handler(int sig, short event, void *p) 54169689Skan{ 55169689Skan switch (sig) { 56169689Skan case SIGINT: 57169689Skan case SIGTERM: 58169689Skan dns_shutdown(); 59169689Skan break; 60169689Skan default: 61169689Skan fatalx("unexpected signal"); 62169689Skan } 63169689Skan} 64169689Skan 65169689Skanvoid 66169689Skandns_shutdown(void) 67169689Skan{ 68169689Skan log_info("dns engine exiting"); 69169689Skan _exit(0); 70169689Skan} 71169689Skan 72169689Skanpid_t 73169689Skanypldap_dns(int pipe_ntp[2], struct passwd *pw) 74169689Skan{ 75169689Skan pid_t pid; 76169689Skan struct event ev_sigint; 77169689Skan struct event ev_sigterm; 78169689Skan struct event ev_sighup; 79169689Skan struct env env; 80169689Skan 81169689Skan switch (pid = fork()) { 82169689Skan case -1: 83169689Skan fatal("cannot fork"); 84169689Skan break; 85169689Skan case 0: 86 break; 87 default: 88 return (pid); 89 } 90 91 setproctitle("dns engine"); 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 endservent(); 99 100 event_init(); 101 signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL); 102 signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL); 103 signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL); 104 signal_add(&ev_sigint, NULL); 105 signal_add(&ev_sigterm, NULL); 106 signal_add(&ev_sighup, NULL); 107 108 if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) 109 fatal(NULL); 110 111 env.sc_iev->events = EV_READ; 112 env.sc_iev->data = &env; 113 imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]); 114 env.sc_iev->handler = dns_dispatch_imsg; 115 event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, 116 env.sc_iev->handler, &env); 117 event_add(&env.sc_iev->ev, NULL); 118 119 event_dispatch(); 120 dns_shutdown(); 121 122 return (0); 123} 124 125void 126dns_dispatch_imsg(int fd, short events, void *p) 127{ 128 struct imsg imsg; 129 int n, cnt; 130 char *name; 131 struct ypldap_addr *h, *hn; 132 struct ibuf *buf; 133 struct env *env = p; 134 struct imsgev *iev = env->sc_iev; 135 struct imsgbuf *ibuf = &iev->ibuf; 136 int shut = 0; 137 138 if ((events & (EV_READ | EV_WRITE)) == 0) 139 fatalx("unknown event"); 140 141 if (events & EV_READ) { 142 if ((n = imsg_read(ibuf)) == -1) 143 fatal("imsg_read error"); 144 if (n == 0) 145 shut = 1; 146 } 147 if (events & EV_WRITE) { 148 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 149 fatal("msgbuf_write"); 150 if (n == 0) 151 shut = 1; 152 goto done; 153 } 154 155 for (;;) { 156 if ((n = imsg_get(ibuf, &imsg)) == -1) 157 fatal("client_dispatch_imsg: imsg_get error"); 158 if (n == 0) 159 break; 160 161 switch (imsg.hdr.type) { 162 case IMSG_HOST_DNS: 163 name = imsg.data; 164 if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE) 165 fatalx("invalid IMSG_HOST_DNS received"); 166 imsg.hdr.len -= 1 + IMSG_HEADER_SIZE; 167 if (name[imsg.hdr.len] != '\0' || 168 strlen(name) != imsg.hdr.len) 169 fatalx("invalid IMSG_HOST_DNS received"); 170 if ((cnt = host_dns(name, &hn)) == -1) 171 break; 172 buf = imsg_create(ibuf, IMSG_HOST_DNS, 173 imsg.hdr.peerid, 0, 174 cnt * sizeof(struct sockaddr_storage)); 175 if (buf == NULL) 176 break; 177 if (cnt > 0) { 178 h = hn; 179 while (h != NULL) { 180 imsg_add(buf, &h->ss, sizeof(h->ss)); 181 hn = h->next; 182 free(h); 183 h = hn; 184 } 185 } 186 187 imsg_close(ibuf, buf); 188 break; 189 default: 190 break; 191 } 192 imsg_free(&imsg); 193 } 194 195done: 196 if (!shut) 197 imsg_event_add(iev); 198 else { 199 /* this pipe is dead, so remove the event handler */ 200 event_del(&iev->ev); 201 event_loopexit(NULL); 202 } 203} 204 205int 206host_dns(const char *s, struct ypldap_addr **hn) 207{ 208 struct addrinfo hints, *res0, *res; 209 int error, cnt = 0; 210 struct sockaddr_in *sa_in; 211 struct sockaddr_in6 *sa_in6; 212 struct ypldap_addr *h, *hh = NULL; 213 214 bzero(&hints, sizeof(hints)); 215 hints.ai_family = PF_UNSPEC; 216 hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ 217 error = getaddrinfo(s, NULL, &hints, &res0); 218 if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME) 219 return (0); 220 if (error) { 221 log_warnx("could not parse \"%s\": %s", s, 222 gai_strerror(error)); 223 return (-1); 224 } 225 226 for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) { 227 if (res->ai_family != AF_INET && 228 res->ai_family != AF_INET6) 229 continue; 230 if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL) 231 fatal(NULL); 232 h->ss.ss_family = res->ai_family; 233 if (res->ai_family == AF_INET) { 234 sa_in = (struct sockaddr_in *)&h->ss; 235 sa_in->sin_len = sizeof(struct sockaddr_in); 236 sa_in->sin_addr.s_addr = ((struct sockaddr_in *) 237 res->ai_addr)->sin_addr.s_addr; 238 } else { 239 sa_in6 = (struct sockaddr_in6 *)&h->ss; 240 sa_in6->sin6_len = sizeof(struct sockaddr_in6); 241 memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *) 242 res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); 243 } 244 245 h->next = hh; 246 hh = h; 247 cnt++; 248 } 249 freeaddrinfo(res0); 250 251 *hn = hh; 252 return (cnt); 253} 254