xref: /openbsd-src/usr.sbin/ypldap/ldapclient.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /* $OpenBSD: ldapclient.c,v 1.13 2009/01/27 23:29:42 pyr Exp $ */
2 
3 /*
4  * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
5  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@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 USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * 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/queue.h>
23 #include <sys/socket.h>
24 #include <sys/tree.h>
25 
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 
29 #include <netdb.h>
30 #include <errno.h>
31 #include <err.h>
32 #include <event.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <pwd.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include "aldap.h"
41 #include "ypldap.h"
42 
43 void    client_sig_handler(int, short, void *);
44 void	client_dispatch_dns(int, short, void *);
45 void    client_dispatch_parent(int, short, void *);
46 void    client_shutdown(void);
47 void    client_connect(int, short, void *);
48 void    client_configure(struct env *);
49 void    client_periodic_update(int, short, void *);
50 int	client_try_idm(struct env *, struct idm *);
51 void	client_try_idm_wrapper(int, short, void *);
52 void	client_try_server_wrapper(int, short, void *);
53 int	client_addr_init(struct idm *);
54 int	client_addr_free(struct idm *);
55 
56 struct aldap	*client_aldap_open(struct ypldap_addr *);
57 
58 /*
59  * dummy wrapper to provide aldap_init with its fd's.
60  */
61 struct aldap *
62 client_aldap_open(struct ypldap_addr *addr)
63 {
64 	int			 fd = -1;
65 	struct ypldap_addr	 *p;
66 
67 	for (p = addr; p != NULL; p = p->next) {
68 		char			 hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
69 		struct sockaddr		*sa = (struct sockaddr *)&p->ss;
70 
71 		if (getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), sbuf,
72 			sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV))
73 				errx(1, "could not get numeric hostname");
74 
75 		if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
76 			return NULL;
77 
78 		if (connect(fd, sa, SA_LEN(sa)) == 0)
79 			break;
80 
81 		warn("connect to %s port %s (%s) failed", hbuf, sbuf, "tcp");
82 		close(fd);
83 	}
84 
85 	if (fd == -1)
86 		return NULL;
87 
88 	return aldap_init(fd);
89 }
90 
91 int
92 client_addr_init(struct idm *idm)
93 {
94         struct sockaddr_in      *sa_in;
95         struct sockaddr_in6     *sa_in6;
96         struct ypldap_addr         *h;
97 
98         for (h = idm->idm_addr; h != NULL; h = h->next) {
99                 switch (h->ss.ss_family) {
100                 case AF_INET:
101                         sa_in = (struct sockaddr_in *)&h->ss;
102                         if (ntohs(sa_in->sin_port) == 0)
103                                 sa_in->sin_port = htons(389);
104                         idm->idm_state = STATE_DNS_DONE;
105                         break;
106                 case AF_INET6:
107                         sa_in6 = (struct sockaddr_in6 *)&h->ss;
108                         if (ntohs(sa_in6->sin6_port) == 0)
109                                 sa_in6->sin6_port = htons(389);
110                         idm->idm_state = STATE_DNS_DONE;
111                         break;
112                 default:
113                         fatalx("king bula sez: wrong AF in client_addr_init");
114                         /* not reached */
115                 }
116         }
117 
118         return (0);
119 }
120 
121 int
122 client_addr_free(struct idm *idm)
123 {
124         struct ypldap_addr         *h;
125 
126 	if (idm->idm_addr == NULL)
127 		return (-1);
128 
129 	for (h = idm->idm_addr; h != NULL; h = h->next)
130 		free(h);
131 
132 	idm->idm_addr = NULL;
133 
134 	return (0);
135 }
136 
137 void
138 client_sig_handler(int sig, short event, void *p)
139 {
140 	switch (sig) {
141 	case SIGINT:
142 	case SIGTERM:
143 		client_shutdown();
144 		break;
145 	default:
146 		fatalx("unexpected signal");
147 	}
148 }
149 
150 void
151 client_dispatch_dns(int fd, short event, void *p)
152 {
153 	struct imsg		 imsg;
154 	u_int16_t		 dlen;
155 	u_char			*data;
156 	struct ypldap_addr	*h;
157 	int			 n, wait_cnt = 0;
158 	struct idm		*idm;
159 	int			 shut = 0;
160 
161 	struct env		*env = p;
162 	struct imsgbuf		*ibuf = env->sc_ibuf_dns;
163 
164 	switch (event) {
165 	case EV_READ:
166 		if ((n = imsg_read(ibuf)) == -1)
167 			fatal("imsg_read error");
168 		if (n == 0)
169 			shut = 1;
170 		break;
171 	case EV_WRITE:
172 		if (msgbuf_write(&ibuf->w) == -1)
173 			fatal("msgbuf_write");
174 		imsg_event_add(ibuf);
175 		return;
176 	default:
177 		fatalx("unknown event");
178 	}
179 
180 	for (;;) {
181 		if ((n = imsg_get(ibuf, &imsg)) == -1)
182 			fatal("client_dispatch_parent: imsg_read_error");
183 		if (n == 0)
184 			break;
185 
186 		switch (imsg.hdr.type) {
187 		case IMSG_HOST_DNS:
188 			TAILQ_FOREACH(idm, &env->sc_idms, idm_entry)
189 				if (idm->idm_id == imsg.hdr.peerid)
190 					break;
191 			if (idm == NULL) {
192 				log_warnx("IMSG_HOST_DNS with invalid peerID");
193 				break;
194 			}
195 			if (idm->idm_addr != NULL) {
196 				log_warnx("IMSG_HOST_DNS but addr != NULL!");
197 				break;
198 			}
199 
200 			dlen = imsg.hdr.len - IMSG_HEADER_SIZE;
201 			if (dlen == 0) {	/* no data -> temp error */
202 				idm->idm_state = STATE_DNS_TEMPFAIL;
203 				break;
204 			}
205 
206 			data = (u_char *)imsg.data;
207 			while (dlen >= sizeof(struct sockaddr_storage)) {
208 				if ((h = calloc(1, sizeof(struct ypldap_addr))) ==
209 				    NULL)
210 					fatal(NULL);
211 				memcpy(&h->ss, data, sizeof(h->ss));
212 
213 				if (idm->idm_addr == NULL)
214 					h->next = NULL;
215 				else
216 					h->next = idm->idm_addr;
217 
218 				idm->idm_addr = h;
219 
220 				data += sizeof(h->ss);
221 				dlen -= sizeof(h->ss);
222 			}
223 			if (dlen != 0)
224 				fatalx("IMSG_HOST_DNS: dlen != 0");
225 
226 			client_addr_init(idm);
227 
228 			break;
229 		default:
230 			break;
231 		}
232 		imsg_free(&imsg);
233 	}
234 
235 	TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) {
236 		if (client_try_idm(env, idm) == -1)
237 			idm->idm_state = STATE_LDAP_FAIL;
238 
239 		if (idm->idm_state < STATE_LDAP_DONE)
240 			wait_cnt++;
241 	}
242 	if (wait_cnt == 0)
243 		imsg_compose(env->sc_ibuf, IMSG_END_UPDATE, 0, 0, NULL, 0);
244 
245 	if (!shut)
246 		imsg_event_add(ibuf);
247 	else {
248 		/* this pipe is dead, so remove the event handler */
249 		event_del(&ibuf->ev);
250 		event_loopexit(NULL);
251 	}
252 }
253 
254 void
255 client_dispatch_parent(int fd, short event, void *p)
256 {
257 	int			 n;
258 	int			 shut = 0;
259 	struct imsg		 imsg;
260 	struct env		*env = p;
261 	struct imsgbuf		*ibuf = env->sc_ibuf;
262 
263 
264 	switch (event) {
265 	case EV_READ:
266 		if ((n = imsg_read(ibuf)) == -1)
267 			fatal("imsg_read error");
268 		if (n == 0)
269 			shut = 1;
270 		break;
271 	case EV_WRITE:
272 		if (msgbuf_write(&ibuf->w) == -1)
273 			fatal("msgbuf_write");
274 		imsg_event_add(ibuf);
275 		return;
276 	default:
277 		fatalx("unknown event");
278 	}
279 
280 	for (;;) {
281 		if ((n = imsg_get(ibuf, &imsg)) == -1)
282 			fatal("client_dispatch_parent: imsg_read_error");
283 		if (n == 0)
284 			break;
285 
286 		switch (imsg.hdr.type) {
287 		case IMSG_CONF_START: {
288 			struct env	params;
289 
290 			if (env->sc_flags & F_CONFIGURING) {
291 				log_warnx("configuration already in progress");
292 				break;
293 			}
294 			memcpy(&params, imsg.data, sizeof(params));
295 			log_debug("configuration starting");
296 			env->sc_flags |= F_CONFIGURING;
297 			purge_config(env);
298 			memcpy(&env->sc_conf_tv, &params.sc_conf_tv,
299 			    sizeof(env->sc_conf_tv));
300 			env->sc_flags |= params.sc_flags;
301 			break;
302 		}
303 		case IMSG_CONF_IDM: {
304 			struct idm	*idm;
305 
306 			if (!(env->sc_flags & F_CONFIGURING))
307 				break;
308 			if ((idm = calloc(1, sizeof(*idm))) == NULL)
309 				fatal(NULL);
310 			memcpy(idm, imsg.data, sizeof(*idm));
311 			idm->idm_env = env;
312 			TAILQ_INSERT_TAIL(&env->sc_idms, idm, idm_entry);
313 			break;
314 		}
315 		case IMSG_CONF_END:
316 			env->sc_flags &= ~F_CONFIGURING;
317 			log_debug("applying configuration");
318 			client_configure(env);
319 			break;
320 		default:
321 			log_debug("client_dispatch_parent: unexpect imsg %d",
322 			    imsg.hdr.type);
323 
324 			break;
325 		}
326 		imsg_free(&imsg);
327 	}
328 	if (!shut)
329 		imsg_event_add(ibuf);
330 	else {
331 		/* this pipe is dead, so remove the event handler */
332 		event_del(&ibuf->ev);
333 		event_loopexit(NULL);
334 	}
335 }
336 
337 void
338 client_shutdown(void)
339 {
340 	log_info("ldap client exiting");
341 	_exit(0);
342 }
343 
344 pid_t
345 ldapclient(int pipe_main2client[2])
346 {
347 	pid_t            pid, dns_pid;
348 	int              pipe_dns[2];
349 	struct passwd	*pw;
350 	struct event	 ev_sigint;
351 	struct event	 ev_sigterm;
352 	struct env	 env;
353 
354 	switch (pid = fork()) {
355 	case -1:
356 		fatal("cannot fork");
357 		break;
358 	case 0:
359 		break;
360 	default:
361 		return (pid);
362 	}
363 
364 	bzero(&env, sizeof(env));
365 	TAILQ_INIT(&env.sc_idms);
366 
367 	if ((pw = getpwnam(YPLDAP_USER)) == NULL)
368 		fatal("getpwnam");
369 
370 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_dns) == -1)
371 		fatal("socketpair");
372 	dns_pid = ypldap_dns(pipe_dns, pw);
373 	close(pipe_dns[1]);
374 
375 #ifndef DEBUG
376 	if (chroot(pw->pw_dir) == -1)
377 		fatal("chroot");
378 	if (chdir("/") == -1)
379 		fatal("chdir");
380 #else
381 #warning disabling chrooting in DEBUG mode
382 #endif
383 	setproctitle("ldap client");
384 	ypldap_process = PROC_CLIENT;
385 
386 #ifndef DEBUG
387 	if (setgroups(1, &pw->pw_gid) ||
388 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
389 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
390 		fatal("cannot drop privileges");
391 #else
392 #warning disabling privilege revocation in DEBUG mode
393 #endif
394 
395 	event_init();
396 	signal_set(&ev_sigint, SIGINT, client_sig_handler, NULL);
397 	signal_set(&ev_sigterm, SIGTERM, client_sig_handler, NULL);
398 	signal_add(&ev_sigint, NULL);
399 	signal_add(&ev_sigterm, NULL);
400 
401 	close(pipe_main2client[0]);
402 	if ((env.sc_ibuf = calloc(1, sizeof(*env.sc_ibuf))) == NULL)
403 		fatal(NULL);
404 	if ((env.sc_ibuf_dns = calloc(1, sizeof(*env.sc_ibuf_dns))) == NULL)
405 		fatal(NULL);
406 
407 	env.sc_ibuf->events = EV_READ;
408 	env.sc_ibuf->data = &env;
409 	imsg_init(env.sc_ibuf, pipe_main2client[1], client_dispatch_parent);
410 	event_set(&env.sc_ibuf->ev, env.sc_ibuf->fd, env.sc_ibuf->events,
411 	    env.sc_ibuf->handler, &env);
412 	event_add(&env.sc_ibuf->ev, NULL);
413 
414 	env.sc_ibuf_dns->events = EV_READ;
415 	env.sc_ibuf_dns->data = &env;
416 	imsg_init(env.sc_ibuf_dns, pipe_dns[0], client_dispatch_dns);
417 	event_set(&env.sc_ibuf_dns->ev, env.sc_ibuf_dns->fd, env.sc_ibuf_dns->events,
418 	    env.sc_ibuf_dns->handler, &env);
419 	event_add(&env.sc_ibuf_dns->ev, NULL);
420 
421 	event_dispatch();
422 	client_shutdown();
423 
424 	return (0);
425 
426 }
427 
428 int
429 client_try_idm(struct env *env, struct idm *idm)
430 {
431 	const char		*where, *errstr;
432 	char			*attrs[ATTR_MAX+1];
433 	char			**ldap_attrs;
434 	int			 i, j, k;
435 	struct idm_req		 ir;
436 	struct aldap_message	*m;
437 	struct aldap		*al;
438 
439 	where = "connect";
440 	if ((al = client_aldap_open(idm->idm_addr)) == NULL)
441 		return (-1);
442 
443 	if (idm->idm_flags & F_NEEDAUTH) {
444 		where = "binding";
445 		if (aldap_bind(al, idm->idm_binddn, idm->idm_bindcred) == -1)
446 			goto bad;
447 
448 		where = "parsing";
449 		if ((m = aldap_parse(al)) == NULL)
450 			goto bad;
451 		where = "verifying msgid";
452 		if (al->msgid != m->msgid) {
453 			aldap_freemsg(m);
454 			goto bad;
455 		}
456 		aldap_freemsg(m);
457 	}
458 
459 	bzero(attrs, sizeof(attrs));
460 	for (i = 0, j = 0; i < ATTR_MAX; i++) {
461 		if (idm->idm_flags & F_FIXED_ATTR(i))
462 			continue;
463 		attrs[j++] = idm->idm_attrs[i];
464 	}
465 	attrs[j] = NULL;
466 
467 	where = "search";
468 	if (aldap_search(al, idm->idm_basedn, LDAP_SCOPE_SUBTREE,
469 		    idm->idm_filters[FILTER_USER], attrs, 0, 0, 0) == -1) {
470 		aldap_get_errno(al, &errstr);
471 		log_debug("%s\n", errstr);
472 		goto bad;
473 	}
474 
475 	/*
476 	 * build password line.
477 	 */
478 	while ((m = aldap_parse(al)) != NULL) {
479 		where = "verifying msgid";
480 		if (al->msgid != m->msgid) {
481 			aldap_freemsg(m);
482 			goto bad;
483 		}
484 		/* end of the search result chain */
485 		if (m->message_type == LDAP_RES_SEARCH_RESULT) {
486 			aldap_freemsg(m);
487 			break;
488 		}
489 		/* search entry; the rest we won't handle */
490 		where = "verifying message_type";
491 		if (m->message_type != LDAP_RES_SEARCH_ENTRY) {
492 			aldap_freemsg(m);
493 			goto bad;
494 		}
495 		/* search entry */
496 		bzero(&ir, sizeof(ir));
497 		for (i = 0, j = 0; i < ATTR_MAX; i++) {
498 			if (idm->idm_flags & F_FIXED_ATTR(i)) {
499 				if (strlcat(ir.ir_line, idm->idm_attrs[i],
500 				    sizeof(ir.ir_line)) >= sizeof(ir.ir_line))
501 					/*
502 					 * entry yields a line > 1024, trash it.
503 					 */
504 					goto next_pwdentry;
505 				if (i == ATTR_UID) {
506 					ir.ir_key.ik_uid = strtonum(
507 					    idm->idm_attrs[i], 0,
508 					    UID_MAX, NULL);
509 				}
510 			} else if (idm->idm_list & F_LIST(i)) {
511 				if (aldap_match_entry(m, attrs[j++], &ldap_attrs) == -1)
512 					goto next_pwdentry;
513 				if (ldap_attrs[0] == NULL)
514 					goto next_pwdentry;
515 				for (k = 0; k >= 0 && ldap_attrs[k] != NULL; k++) {
516 					if (strlcat(ir.ir_line, ldap_attrs[k],
517 					    sizeof(ir.ir_line)) >= sizeof(ir.ir_line))
518 						continue;
519 					if (ldap_attrs[k+1] != NULL)
520 						if (strlcat(ir.ir_line, ",",
521 							    sizeof(ir.ir_line))
522 						    >= sizeof(ir.ir_line)) {
523 							aldap_free_entry(ldap_attrs);
524 							goto next_pwdentry;
525 						}
526 				}
527 				aldap_free_entry(ldap_attrs);
528 			} else {
529 				if (aldap_match_entry(m, attrs[j++], &ldap_attrs) == -1)
530 					goto next_pwdentry;
531 				if (ldap_attrs[0] == NULL)
532 					goto next_pwdentry;
533 				if (strlcat(ir.ir_line, ldap_attrs[0],
534 				    sizeof(ir.ir_line)) >= sizeof(ir.ir_line)) {
535 					aldap_free_entry(ldap_attrs);
536 					goto next_pwdentry;
537 				}
538 				if (i == ATTR_UID) {
539 					ir.ir_key.ik_uid = strtonum(
540 					    ldap_attrs[0], 0, UID_MAX, NULL);
541 				}
542 				aldap_free_entry(ldap_attrs);
543 			}
544 			if (i != ATTR_SHELL)
545 				if (strlcat(ir.ir_line, ":",
546 				    sizeof(ir.ir_line)) >= sizeof(ir.ir_line))
547 					goto next_pwdentry;
548 		}
549 		imsg_compose(env->sc_ibuf, IMSG_PW_ENTRY, 0, 0,
550 		    &ir, sizeof(ir));
551 next_pwdentry:
552 		aldap_freemsg(m);
553 	}
554 
555 	bzero(attrs, sizeof(attrs));
556 	for (i = ATTR_GR_MIN, j = 0; i < ATTR_GR_MAX; i++) {
557 		if (idm->idm_flags & F_FIXED_ATTR(i))
558 			continue;
559 		attrs[j++] = idm->idm_attrs[i];
560 	}
561 	attrs[j] = NULL;
562 
563 	where = "search";
564 	if (aldap_search(al, idm->idm_basedn, LDAP_SCOPE_SUBTREE,
565 		    idm->idm_filters[FILTER_GROUP], attrs, 0, 0, 0) == -1) {
566 		aldap_get_errno(al, &errstr);
567 		log_debug("%s\n", errstr);
568 
569 		goto bad;
570 	}
571 
572 	/*
573 	 * build group line.
574 	 */
575 	while ((m = aldap_parse(al)) != NULL) {
576 		where = "verifying msgid";
577 		if (al->msgid != m->msgid) {
578 			aldap_freemsg(m);
579 			goto bad;
580 		}
581 		/* end of the search result chain */
582 		if (m->message_type == LDAP_RES_SEARCH_RESULT) {
583 			aldap_freemsg(m);
584 			break;
585 		}
586 		/* search entry; the rest we won't handle */
587 		where = "verifying message_type";
588 		if (m->message_type != LDAP_RES_SEARCH_ENTRY) {
589 			aldap_freemsg(m);
590 			goto bad;
591 		}
592 		/* search entry */
593 		bzero(&ir, sizeof(ir));
594 		for (i = ATTR_GR_MIN, j = 0; i < ATTR_GR_MAX; i++) {
595 			if (idm->idm_flags & F_FIXED_ATTR(i)) {
596 				if (strlcat(ir.ir_line, idm->idm_attrs[i],
597 				    sizeof(ir.ir_line)) >= sizeof(ir.ir_line))
598 					/*
599 					 * entry yields a line > 1024, trash it.
600 					 */
601 					goto next_grpentry;
602 				if (i == ATTR_GR_GID) {
603 					ir.ir_key.ik_gid = strtonum(
604 					    idm->idm_attrs[i], 0,
605 					    GID_MAX, NULL);
606 				}
607 			} else if (idm->idm_list & F_LIST(i)) {
608 				if (aldap_match_entry(m, attrs[j++], &ldap_attrs) == -1)
609 					goto next_grpentry;
610 				if (ldap_attrs[0] == NULL)
611 					goto next_grpentry;
612 				for (k = 0; k >= 0 && ldap_attrs[k] != NULL; k++) {
613 					if (strlcat(ir.ir_line, ldap_attrs[k],
614 					    sizeof(ir.ir_line)) >= sizeof(ir.ir_line))
615 						continue;
616 					if (ldap_attrs[k+1] != NULL)
617 						if (strlcat(ir.ir_line, ",",
618 							    sizeof(ir.ir_line))
619 						    >= sizeof(ir.ir_line)) {
620 							aldap_free_entry(ldap_attrs);
621 							goto next_grpentry;
622 						}
623 				}
624 				aldap_free_entry(ldap_attrs);
625 			} else {
626 				if (aldap_match_entry(m, attrs[j++], &ldap_attrs) == -1)
627 					goto next_grpentry;
628 				if (ldap_attrs[0] == NULL)
629 					goto next_grpentry;
630 				if (strlcat(ir.ir_line, ldap_attrs[0],
631 				    sizeof(ir.ir_line)) >= sizeof(ir.ir_line)) {
632 					aldap_free_entry(ldap_attrs);
633 					goto next_grpentry;
634 				}
635 				if (i == ATTR_GR_GID) {
636 					ir.ir_key.ik_uid = strtonum(
637 					    ldap_attrs[0], 0, GID_MAX, NULL);
638 				}
639 				aldap_free_entry(ldap_attrs);
640 			}
641 			if (i != ATTR_GR_MEMBERS)
642 				if (strlcat(ir.ir_line, ":",
643 				    sizeof(ir.ir_line)) >= sizeof(ir.ir_line))
644 					goto next_grpentry;
645 		}
646 		imsg_compose(env->sc_ibuf, IMSG_GRP_ENTRY, 0, 0,
647 		    &ir, sizeof(ir));
648 next_grpentry:
649 		aldap_freemsg(m);
650 	}
651 
652 	aldap_close(al);
653 
654 	idm->idm_state = STATE_LDAP_DONE;
655 
656 	return (0);
657 bad:
658 	log_debug("directory %s errored out in %s", idm->idm_name, where);
659 	return (-1);
660 }
661 
662 void
663 client_periodic_update(int fd, short event, void *p)
664 {
665 	struct env	*env = p;
666 
667 	struct idm	*idm;
668 	int		 fail_cnt = 0;
669 
670 	/* If LDAP isn't finished, notify the master process to trash the
671 	 * update. */
672 	TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) {
673 		if (idm->idm_state < STATE_LDAP_DONE)
674 			fail_cnt++;
675 
676 		idm->idm_state = STATE_NONE;
677 
678 		client_addr_free(idm);
679 	}
680 	if (fail_cnt > 0) {
681 		log_debug("trash the update");
682 		imsg_compose(env->sc_ibuf, IMSG_TRASH_UPDATE, 0, 0, NULL, 0);
683 	}
684 
685 	client_configure(env);
686 }
687 
688 void
689 client_configure(struct env *env)
690 {
691 	struct timeval	 tv;
692 	struct idm	*idm;
693         u_int16_t        dlen;
694 
695 	log_debug("connecting to directories");
696 
697 	imsg_compose(env->sc_ibuf, IMSG_START_UPDATE, 0, 0, NULL, 0);
698 
699 	/* Start the DNS lookups */
700 	TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) {
701 		dlen = strlen(idm->idm_name) + 1;
702 		imsg_compose(env->sc_ibuf_dns, IMSG_HOST_DNS, idm->idm_id, 0,
703 		    idm->idm_name, dlen);
704 	}
705 
706 	tv.tv_sec = env->sc_conf_tv.tv_sec;
707 	tv.tv_usec = env->sc_conf_tv.tv_usec;
708 	evtimer_set(&env->sc_conf_ev, client_periodic_update, env);
709 	evtimer_add(&env->sc_conf_ev, &tv);
710 }
711