19e7c127fSCraig Rodrigues /* $OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */
29e7c127fSCraig Rodrigues
39e7c127fSCraig Rodrigues /*
49e7c127fSCraig Rodrigues * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org>
59e7c127fSCraig Rodrigues *
69e7c127fSCraig Rodrigues * Permission to use, copy, modify, and distribute this software for any
79e7c127fSCraig Rodrigues * purpose with or without fee is hereby granted, provided that the above
89e7c127fSCraig Rodrigues * copyright notice and this permission notice appear in all copies.
99e7c127fSCraig Rodrigues *
109e7c127fSCraig Rodrigues * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
119e7c127fSCraig Rodrigues * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
129e7c127fSCraig Rodrigues * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
139e7c127fSCraig Rodrigues * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
149e7c127fSCraig Rodrigues * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
159e7c127fSCraig Rodrigues * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
169e7c127fSCraig Rodrigues * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
179e7c127fSCraig Rodrigues */
189e7c127fSCraig Rodrigues
199e7c127fSCraig Rodrigues #include <sys/types.h>
2066b5c05dSCraig Rodrigues #include <sys/param.h>
219e7c127fSCraig Rodrigues #include <sys/socket.h>
229e7c127fSCraig Rodrigues #include <sys/stat.h>
239e7c127fSCraig Rodrigues #include <sys/time.h>
249e7c127fSCraig Rodrigues #include <sys/tree.h>
259e7c127fSCraig Rodrigues #include <sys/queue.h>
269e7c127fSCraig Rodrigues
279e7c127fSCraig Rodrigues #include <netinet/in.h>
289e7c127fSCraig Rodrigues #include <arpa/nameser.h>
299e7c127fSCraig Rodrigues
309e7c127fSCraig Rodrigues #include <netdb.h>
319e7c127fSCraig Rodrigues #include <pwd.h>
329e7c127fSCraig Rodrigues #include <errno.h>
339e7c127fSCraig Rodrigues #include <event.h>
349e7c127fSCraig Rodrigues #include <resolv.h>
359e7c127fSCraig Rodrigues #include <poll.h>
369e7c127fSCraig Rodrigues #include <signal.h>
379e7c127fSCraig Rodrigues #include <stdlib.h>
389e7c127fSCraig Rodrigues #include <string.h>
399e7c127fSCraig Rodrigues #include <unistd.h>
409e7c127fSCraig Rodrigues #include <limits.h>
419e7c127fSCraig Rodrigues
429e7c127fSCraig Rodrigues #include "ypldap.h"
439e7c127fSCraig Rodrigues
449e7c127fSCraig Rodrigues volatile sig_atomic_t quit_dns = 0;
459e7c127fSCraig Rodrigues struct imsgev *iev_dns;
469e7c127fSCraig Rodrigues
479e7c127fSCraig Rodrigues void dns_dispatch_imsg(int, short, void *);
489e7c127fSCraig Rodrigues void dns_sig_handler(int, short, void *);
499e7c127fSCraig Rodrigues void dns_shutdown(void);
50eaf209deSMarcelo Araujo int host_dns(const char *, struct ypldap_addr_list *);
519e7c127fSCraig Rodrigues
529e7c127fSCraig Rodrigues void
dns_sig_handler(int sig,short event,void * p)539e7c127fSCraig Rodrigues dns_sig_handler(int sig, short event, void *p)
549e7c127fSCraig Rodrigues {
559e7c127fSCraig Rodrigues switch (sig) {
569e7c127fSCraig Rodrigues case SIGINT:
579e7c127fSCraig Rodrigues case SIGTERM:
589e7c127fSCraig Rodrigues dns_shutdown();
599e7c127fSCraig Rodrigues break;
609e7c127fSCraig Rodrigues default:
619e7c127fSCraig Rodrigues fatalx("unexpected signal");
629e7c127fSCraig Rodrigues }
639e7c127fSCraig Rodrigues }
649e7c127fSCraig Rodrigues
659e7c127fSCraig Rodrigues void
dns_shutdown(void)669e7c127fSCraig Rodrigues dns_shutdown(void)
679e7c127fSCraig Rodrigues {
689e7c127fSCraig Rodrigues log_info("dns engine exiting");
699e7c127fSCraig Rodrigues _exit(0);
709e7c127fSCraig Rodrigues }
719e7c127fSCraig Rodrigues
729e7c127fSCraig Rodrigues pid_t
ypldap_dns(int pipe_ntp[2],struct passwd * pw)739e7c127fSCraig Rodrigues ypldap_dns(int pipe_ntp[2], struct passwd *pw)
749e7c127fSCraig Rodrigues {
759e7c127fSCraig Rodrigues pid_t pid;
769e7c127fSCraig Rodrigues struct event ev_sigint;
779e7c127fSCraig Rodrigues struct event ev_sigterm;
789e7c127fSCraig Rodrigues struct event ev_sighup;
799e7c127fSCraig Rodrigues struct env env;
809e7c127fSCraig Rodrigues
819e7c127fSCraig Rodrigues switch (pid = fork()) {
829e7c127fSCraig Rodrigues case -1:
839e7c127fSCraig Rodrigues fatal("cannot fork");
849e7c127fSCraig Rodrigues break;
859e7c127fSCraig Rodrigues case 0:
869e7c127fSCraig Rodrigues break;
879e7c127fSCraig Rodrigues default:
889e7c127fSCraig Rodrigues return (pid);
899e7c127fSCraig Rodrigues }
909e7c127fSCraig Rodrigues
919e7c127fSCraig Rodrigues setproctitle("dns engine");
929e7c127fSCraig Rodrigues close(pipe_ntp[0]);
939e7c127fSCraig Rodrigues
949e7c127fSCraig Rodrigues if (setgroups(1, &pw->pw_gid) ||
959e7c127fSCraig Rodrigues setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
969e7c127fSCraig Rodrigues setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
979e7c127fSCraig Rodrigues fatal("can't drop privileges");
989e7c127fSCraig Rodrigues endservent();
999e7c127fSCraig Rodrigues
1009e7c127fSCraig Rodrigues event_init();
1019e7c127fSCraig Rodrigues signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL);
1029e7c127fSCraig Rodrigues signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL);
1039e7c127fSCraig Rodrigues signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL);
1049e7c127fSCraig Rodrigues signal_add(&ev_sigint, NULL);
1059e7c127fSCraig Rodrigues signal_add(&ev_sigterm, NULL);
1069e7c127fSCraig Rodrigues signal_add(&ev_sighup, NULL);
1079e7c127fSCraig Rodrigues
1089e7c127fSCraig Rodrigues if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
1099e7c127fSCraig Rodrigues fatal(NULL);
1109e7c127fSCraig Rodrigues
1119e7c127fSCraig Rodrigues env.sc_iev->events = EV_READ;
1129e7c127fSCraig Rodrigues env.sc_iev->data = &env;
1139e7c127fSCraig Rodrigues imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]);
1149e7c127fSCraig Rodrigues env.sc_iev->handler = dns_dispatch_imsg;
1159e7c127fSCraig Rodrigues event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
1169e7c127fSCraig Rodrigues env.sc_iev->handler, &env);
1179e7c127fSCraig Rodrigues event_add(&env.sc_iev->ev, NULL);
1189e7c127fSCraig Rodrigues
1199e7c127fSCraig Rodrigues event_dispatch();
1209e7c127fSCraig Rodrigues dns_shutdown();
1219e7c127fSCraig Rodrigues
1229e7c127fSCraig Rodrigues return (0);
1239e7c127fSCraig Rodrigues }
1249e7c127fSCraig Rodrigues
1259e7c127fSCraig Rodrigues void
dns_dispatch_imsg(int fd,short events,void * p)1269e7c127fSCraig Rodrigues dns_dispatch_imsg(int fd, short events, void *p)
1279e7c127fSCraig Rodrigues {
1289e7c127fSCraig Rodrigues struct imsg imsg;
1299e7c127fSCraig Rodrigues int n, cnt;
1309e7c127fSCraig Rodrigues char *name;
131eaf209deSMarcelo Araujo struct ypldap_addr_list hn = TAILQ_HEAD_INITIALIZER(hn);
132eaf209deSMarcelo Araujo struct ypldap_addr *h;
1339e7c127fSCraig Rodrigues struct ibuf *buf;
1349e7c127fSCraig Rodrigues struct env *env = p;
1359e7c127fSCraig Rodrigues struct imsgev *iev = env->sc_iev;
1369e7c127fSCraig Rodrigues struct imsgbuf *ibuf = &iev->ibuf;
1379e7c127fSCraig Rodrigues int shut = 0;
1389e7c127fSCraig Rodrigues
1399e7c127fSCraig Rodrigues if ((events & (EV_READ | EV_WRITE)) == 0)
1409e7c127fSCraig Rodrigues fatalx("unknown event");
1419e7c127fSCraig Rodrigues
1429e7c127fSCraig Rodrigues if (events & EV_READ) {
1437433efffSMarcelo Araujo if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1449e7c127fSCraig Rodrigues fatal("imsg_read error");
1459e7c127fSCraig Rodrigues if (n == 0)
1469e7c127fSCraig Rodrigues shut = 1;
1479e7c127fSCraig Rodrigues }
1489e7c127fSCraig Rodrigues if (events & EV_WRITE) {
1499e7c127fSCraig Rodrigues if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
1509e7c127fSCraig Rodrigues fatal("msgbuf_write");
1519e7c127fSCraig Rodrigues if (n == 0)
1529e7c127fSCraig Rodrigues shut = 1;
1539e7c127fSCraig Rodrigues goto done;
1549e7c127fSCraig Rodrigues }
1559e7c127fSCraig Rodrigues
1569e7c127fSCraig Rodrigues for (;;) {
1579e7c127fSCraig Rodrigues if ((n = imsg_get(ibuf, &imsg)) == -1)
1589e7c127fSCraig Rodrigues fatal("client_dispatch_imsg: imsg_get error");
1599e7c127fSCraig Rodrigues if (n == 0)
1609e7c127fSCraig Rodrigues break;
1619e7c127fSCraig Rodrigues
1629e7c127fSCraig Rodrigues switch (imsg.hdr.type) {
1639e7c127fSCraig Rodrigues case IMSG_HOST_DNS:
1649e7c127fSCraig Rodrigues name = imsg.data;
1659e7c127fSCraig Rodrigues if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
1669e7c127fSCraig Rodrigues fatalx("invalid IMSG_HOST_DNS received");
1679e7c127fSCraig Rodrigues imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
1689e7c127fSCraig Rodrigues if (name[imsg.hdr.len] != '\0' ||
1699e7c127fSCraig Rodrigues strlen(name) != imsg.hdr.len)
1709e7c127fSCraig Rodrigues fatalx("invalid IMSG_HOST_DNS received");
1719e7c127fSCraig Rodrigues if ((cnt = host_dns(name, &hn)) == -1)
1729e7c127fSCraig Rodrigues break;
1739e7c127fSCraig Rodrigues buf = imsg_create(ibuf, IMSG_HOST_DNS,
1749e7c127fSCraig Rodrigues imsg.hdr.peerid, 0,
1759e7c127fSCraig Rodrigues cnt * sizeof(struct sockaddr_storage));
1769e7c127fSCraig Rodrigues if (buf == NULL)
1779e7c127fSCraig Rodrigues break;
1789e7c127fSCraig Rodrigues if (cnt > 0) {
179eaf209deSMarcelo Araujo while(!TAILQ_EMPTY(&hn)) {
180eaf209deSMarcelo Araujo h = TAILQ_FIRST(&hn);
181eaf209deSMarcelo Araujo TAILQ_REMOVE(&hn, h, next);
1829e7c127fSCraig Rodrigues imsg_add(buf, &h->ss, sizeof(h->ss));
1839e7c127fSCraig Rodrigues free(h);
1849e7c127fSCraig Rodrigues }
1859e7c127fSCraig Rodrigues }
1869e7c127fSCraig Rodrigues
1879e7c127fSCraig Rodrigues imsg_close(ibuf, buf);
1889e7c127fSCraig Rodrigues break;
1899e7c127fSCraig Rodrigues default:
1909e7c127fSCraig Rodrigues break;
1919e7c127fSCraig Rodrigues }
1929e7c127fSCraig Rodrigues imsg_free(&imsg);
1939e7c127fSCraig Rodrigues }
1949e7c127fSCraig Rodrigues
1959e7c127fSCraig Rodrigues done:
1969e7c127fSCraig Rodrigues if (!shut)
1979e7c127fSCraig Rodrigues imsg_event_add(iev);
1989e7c127fSCraig Rodrigues else {
1999e7c127fSCraig Rodrigues /* this pipe is dead, so remove the event handler */
2009e7c127fSCraig Rodrigues event_del(&iev->ev);
2019e7c127fSCraig Rodrigues event_loopexit(NULL);
2029e7c127fSCraig Rodrigues }
2039e7c127fSCraig Rodrigues }
2049e7c127fSCraig Rodrigues
2059e7c127fSCraig Rodrigues int
host_dns(const char * s,struct ypldap_addr_list * hn)206eaf209deSMarcelo Araujo host_dns(const char *s, struct ypldap_addr_list *hn)
2079e7c127fSCraig Rodrigues {
2089e7c127fSCraig Rodrigues struct addrinfo hints, *res0, *res;
2099e7c127fSCraig Rodrigues int error, cnt = 0;
2109e7c127fSCraig Rodrigues struct sockaddr_in *sa_in;
2119e7c127fSCraig Rodrigues struct sockaddr_in6 *sa_in6;
212eaf209deSMarcelo Araujo struct ypldap_addr *h;
2139e7c127fSCraig Rodrigues
214*bbdfc8f1SMarcelo Araujo memset(&hints, 0, sizeof(hints));
2159e7c127fSCraig Rodrigues hints.ai_family = PF_UNSPEC;
2169e7c127fSCraig Rodrigues hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
2179e7c127fSCraig Rodrigues error = getaddrinfo(s, NULL, &hints, &res0);
218468878d9SCraig Rodrigues if (error == EAI_AGAIN || error == EAI_NONAME)
2199e7c127fSCraig Rodrigues return (0);
2209e7c127fSCraig Rodrigues if (error) {
2219e7c127fSCraig Rodrigues log_warnx("could not parse \"%s\": %s", s,
2229e7c127fSCraig Rodrigues gai_strerror(error));
2239e7c127fSCraig Rodrigues return (-1);
2249e7c127fSCraig Rodrigues }
2259e7c127fSCraig Rodrigues
2269e7c127fSCraig Rodrigues for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) {
2279e7c127fSCraig Rodrigues if (res->ai_family != AF_INET &&
2289e7c127fSCraig Rodrigues res->ai_family != AF_INET6)
2299e7c127fSCraig Rodrigues continue;
2309e7c127fSCraig Rodrigues if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL)
2319e7c127fSCraig Rodrigues fatal(NULL);
2329e7c127fSCraig Rodrigues h->ss.ss_family = res->ai_family;
2339e7c127fSCraig Rodrigues if (res->ai_family == AF_INET) {
2349e7c127fSCraig Rodrigues sa_in = (struct sockaddr_in *)&h->ss;
2359e7c127fSCraig Rodrigues sa_in->sin_len = sizeof(struct sockaddr_in);
2369e7c127fSCraig Rodrigues sa_in->sin_addr.s_addr = ((struct sockaddr_in *)
2379e7c127fSCraig Rodrigues res->ai_addr)->sin_addr.s_addr;
2389e7c127fSCraig Rodrigues } else {
2399e7c127fSCraig Rodrigues sa_in6 = (struct sockaddr_in6 *)&h->ss;
2409e7c127fSCraig Rodrigues sa_in6->sin6_len = sizeof(struct sockaddr_in6);
2419e7c127fSCraig Rodrigues memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *)
2429e7c127fSCraig Rodrigues res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
2439e7c127fSCraig Rodrigues }
2449e7c127fSCraig Rodrigues
245eaf209deSMarcelo Araujo TAILQ_INSERT_HEAD(hn, h, next);
2469e7c127fSCraig Rodrigues cnt++;
2479e7c127fSCraig Rodrigues }
2489e7c127fSCraig Rodrigues freeaddrinfo(res0);
2499e7c127fSCraig Rodrigues return (cnt);
2509e7c127fSCraig Rodrigues }
251