1 /* $OpenBSD: ypldap_dns.c,v 1.21 2024/11/21 13:38:15 claudio 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/socket.h> 21 #include <sys/stat.h> 22 #include <sys/time.h> 23 #include <sys/tree.h> 24 #include <sys/queue.h> 25 26 #include <netinet/in.h> 27 28 #include <netdb.h> 29 #include <pwd.h> 30 #include <errno.h> 31 #include <event.h> 32 #include <resolv.h> 33 #include <poll.h> 34 #include <signal.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <limits.h> 39 40 #include "ypldap.h" 41 #include "log.h" 42 43 volatile sig_atomic_t quit_dns = 0; 44 struct imsgev *iev_dns; 45 46 void dns_dispatch_imsg(int, short, void *); 47 void dns_sig_handler(int, short, void *); 48 void dns_shutdown(void); 49 int host_dns(const char *, struct ypldap_addr_list *); 50 51 void 52 dns_sig_handler(int sig, short event, void *p) 53 { 54 switch (sig) { 55 case SIGINT: 56 case SIGTERM: 57 dns_shutdown(); 58 break; 59 case SIGHUP: 60 /* ignore */ 61 break; 62 default: 63 fatalx("unexpected signal"); 64 } 65 } 66 67 void 68 dns_shutdown(void) 69 { 70 log_info("dns engine exiting"); 71 _exit(0); 72 } 73 74 pid_t 75 ypldap_dns(int pipe_ntp[2], struct passwd *pw) 76 { 77 pid_t pid; 78 struct event ev_sigint; 79 struct event ev_sigterm; 80 struct event ev_sighup; 81 struct env env; 82 83 switch (pid = fork()) { 84 case -1: 85 fatal("cannot fork"); 86 break; 87 case 0: 88 break; 89 default: 90 return (pid); 91 } 92 93 setproctitle("dns engine"); 94 close(pipe_ntp[0]); 95 96 if (setgroups(1, &pw->pw_gid) || 97 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 98 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 99 fatal("can't drop privileges"); 100 endservent(); 101 102 if (pledge("stdio dns", NULL) == -1) 103 fatal("pledge"); 104 105 event_init(); 106 signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL); 107 signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL); 108 signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL); 109 signal_add(&ev_sigint, NULL); 110 signal_add(&ev_sigterm, NULL); 111 signal_add(&ev_sighup, NULL); 112 113 if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) 114 fatal(NULL); 115 116 env.sc_iev->events = EV_READ; 117 env.sc_iev->data = &env; 118 if (imsgbuf_init(&env.sc_iev->ibuf, pipe_ntp[1]) == -1) 119 fatal(NULL); 120 env.sc_iev->handler = dns_dispatch_imsg; 121 event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, 122 env.sc_iev->handler, &env); 123 event_add(&env.sc_iev->ev, NULL); 124 125 event_dispatch(); 126 dns_shutdown(); 127 128 return (0); 129 } 130 131 void 132 dns_dispatch_imsg(int fd, short events, void *p) 133 { 134 struct imsg imsg; 135 int n, cnt; 136 char *name; 137 struct ypldap_addr_list hn = TAILQ_HEAD_INITIALIZER(hn); 138 struct ypldap_addr *h; 139 struct ibuf *buf; 140 struct env *env = p; 141 struct imsgev *iev = env->sc_iev; 142 struct imsgbuf *ibuf = &iev->ibuf; 143 int shut = 0; 144 size_t len; 145 146 if ((events & (EV_READ | EV_WRITE)) == 0) 147 fatalx("unknown event"); 148 149 if (events & EV_READ) { 150 if ((n = imsgbuf_read(ibuf)) == -1) 151 fatal("imsgbuf_read error"); 152 if (n == 0) 153 shut = 1; 154 } 155 if (events & EV_WRITE) { 156 if (imsgbuf_write(ibuf) == -1) { 157 if (errno == EPIPE) /* connection closed */ 158 shut = 1; 159 else 160 fatal("imsgbuf_write"); 161 } 162 } 163 164 for (;;) { 165 if ((n = imsg_get(ibuf, &imsg)) == -1) 166 fatal("client_dispatch_imsg: imsg_get error"); 167 if (n == 0) 168 break; 169 170 switch (imsg.hdr.type) { 171 case IMSG_HOST_DNS: 172 name = imsg.data; 173 if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE) 174 fatalx("invalid IMSG_HOST_DNS received"); 175 len = imsg.hdr.len - 1 - IMSG_HEADER_SIZE; 176 if (name[len] != '\0' || 177 strlen(name) != len) 178 fatalx("invalid IMSG_HOST_DNS received"); 179 if ((cnt = host_dns(name, &hn)) == -1) 180 break; 181 buf = imsg_create(ibuf, IMSG_HOST_DNS, 182 imsg.hdr.peerid, 0, 183 cnt * sizeof(struct sockaddr_storage)); 184 if (buf == NULL) 185 break; 186 if (cnt > 0) { 187 while (!TAILQ_EMPTY(&hn)) { 188 h = TAILQ_FIRST(&hn); 189 TAILQ_REMOVE(&hn, h, next); 190 imsg_add(buf, &h->ss, sizeof(h->ss)); 191 free(h); 192 } 193 } 194 195 imsg_close(ibuf, buf); 196 break; 197 default: 198 break; 199 } 200 imsg_free(&imsg); 201 } 202 203 if (!shut) 204 imsg_event_add(iev); 205 else { 206 /* this pipe is dead, so remove the event handler */ 207 event_del(&iev->ev); 208 event_loopexit(NULL); 209 } 210 } 211 212 int 213 host_dns(const char *s, struct ypldap_addr_list *hn) 214 { 215 struct addrinfo hints, *res0, *res; 216 int error, cnt = 0; 217 struct sockaddr_in *sa_in; 218 struct sockaddr_in6 *sa_in6; 219 struct ypldap_addr *h; 220 221 memset(&hints, 0, sizeof(hints)); 222 hints.ai_family = PF_UNSPEC; 223 hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ 224 error = getaddrinfo(s, NULL, &hints, &res0); 225 if (error != 0) { 226 log_warnx("could not resolve \"%s\": %s", s, 227 gai_strerror(error)); 228 if (error == EAI_AGAIN || error == EAI_NODATA || 229 error == EAI_NONAME) 230 return (0); 231 return (-1); 232 } 233 234 for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) { 235 if (res->ai_family != AF_INET && 236 res->ai_family != AF_INET6) 237 continue; 238 if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL) 239 fatal(NULL); 240 h->ss.ss_family = res->ai_family; 241 if (res->ai_family == AF_INET) { 242 sa_in = (struct sockaddr_in *)&h->ss; 243 sa_in->sin_len = sizeof(struct sockaddr_in); 244 sa_in->sin_addr.s_addr = ((struct sockaddr_in *) 245 res->ai_addr)->sin_addr.s_addr; 246 } else { 247 sa_in6 = (struct sockaddr_in6 *)&h->ss; 248 sa_in6->sin6_len = sizeof(struct sockaddr_in6); 249 memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *) 250 res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); 251 } 252 253 TAILQ_INSERT_HEAD(hn, h, next); 254 cnt++; 255 } 256 freeaddrinfo(res0); 257 return (cnt); 258 } 259