]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ypldap/ypldap_dns.c
sysctl(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / usr.sbin / ypldap / ypldap_dns.c
1 /*      $OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */
2 /*      $FreeBSD$ */
3
4 /*
5  * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19
20 #include <sys/types.h>
21 #include <sys/param.h>
22 #include <sys/socket.h>
23 #include <sys/stat.h>
24 #include <sys/time.h>
25 #include <sys/tree.h>
26 #include <sys/queue.h>
27
28 #include <netinet/in.h>
29 #include <arpa/nameser.h>
30
31 #include <netdb.h>
32 #include <pwd.h>
33 #include <errno.h>
34 #include <event.h>
35 #include <resolv.h>
36 #include <poll.h>
37 #include <signal.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <limits.h>
42
43 #include "ypldap.h"
44
45 volatile sig_atomic_t    quit_dns = 0;
46 struct imsgev           *iev_dns;
47
48 void    dns_dispatch_imsg(int, short, void *);
49 void    dns_sig_handler(int, short, void *);
50 void    dns_shutdown(void);
51 int     host_dns(const char *, struct ypldap_addr_list *);
52
53 void
54 dns_sig_handler(int sig, short event, void *p)
55 {
56         switch (sig) {
57         case SIGINT:
58         case SIGTERM:
59                 dns_shutdown();
60                 break;
61         default:
62                 fatalx("unexpected signal");
63         }
64 }
65
66 void
67 dns_shutdown(void)
68 {
69         log_info("dns engine exiting");
70         _exit(0);
71 }
72
73 pid_t
74 ypldap_dns(int pipe_ntp[2], struct passwd *pw)
75 {
76         pid_t                    pid;
77         struct event     ev_sigint;
78         struct event     ev_sigterm;
79         struct event     ev_sighup;
80         struct env       env;
81
82         switch (pid = fork()) {
83         case -1:
84                 fatal("cannot fork");
85                 break;
86         case 0:
87                 break;
88         default:
89                 return (pid);
90         }
91
92         setproctitle("dns engine");
93         close(pipe_ntp[0]);
94
95         if (setgroups(1, &pw->pw_gid) ||
96             setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
97             setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
98                 fatal("can't drop privileges");
99         endservent();
100
101         event_init();
102         signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL);
103         signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL);
104         signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL);
105         signal_add(&ev_sigint, NULL);
106         signal_add(&ev_sigterm, NULL);
107         signal_add(&ev_sighup, NULL);
108
109         if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
110                 fatal(NULL);
111
112         env.sc_iev->events = EV_READ;
113         env.sc_iev->data = &env;
114         imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]);
115         env.sc_iev->handler = dns_dispatch_imsg;
116         event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
117             env.sc_iev->handler, &env);
118         event_add(&env.sc_iev->ev, NULL);
119
120         event_dispatch();
121         dns_shutdown();
122
123         return (0);
124 }
125
126 void
127 dns_dispatch_imsg(int fd, short events, void *p)
128 {
129         struct imsg              imsg;
130         int                      n, cnt;
131         char                    *name;
132         struct ypldap_addr_list hn = TAILQ_HEAD_INITIALIZER(hn);
133         struct ypldap_addr      *h;
134         struct ibuf             *buf;
135         struct env              *env = p;
136         struct imsgev           *iev = env->sc_iev;
137         struct imsgbuf          *ibuf = &iev->ibuf;
138         int                      shut = 0;
139
140         if ((events & (EV_READ | EV_WRITE)) == 0)
141                 fatalx("unknown event");
142
143         if (events & EV_READ) {
144                 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
145                         fatal("imsg_read error");
146                 if (n == 0)
147                         shut = 1;
148         }
149         if (events & EV_WRITE) {
150                 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
151                         fatal("msgbuf_write");
152                 if (n == 0)
153                         shut = 1;
154                 goto done;
155         }
156
157         for (;;) {
158                 if ((n = imsg_get(ibuf, &imsg)) == -1)
159                         fatal("client_dispatch_imsg: imsg_get error");
160                 if (n == 0)
161                         break;
162
163                 switch (imsg.hdr.type) {
164                 case IMSG_HOST_DNS:
165                         name = imsg.data;
166                         if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
167                                 fatalx("invalid IMSG_HOST_DNS received");
168                         imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
169                         if (name[imsg.hdr.len] != '\0' ||
170                             strlen(name) != imsg.hdr.len)
171                                 fatalx("invalid IMSG_HOST_DNS received");
172                         if ((cnt = host_dns(name, &hn)) == -1)
173                                 break;
174                         buf = imsg_create(ibuf, IMSG_HOST_DNS,
175                             imsg.hdr.peerid, 0,
176                             cnt * sizeof(struct sockaddr_storage));
177                         if (buf == NULL)
178                                 break;
179                         if (cnt > 0) {
180                                 while(!TAILQ_EMPTY(&hn)) {
181                                         h = TAILQ_FIRST(&hn);
182                                         TAILQ_REMOVE(&hn, h, next);
183                                         imsg_add(buf, &h->ss, sizeof(h->ss));
184                                         free(h);
185                                 }
186                         }
187
188                         imsg_close(ibuf, buf);
189                         break;
190                 default:
191                         break;
192                 }
193                 imsg_free(&imsg);
194         }
195
196 done:
197         if (!shut)
198                 imsg_event_add(iev);
199         else {
200                 /* this pipe is dead, so remove the event handler */
201                 event_del(&iev->ev);
202                 event_loopexit(NULL);
203         }
204 }
205
206 int
207 host_dns(const char *s, struct ypldap_addr_list *hn)
208 {
209         struct addrinfo          hints, *res0, *res;
210         int                      error, cnt = 0;
211         struct sockaddr_in      *sa_in;
212         struct sockaddr_in6     *sa_in6;
213         struct ypldap_addr      *h;
214
215         memset(&hints, 0, sizeof(hints));
216         hints.ai_family = PF_UNSPEC;
217         hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
218         error = getaddrinfo(s, NULL, &hints, &res0);
219         if (error == EAI_AGAIN || error == EAI_NONAME)
220                         return (0);
221         if (error) {
222                 log_warnx("could not parse \"%s\": %s", s,
223                     gai_strerror(error));
224                 return (-1);
225         }
226
227         for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) {
228                 if (res->ai_family != AF_INET &&
229                     res->ai_family != AF_INET6)
230                         continue;
231                 if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL)
232                         fatal(NULL);
233                 h->ss.ss_family = res->ai_family;
234                 if (res->ai_family == AF_INET) {
235                         sa_in = (struct sockaddr_in *)&h->ss;
236                         sa_in->sin_len = sizeof(struct sockaddr_in);
237                         sa_in->sin_addr.s_addr = ((struct sockaddr_in *)
238                             res->ai_addr)->sin_addr.s_addr;
239                 } else {
240                         sa_in6 = (struct sockaddr_in6 *)&h->ss;
241                         sa_in6->sin6_len = sizeof(struct sockaddr_in6);
242                         memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *)
243                             res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
244                 }
245
246                 TAILQ_INSERT_HEAD(hn, h, next);
247                 cnt++;
248         }
249         freeaddrinfo(res0);
250         return (cnt);
251 }