GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldapd/ldape.c Lines: 0 268 0.0 %
Date: 2017-11-07 Branches: 0 171 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ldape.c,v 1.26 2017/02/24 14:28:31 gsoares Exp $ */
2
3
/*
4
 * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
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 USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/queue.h>
20
#include <sys/types.h>
21
#include <sys/socket.h>
22
#include <sys/stat.h>
23
#include <sys/un.h>
24
#include <sys/wait.h>
25
26
#include <err.h>
27
#include <errno.h>
28
#include <signal.h>
29
#include <stdlib.h>
30
#include <string.h>
31
#include <unistd.h>
32
33
#include "ldapd.h"
34
#include "log.h"
35
36
void			 ldape_sig_handler(int fd, short why, void *data);
37
static void		 ldape_auth_result(struct imsg *imsg);
38
static void		 ldape_open_result(struct imsg *imsg);
39
static void		 ldape_imsgev(struct imsgev *iev, int code,
40
			    struct imsg *imsg);
41
static void		 ldape_needfd(struct imsgev *iev);
42
43
int			 ldap_starttls(struct request *req);
44
void			 send_ldap_extended_response(struct conn *conn,
45
				int msgid, unsigned long type,
46
				long long result_code,
47
				const char *extended_oid);
48
49
struct imsgev		*iev_ldapd;
50
struct control_sock	 csock;
51
52
void
53
ldape_sig_handler(int sig, short why, void *data)
54
{
55
	log_debug("ldape: got signal %d", sig);
56
	if (sig == SIGCHLD) {
57
		for (;;) {
58
			pid_t	 pid;
59
			int	 status;
60
61
			pid = waitpid(WAIT_ANY, &status, WNOHANG);
62
			if (pid <= 0)
63
				break;
64
		}
65
		return;
66
	}
67
68
	event_loopexit(NULL);
69
}
70
71
void
72
send_ldap_extended_response(struct conn *conn, int msgid, unsigned long type,
73
    long long result_code, const char *extended_oid)
74
{
75
	int			 rc;
76
	struct ber_element	*root, *elm;
77
	void			*buf;
78
79
	log_debug("sending response %u with result %lld", type, result_code);
80
81
	if ((root = ber_add_sequence(NULL)) == NULL)
82
		goto fail;
83
84
	elm = ber_printf_elements(root, "d{tEss",
85
	    msgid, BER_CLASS_APP, type, result_code, "", "");
86
	if (elm == NULL)
87
		goto fail;
88
89
	if (extended_oid)
90
		if (ber_add_string(elm, extended_oid) == NULL)
91
			goto fail;
92
93
	ldap_debug_elements(root, type, "sending response on fd %d", conn->fd);
94
95
	rc = ber_write_elements(&conn->ber, root);
96
	ber_free_elements(root);
97
98
	if (rc < 0)
99
		log_warn("failed to create ldap result");
100
	else {
101
		ber_get_writebuf(&conn->ber, &buf);
102
		if (bufferevent_write(conn->bev, buf, rc) != 0)
103
			log_warn("failed to send ldap result");
104
	}
105
106
	return;
107
fail:
108
	if (root)
109
		ber_free_elements(root);
110
}
111
112
int
113
ldap_refer(struct request *req, const char *basedn, struct search *search,
114
    struct referrals *refs)
115
{
116
	struct ber_element	*root, *elm, *ref_root = NULL;
117
	struct referral		*ref;
118
	long long		 result_code = LDAP_REFERRAL;
119
	unsigned long		 type;
120
	int			 rc;
121
	void			*buf;
122
	char			*url, *scope_str = NULL;
123
124
	if (req->type == LDAP_REQ_SEARCH)
125
		type = LDAP_RES_SEARCH_RESULT;
126
	else
127
		type = req->type + 1;
128
129
	if (search != NULL) {
130
		if (search->scope != LDAP_SCOPE_SUBTREE)
131
			scope_str = "base";
132
		else
133
			scope_str = "sub";
134
	}
135
136
	log_debug("sending referral in response %u on msgid %lld",
137
	    type, req->msgid);
138
139
	if ((root = ber_add_sequence(NULL)) == NULL)
140
		goto fail;
141
142
	if ((elm = ref_root = ber_add_sequence(NULL)) == NULL)
143
		goto fail;
144
	ber_set_header(ref_root, BER_CLASS_CONTEXT, LDAP_REQ_SEARCH);
145
	SLIST_FOREACH(ref, refs, next) {
146
		if (search != NULL)
147
			rc = asprintf(&url, "%s/%s??%s", ref->url, basedn,
148
			    scope_str);
149
		else
150
			rc = asprintf(&url, "%s/%s", ref->url, basedn);
151
		if (rc == -1) {
152
			log_warn("asprintf");
153
			goto fail;
154
		}
155
		log_debug("adding referral '%s'", url);
156
		elm = ber_add_string(elm, url);
157
		free(url);
158
		if (elm == NULL)
159
			goto fail;
160
	}
161
162
	elm = ber_printf_elements(root, "d{tEsse",
163
	    req->msgid, BER_CLASS_APP, type, result_code, "", "", ref_root);
164
	if (elm == NULL)
165
		goto fail;
166
	ref_root = NULL;
167
168
	rc = ber_write_elements(&req->conn->ber, root);
169
	ber_free_elements(root);
170
171
	if (rc < 0)
172
		log_warn("failed to create ldap result");
173
	else {
174
		ber_get_writebuf(&req->conn->ber, &buf);
175
		if (bufferevent_write(req->conn->bev, buf, rc) != 0)
176
			log_warn("failed to send ldap result");
177
	}
178
179
	request_free(req);
180
	return LDAP_REFERRAL;
181
182
fail:
183
	if (root != NULL)
184
		ber_free_elements(root);
185
	if (ref_root != NULL)
186
		ber_free_elements(ref_root);
187
	request_free(req);
188
	return LDAP_REFERRAL;
189
}
190
191
void
192
send_ldap_result(struct conn *conn, int msgid, unsigned long type,
193
    long long result_code)
194
{
195
	send_ldap_extended_response(conn, msgid, type, result_code, NULL);
196
}
197
198
int
199
ldap_respond(struct request *req, int code)
200
{
201
	if (code >= 0)
202
		send_ldap_result(req->conn, req->msgid, req->type + 1, code);
203
	request_free(req);
204
	return code;
205
}
206
207
int
208
ldap_abandon(struct request *req)
209
{
210
	long long	 msgid;
211
	struct search	*search;
212
213
	if (ber_scanf_elements(req->op, "i", &msgid) != 0) {
214
		request_free(req);
215
		return -1;	/* protocol error, but don't respond */
