GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ypldap/ldapclient.c Lines: 0 341 0.0 %
Date: 2017-11-07 Branches: 0 250 0.0 %

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