]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ypldap/ypldap_dns.c
Merge llvm-project release/17.x llvmorg-17.0.1-25-g098e653a5bed
[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
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/param.h>
21 #include <sys/socket.h>
22 #include <sys/stat.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 #include <limits.h>
41
42 #include "ypldap.h"
43
44 volatile sig_atomic_t    quit_dns = 0;
45 struct imsgev           *iev_dns;
46
47 void    dns_dispatch_imsg(int, short, void *);
48 void    dns_sig_handler(int, short, void *);
49 void    dns_shutdown(void);
50 int     host_dns(const char *, struct ypldap_addr_list *);
51
52 void
53 dns_sig_handler(int sig, short event, void *p)
54 {
55         switch (sig) {
56         case SIGINT:
57         case SIGTERM:
58                 dns_shutdown();
59                 break;
60         default:
61                 fatalx("unexpected signal");
62         }
63 }
64
65 void
66 dns_shutdown(void)
67 {
68         log_info("dns engine exiting");
69         _exit(0);
70 }
71
72 pid_t
73 ypldap_dns(int pipe_ntp[2], struct passwd *pw)
74 {
75         pid_t                    pid;
76         struct event     ev_sigint;
77         struct event     ev_sigterm;
78         struct event     ev_sighup;
79         struct env       env;
80
81         switch (pid = fork()) {
82         case -1:
83                 fatal("cannot fork");
84                 break;
85         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
125 void
126 dns_dispatch_imsg(int fd, short events, void *p)
127 {
128         struct imsg              imsg;
129         int                      n, cnt;
130         char                    *name;
131         struct ypldap_addr_list hn = TAILQ_HEAD_INITIALIZER(hn);
132         struct ypldap_addr      *h;
133         struct ibuf             *buf;
134         struct env              *env = p;
135         struct imsgev           *iev = env->sc_iev;
136         struct imsgbuf          *ibuf = &iev->ibuf;
137         int                      shut = 0;
138
139         if ((events & (EV_READ | EV_WRITE)) == 0)
140                 fatalx("unknown event");
141
142         if (events & EV_READ) {
143                 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
144                         fatal("imsg_read error");
145                 if (n == 0)
146                         shut = 1;
147         }
148         if (events & EV_WRITE) {
149                 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
150                         fatal("msgbuf_write");
151                 if (n == 0)
152                         shut = 1;
153                 goto done;
154         }
155
156         for (;;) {
157                 if ((n = imsg_get(ibuf, &imsg)) == -1)
158                         fatal("client_dispatch_imsg: imsg_get error");
159                 if (n == 0)
160                         break;
161
162                 switch (imsg.hdr.type) {
163                 case IMSG_HOST_DNS:
164                         name = imsg.data;
165                         if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
166                                 fatalx("invalid IMSG_HOST_DNS received");
167                         imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
168                         if (name[imsg.hdr.len] != '\0' ||
169                             strlen(name) != imsg.hdr.len)
170                                 fatalx("invalid IMSG_HOST_DNS received");
171                         if ((cnt = host_dns(name, &hn)) == -1)
172                                 break;
173                         buf = imsg_create(ibuf, IMSG_HOST_DNS,
174                             imsg.hdr.peerid, 0,
175                             cnt * sizeof(struct sockaddr_storage));
176                         if (buf == NULL)
177                                 break;
178                         if (cnt > 0) {
179                                 while(!TAILQ_EMPTY(&hn)) {
180                                         h = TAILQ_FIRST(&hn);
181                                         TAILQ_REMOVE(&hn, h, next);
182                                         imsg_add(buf, &h->ss, sizeof(h->ss));
183                                         free(h);
184                                 }
185                         }
186
187                         imsg_close(ibuf, buf);
188                         break;
189                 default:
190                         break;
191                 }
192                 imsg_free(&imsg);
193         }
194
195 done:
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
205 int
206 host_dns(const char *s, struct ypldap_addr_list *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;
213
214         memset(&hints, 0, 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_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                 TAILQ_INSERT_HEAD(hn, h, next);
246                 cnt++;
247         }
248         freeaddrinfo(res0);
249         return (cnt);
250 }