216
	}
217
218
	TAILQ_FOREACH(search, &req->conn->searches, next) {
219
		if (search->req->msgid == msgid) {
220
			/* unlinks the search from conn->searches */
221
			search_close(search);
222
			break;
223
		}
224
	}
225
	request_free(req);
226
	return -1;
227
}
228
229
int
230
ldap_unbind(struct request *req)
231
{
232
	log_debug("current bind dn = %s", req->conn->binddn);
233
	conn_disconnect(req->conn);
234
	request_free(req);
235
	return -1;		/* don't send any response */
236
}
237
238
int
239
ldap_compare(struct request *req)
240
{
241
	struct ber_element	*entry, *elm, *attr;
242
	struct namespace	*ns;
243
	struct referrals	*refs;
244
	struct attr_type	*at;
245
	char			*dn, *aname, *value, *s;
246
247
	if (ber_scanf_elements(req->op, "{s{ss", &dn, &aname, &value) != 0) {
248
		log_debug("%s: protocol error", __func__);
249
		request_free(req);
250
		return -1;
251
	}
252
253
	if ((at = lookup_attribute(conf->schema, aname)) == NULL)
254
		return ldap_respond(req, LDAP_UNDEFINED_TYPE);
255
256
	if ((ns = namespace_for_base(dn)) == NULL) {
257
		refs = namespace_referrals(dn);
258
		if (refs == NULL)
259
			return ldap_respond(req, LDAP_NO_SUCH_OBJECT);
260
		else
261
			return ldap_refer(req, dn, NULL, refs);
262
	}
263
264
	if ((entry = namespace_get(ns, dn)) == NULL)
265
		return ldap_respond(req, LDAP_NO_SUCH_OBJECT);
266
267
	if ((attr = ldap_find_attribute(entry, at)) == NULL)
268
		return ldap_respond(req, LDAP_NO_SUCH_ATTRIBUTE);
269
270
	if ((attr = attr->be_next) == NULL)	/* skip attribute name */
271
		return ldap_respond(req, LDAP_OTHER);
272
273
	for (elm = attr->be_sub; elm != NULL; elm = elm->be_next) {
274
		if (ber_get_string(elm, &s) != 0)
275
			return ldap_respond(req, LDAP_OTHER);
276
		if (strcasecmp(value, s) == 0)
277
			return ldap_respond(req, LDAP_COMPARE_TRUE);
278
	}
279
280
	return ldap_respond(req, LDAP_COMPARE_FALSE);
281
}
282
283
int
284
ldap_starttls(struct request *req)
285
{
286
	if ((req->conn->listener->flags & F_STARTTLS) == 0) {
287
		log_debug("StartTLS not configured for this connection");
288
		return LDAP_OPERATIONS_ERROR;
289
	}
290
291
	req->conn->s_flags |= F_STARTTLS;
292
	return LDAP_SUCCESS;
293
}
294
295
int
296
ldap_extended(struct request *req)
297
{
298
	int			 i, rc = LDAP_PROTOCOL_ERROR;
299
	char			*oid = NULL;
300
	struct ber_element	*ext_val = NULL;
301
	struct {
302
		const char	*oid;
303
		int (*fn)(struct request *);
304
	} extended_ops[] = {
305
		{ "1.3.6.1.4.1.1466.20037", ldap_starttls },
306
		{ NULL }
307
	};
308
309
	if (ber_scanf_elements(req->op, "{se", &oid, &ext_val) != 0)
310
		goto done;
311
312
	log_debug("got extended operation %s", oid);
313
	req->op = ext_val;
314
315
	for (i = 0; extended_ops[i].oid != NULL; i++) {
316
		if (strcmp(oid, extended_ops[i].oid) == 0) {
317
			rc = extended_ops[i].fn(req);
318
			break;
319
		}
320
	}
321
322
	if (extended_ops[i].fn == NULL)
323
		log_warnx("unimplemented extended operation %s", oid);
324
325
done:
326
	send_ldap_extended_response(req->conn, req->msgid, LDAP_RES_EXTENDED,
327
	    rc, oid);
328
329
	request_free(req);
330
	return 0;
331
}
332
333
void
334
ldape(int debug, int verbose, char *csockpath)
335
{
336
	int			 on = 1;
337
	struct namespace	*ns;
338
	struct listener		*l;
339
	struct sockaddr_un	*sun = NULL;
340
	struct event		 ev_sigint;
341
	struct event		 ev_sigterm;
342
	struct event		 ev_sigchld;
343
	struct event		 ev_sighup;
344
	struct ssl		 key;
345
	struct passwd		*pw;
346
	char			 host[128];
347
	mode_t			old_umask = 0;
348
349
	log_init(debug);
350
	log_verbose(verbose);
351
352
	TAILQ_INIT(&conn_list);
353
354
	setproctitle("ldap server");
355
	event_init();
356
357
	signal_set(&ev_sigint, SIGINT, ldape_sig_handler, NULL);
358
	signal_set(&ev_sigterm, SIGTERM, ldape_sig_handler, NULL);
359
	signal_set(&ev_sigchld, SIGCHLD, ldape_sig_handler, NULL);
360
	signal_set(&ev_sighup, SIGHUP, ldape_sig_handler, NULL);
361
	signal_add(&ev_sigint, NULL);
362
	signal_add(&ev_sigterm, NULL);
363
	signal_add(&ev_sigchld, NULL);
364
	signal_add(&ev_sighup, NULL);
365
	signal(SIGPIPE, SIG_IGN);
366
367
	/* Initialize parent imsg events. */
368
	if ((iev_ldapd = calloc(1, sizeof(struct imsgev))) == NULL)
369
		fatal("calloc");
370
	imsgev_init(iev_ldapd, PROC_PARENT_SOCK_FILENO, NULL, ldape_imsgev,
371
	    ldape_needfd);
372
373
	/* Initialize control socket. */
374
	memset(&csock, 0, sizeof(csock));
375
	csock.cs_name = csockpath;
376
	control_init(&csock);
377
	control_listen(&csock);
378
	TAILQ_INIT(&ctl_conns);
379
380
	/* Initialize LDAP listeners.
381
	 */
382
	TAILQ_FOREACH(l, &conf->listeners, entry) {
383
		l->fd = socket(l->ss.ss_family, SOCK_STREAM | SOCK_NONBLOCK,
384
		    0);
385
		if (l->fd < 0)
386
			fatal("ldape: socket");
387
388
		setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
389
390
		if (l->ss.ss_family == AF_UNIX) {
391
			sun = (struct sockaddr_un *)&l->ss;
392
			log_info("listening on %s", sun->sun_path);
393
			if (unlink(sun->sun_path) == -1 && errno != ENOENT)
394
				fatal("ldape: unlink");
395
		} else {
396
			print_host(&l->ss, host, sizeof(host));
397
			log_info("listening on %s:%d", host, ntohs(l->port));
398
		}
399
400
		if (l->ss.ss_family == AF_UNIX) {
401
			old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
402
		}
403
404
		if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) != 0)
