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