405
			fatal("ldape: bind");
406
407
		if (l->ss.ss_family == AF_UNIX) {
408
			mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
409
410
			(void)umask(old_umask);
411
			if (chmod(sun->sun_path, mode) == -1) {
412
				unlink(sun->sun_path);
413
				fatal("ldape: chmod");
414
			}
415
		}
416
417
		if (listen(l->fd, 20) != 0)
418
			fatal("ldape: listen");
419
420
		event_set(&l->ev, l->fd, EV_READ, conn_accept, l);
421
		event_add(&l->ev, NULL);
422
		evtimer_set(&l->evt, conn_accept, l);
423
424
		if (l->flags & F_SSL) {
425
			if (strlcpy(key.ssl_name, l->ssl_cert_name,
426
			    sizeof(key.ssl_name)) >= sizeof(key.ssl_name))
427
				fatal("ldape: certificate name truncated");
428
429
			l->ssl = SPLAY_FIND(ssltree, conf->sc_ssl, &key);
430
			if (l->ssl == NULL)
431
				fatal("ldape: certificate tree corrupted");
432
433
			l->tls = tls_server();
434
			if (l->tls == NULL)
435
				fatal("ldape: couldn't allocate tls context");
436
437
			if (tls_configure(l->tls, l->ssl->config)) {
438
				log_warn("ldape: %s", tls_error(l->tls));
439
				fatal("ldape: couldn't configure tls");
440
			}
441
		}
442
	}
443
444
	TAILQ_FOREACH(ns, &conf->namespaces, next) {
445
		if (!namespace_has_referrals(ns) && namespace_open(ns) != 0)
446
			fatal(ns->suffix);
447
	}
448
449
	if ((pw = getpwnam(LDAPD_USER)) == NULL)
450
		fatal("getpwnam");
451
452
	if (pw != NULL) {
453
		if (chroot(pw->pw_dir) == -1)
454
			fatal("chroot");
455
		if (chdir("/") == -1)
456
			fatal("chdir(\"/\")");
457
458
		if (setgroups(1, &pw->pw_gid) ||
459
		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
460
		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
461
			fatal("cannot drop privileges");
462
	}
463
464
	if (pledge("stdio flock inet unix recvfd rpath cpath wpath", NULL) == -1)
465
		fatal("pledge");
466
467
	log_debug("ldape: entering event loop");
468
	event_dispatch();
469
470
	while ((ns = TAILQ_FIRST(&conf->namespaces)) != NULL)
471
		namespace_remove(ns);
472
473
	control_cleanup(&csock);
474
475
	log_info("ldape: exiting");
476
	exit(0);
477
}
478
479
static void
480
ldape_imsgev(struct imsgev *iev, int code, struct imsg *imsg)
481
{
482
	switch (code) {
483
	case IMSGEV_IMSG:
484
		log_debug("%s: got imsg %d on fd %d",
485
		    __func__, imsg->hdr.type, iev->ibuf.fd);
486
		switch (imsg->hdr.type) {
487
		case IMSG_LDAPD_AUTH_RESULT:
488
			ldape_auth_result(imsg);
489
			break;
490
		case IMSG_LDAPD_OPEN_RESULT:
491
			ldape_open_result(imsg);
492
			break;
493
		default:
494
			log_debug("%s: unexpected imsg %d",
495
			    __func__, imsg->hdr.type);
496
			break;
497
		}
498
		break;
499
	case IMSGEV_EREAD:
500
	case IMSGEV_EWRITE:
501
	case IMSGEV_EIMSG:
502
		fatal("imsgev read/write error");
503
		break;
504
	case IMSGEV_DONE:
505
		event_loopexit(NULL);
506
		break;
507
	}
508
}
509
510
static void
511
ldape_needfd(struct imsgev *iev)
512
{
513
	/* Try to close a control connection first */
514
	if (control_close_any(&csock) == 0) {
515
		log_warn("closed a control connection");
516
		return;
517
	}
518
519
	if (conn_close_any() == 0) {
520
		log_warn("closed a client connection");
521
		return;
522
	}
523
524
	fatal("unable to free an fd");
525
}
526
527
static void
528
ldape_auth_result(struct imsg *imsg)
529
{
530
	struct conn		*conn;
531
	struct auth_res		*ares = imsg->data;
532
533
	log_debug("authentication on conn %d/%lld = %d", ares->fd, ares->msgid,
534
	    ares->ok);
535
	conn = conn_by_fd(ares->fd);
536
	if (conn->bind_req != NULL && conn->bind_req->msgid == ares->msgid)
537
		ldap_bind_continue(conn, ares->ok);
538
	else
539
		log_warnx("spurious auth result");
540
}
541
542
static void
543
ldape_open_result(struct imsg *imsg)
544
{
545
	struct namespace	*ns;
546
	struct open_req		*oreq = imsg->data;
547
548
	if (imsg->hdr.len != sizeof(*oreq) + IMSG_HEADER_SIZE)
549
		fatal("invalid size of open result");
550
551
	/* make sure path is null-terminated */
552
	oreq->path[PATH_MAX] = '\0';
553
554
	log_debug("open(%s) returned fd %d", oreq->path, imsg->fd);
555
556
	TAILQ_FOREACH(ns, &conf->namespaces, next) {
557
		if (namespace_has_referrals(ns))
558
			continue;
559
		if (strcmp(oreq->path, ns->data_path) == 0) {
560
			namespace_set_data_fd(ns, imsg->fd);
561
			break;
562
		}
563
		if (strcmp(oreq->path, ns->indx_path) == 0) {
564
			namespace_set_indx_fd(ns, imsg->fd);
565
			break;
566
		}
567
	}
568
569
	if (ns == NULL) {
570
		log_warnx("spurious open result");
571
		close(imsg->fd);
572
	} else
573
		namespace_queue_schedule(ns, 0);
574
}
575