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

Line Branch Exec Source
1
/*	$OpenBSD: namespace.c,v 1.17 2017/01/20 11:55:08 benno 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/types.h>
20
#include <sys/queue.h>
21
22
#include <assert.h>
23
#include <errno.h>
24
#include <stdio.h>
25
#include <stdlib.h>
26
#include <string.h>
27
#include <zlib.h>
28
29
#include "ldapd.h"
30
#include "log.h"
31
32
extern const char	*datadir;
33
34
/* Maximum number of requests to queue per namespace during compaction.
35
 * After this many requests, we return LDAP_BUSY.
36
 */
37
#define MAX_REQUEST_QUEUE	 10000
38
39
static struct btval	*namespace_find(struct namespace *ns, char *dn);
40
static void		 namespace_queue_replay(int fd, short event, void *arg);
41
static int		 namespace_set_fd(struct namespace *ns,
42
			    struct btree **bt, int fd, unsigned int flags);
43
44
int
45
namespace_begin_txn(struct namespace *ns, struct btree_txn **data_txn,
46
    struct btree_txn **indx_txn, int rdonly)
47
{
48
	if (ns->data_db == NULL || ns->indx_db == NULL) {
49
		errno = EBUSY;	/* namespace is being reopened */
50
		return -1;
51
	}
52
53
	if ((*data_txn = btree_txn_begin(ns->data_db, rdonly)) == NULL ||
54
	    (*indx_txn = btree_txn_begin(ns->indx_db, rdonly)) == NULL) {
55
		if (errno == ESTALE) {
56
			if (*data_txn == NULL)
57
				namespace_reopen_data(ns);
58
			else
59
				namespace_reopen_indx(ns);
60
			errno = EBUSY;
61
		}
62
		log_warn("failed to open transaction");
63
		btree_txn_abort(*data_txn);
64
		*data_txn = NULL;
65
		return -1;
66
	}
67
68
	return 0;
69
}
70
71
int
72
namespace_begin(struct namespace *ns)
73
{
74
	return namespace_begin_txn(ns, &ns->data_txn, &ns->indx_txn, 0);
75
}
76
77
int
78
namespace_commit(struct namespace *ns)
79
{
80
	if (ns->indx_txn != NULL &&
81
	    btree_txn_commit(ns->indx_txn) != BT_SUCCESS) {
82
		log_warn("%s(indx): commit failed", ns->suffix);
83
		btree_txn_abort(ns->data_txn);
84
		ns->indx_txn = ns->data_txn = NULL;
85
		return -1;
86
	}
87
	ns->indx_txn = NULL;
88
89
	if (ns->data_txn != NULL &&
90
	    btree_txn_commit(ns->data_txn) != BT_SUCCESS) {
91
		log_warn("%s(data): commit failed", ns->suffix);
92
		ns->data_txn = NULL;
93
		return -1;
94
	}
95
	ns->data_txn = NULL;
96
97
	return 0;
98
}
99
100
void
101
namespace_abort(struct namespace *ns)
102
{
103
	btree_txn_abort(ns->data_txn);
104
	ns->data_txn = NULL;
105
106
	btree_txn_abort(ns->indx_txn);
107
	ns->indx_txn = NULL;
108
}
109
110
int
111
namespace_open(struct namespace *ns)
112
{
113
	unsigned int	 db_flags = 0;
114
115
	assert(ns);
116
	assert(ns->suffix);
117
118
	if (ns->sync == 0)
119
		db_flags |= BT_NOSYNC;
120
121
	if (asprintf(&ns->data_path, "%s/%s_data.db", datadir, ns->suffix) < 0)
122
		return -1;
123
	log_info("opening namespace %s", ns->suffix);
124
	ns->data_db = btree_open(ns->data_path, db_flags | BT_REVERSEKEY, 0644);
125
	if (ns->data_db == NULL)
126
		return -1;
127
128
	btree_set_cache_size(ns->data_db, ns->cache_size);
129
130
	if (asprintf(&ns->indx_path, "%s/%s_indx.db", datadir, ns->suffix) < 0)
131
		return -1;
132
	ns->indx_db = btree_open(ns->indx_path, db_flags, 0644);
133
	if (ns->indx_db == NULL)
134
		return -1;
135
136
	btree_set_cache_size(ns->indx_db, ns->index_cache_size);
137
138
	/* prepare request queue scheduler */
139
	evtimer_set(&ns->ev_queue, namespace_queue_replay, ns);
140
141
	return 0;
142
}
143
144
static int
145
namespace_reopen(const char *path)
146
{
147
	struct open_req		 req;
148
149
	log_debug("asking parent to open %s", path);
150
151
	memset(&req, 0, sizeof(req));
152
	if (strlcpy(req.path, path, sizeof(req.path)) >= sizeof(req.path)) {
153
		log_warnx("%s: path truncated", __func__);
154
		return -1;
155
	}
156
157
	return imsgev_compose(iev_ldapd, IMSG_LDAPD_OPEN, 0, 0, -1, &req,
158
	    sizeof(req));
159
}
160
161
int
162
namespace_reopen_data(struct namespace *ns)
163
{
164
	if (ns->data_db != NULL) {
165
		btree_close(ns->data_db);
166
		ns->data_db = NULL;
167
		return namespace_reopen(ns->data_path);
168
	}
169
	return 1;
170
}
171
172
int
173
namespace_reopen_indx(struct namespace *ns)
174
{
175
	if (ns->indx_db != NULL) {
176
		btree_close(ns->indx_db);
177
		ns->indx_db = NULL;
178
		return namespace_reopen(ns->indx_path);
179
	}
180
	return 1;
181
}
182
183
static int
184
namespace_set_fd(struct namespace *ns, struct btree **bt, int fd,
185
    unsigned int flags)
186
{
187
	log_info("reopening namespace %s (entries)", ns->suffix);
188
	btree_close(*bt);
189
	if (ns->sync == 0)
190
		flags |= BT_NOSYNC;
191
	*bt = btree_open_fd(fd, flags);
192
	if (*bt == NULL)
193
		return -1;
194
	return 0;
195
}
196
197
int
198
namespace_set_data_fd(struct namespace *ns, int fd)
199
{
200
	return namespace_set_fd(ns, &ns->data_db, fd, BT_REVERSEKEY);
201
}
202
203
int
204
namespace_set_indx_fd(struct namespace *ns, int fd)
205
{
206
	return namespace_set_fd(ns, &ns->indx_db, fd, 0);
207
}
208
209
void
210
namespace_close(struct namespace *ns)
211
{
212
	struct conn		*conn;
213
	struct search		*search, *next;
214
	struct request		*req;
215
216
	/* Cancel any queued requests for this namespace.
217
	 */
218
	if (ns->queued_requests > 0) {
219
		log_warnx("cancelling %u queued requests on namespace %s",
220
		    ns->queued_requests, ns->suffix);
221
		while ((req = TAILQ_FIRST(&ns->request_queue)) != NULL) {
222
			TAILQ_REMOVE(&ns->request_queue, req, next);
223
			ldap_respond(req, LDAP_UNAVAILABLE);
224
		}
225
	}
226
227
	/* Cancel any searches on this namespace.
228
	 */
229
	TAILQ_FOREACH(conn, &conn_list, next) {
230
		for (search = TAILQ_FIRST(&conn->searches); search != NULL;
231
		    search = next) {
232
			next = TAILQ_NEXT(search, next);
233
			if (search->ns == ns)
234
				search_close(search);
235
		}
236
	}
237
238
	free(ns->suffix);
239
	btree_close(ns->data_db);
240
	btree_close(ns->indx_db);
241
	if (evtimer_pending(&ns->ev_queue, NULL))
242
		evtimer_del(&ns->ev_queue);
243
	free(ns->data_path);
244
	free(ns->indx_path);
245
	free(ns);
246
}
247
248
void
249
namespace_remove(struct namespace *ns)
250
{
251
	TAILQ_REMOVE(&conf->namespaces, ns, next);
252
	namespace_close(ns);
253
}
254
255
static struct btval *
256
namespace_find(struct namespace *ns, char *dn)
257
{
258
	struct btval		 key;
259
	static struct btval	 val;
260
261
	if (ns->data_db == NULL) {
262
		errno = EBUSY;	/* namespace is being reopened */
263
		return NULL;
264
	}
265
266
	memset(&key, 0, sizeof(key));
267
	memset(&val, 0, sizeof(val));
268
269
	key.data = dn;
270
	key.size = strlen(dn);
271
272
	if (btree_txn_get(ns->data_db, ns->data_txn, &key, &val) != 0) {
273
		if (errno == ENOENT)
274
			log_debug("%s: dn not found", dn);
275
		else
276
			log_warn("%s", dn);
277
278
		if (errno == ESTALE)
279
			namespace_reopen_data(ns);
280
281
		return NULL;
282
	}
283
284
	return &val;
285
}
286
287
struct ber_element *
288
namespace_get(struct namespace *ns, char *dn)
289
{
290
	struct ber_element	*elm;
291
	struct btval		*val;
292
293
	if ((val = namespace_find(ns, dn)) == NULL)
294
		return NULL;
295
296
	elm = namespace_db2ber(ns, val);
297
	btval_reset(val);
298
	return elm;
299
}
300
301
int
302
namespace_exists(struct namespace *ns, char *dn)
303
{
304
	struct btval		*val;
305
306
	if ((val = namespace_find(ns, dn)) == NULL)
307
		return 0;
308
	btval_reset(val);
309
	return 1;
310
}
311
312
int
313
namespace_ber2db(struct namespace *ns, struct ber_element *root,
314
    struct btval *val)
315
{
316
	return ber2db(root, val, ns->compression_level);
317
}
318
319
struct ber_element *
320
namespace_db2ber(struct namespace *ns, struct btval *val)
321
{
322
	return db2ber(val, ns->compression_level);
323
}
324
325
static int
326
namespace_put(struct namespace *ns, char *dn, struct ber_element *root,
327
    int update)
328
{
329
	int			 rc;
330
	struct btval		 key, val;
331
332
	assert(ns != NULL);
333
	assert(ns->data_txn != NULL);
334
	assert(ns->indx_txn != NULL);
335
336
	memset(&key, 0, sizeof(key));
337
	key.data = dn;
338
	key.size = strlen(dn);
339
340
	if (namespace_ber2db(ns, root, &val) != 0)
341
		return BT_FAIL;
342
343
	rc = btree_txn_put(NULL, ns->data_txn, &key, &val,
344
	    update ? 0 : BT_NOOVERWRITE);
345
	if (rc != BT_SUCCESS) {
346
		if (errno == EEXIST)
347
			log_debug("%s: already exists", dn);
348
		else
349
			log_warn("%s", dn);
350
		goto done;
351
	}
352
353
	/* FIXME: if updating, try harder to just update changed indices.
354
	 */
355
	if (update && (rc = unindex_entry(ns, &key, root)) != BT_SUCCESS)
356
		goto done;
357
358
	rc = index_entry(ns, &key, root);
359
360
done:
361
	btval_reset(&val);
362
	return rc;
363
}
364
365
int
366
namespace_add(struct namespace *ns, char *dn, struct ber_element *root)
367
{
368
	return namespace_put(ns, dn, root, 0);
369
}
370
371
int
372
namespace_update(struct namespace *ns, char *dn, struct ber_element *root)
373
{
374
	return namespace_put(ns, dn, root, 1);
375
}
376
377
int
378
namespace_del(struct namespace *ns, char *dn)
379
{
380
	int			 rc;
381
	struct ber_element	*root;
382
	struct btval		 key, data;
383
384
	assert(ns != NULL);
385
	assert(ns->indx_txn != NULL);
386
	assert(ns->data_txn != NULL);
387
388
	memset(&key, 0, sizeof(key));
389
	memset(&data, 0, sizeof(data));
390
391
	key.data = dn;
392
	key.size = strlen(key.data);
393
394
	rc = btree_txn_del(NULL, ns->data_txn, &key, &data);
395
	if (rc == BT_SUCCESS && (root = namespace_db2ber(ns, &data)) != NULL)
396
		rc = unindex_entry(ns, &key, root);
397
398
	btval_reset(&data);
399
	return rc;
400
}
401
402
int
403
namespace_has_referrals(struct namespace *ns)
404
{
405
	return !SLIST_EMPTY(&ns->referrals);
406
}
407
408
struct namespace *
409
namespace_lookup_base(const char *basedn, int include_referrals)
410
{
411
	size_t			 blen, slen;
412
	struct namespace	*ns, *matched_ns = NULL;
413
414
	assert(basedn);
415
	blen = strlen(basedn);
416
417
	TAILQ_FOREACH(ns, &conf->namespaces, next) {
418
		slen = strlen(ns->suffix);
419
		if ((include_referrals || !namespace_has_referrals(ns)) &&
420
		    blen >= slen &&
421
		    bcmp(basedn + blen - slen, ns->suffix, slen) == 0) {
422
			/* Match the longest namespace suffix. */
423
			if (matched_ns == NULL ||
424
			    strlen(ns->suffix) > strlen(matched_ns->suffix))
425
				matched_ns = ns;
426
		}
427
	}
428
429
	return matched_ns;
430
}
431
432
struct namespace *
433
namespace_for_base(const char *basedn)
434
{
435
	return namespace_lookup_base(basedn, 0);
436
}
437
438
struct referrals *
439
namespace_referrals(const char *basedn)
440
{
441
	struct namespace	*ns;
442
443
	if ((ns = namespace_lookup_base(basedn, 1)) != NULL &&
444
	    namespace_has_referrals(ns))
445
		return &ns->referrals;
446
447
	if (!SLIST_EMPTY(&conf->referrals))
448
		return &conf->referrals;
449
450
	return NULL;
451
}
452
453
int
454
namespace_has_index(struct namespace *ns, const char *attr,
455
    enum index_type type)
456
{
457
	struct attr_index	*ai;
458
459
	assert(ns);
460
	assert(attr);
461
	TAILQ_FOREACH(ai, &ns->indices, next) {
462
		if (strcasecmp(attr, ai->attr) == 0 && ai->type == type)
463
			return 1;
464
	}
465
466
	return 0;
467
}
468
469
/* Queues modification requests while the namespace is being reopened.
470
 */
471
int
472
namespace_queue_request(struct namespace *ns, struct request *req)
473
{
474
	if (ns->queued_requests > MAX_REQUEST_QUEUE) {
475
		log_warn("%u requests alreay queued, sorry");
476
		return -1;
477
	}
478
479
	TAILQ_INSERT_TAIL(&ns->request_queue, req, next);
480
	ns->queued_requests++;
481
482
	if (!evtimer_pending(&ns->ev_queue, NULL))
483
		namespace_queue_schedule(ns, 250000);
484
485
	return 0;
486
}
487
488
static void
489
namespace_queue_replay(int fd, short event, void *data)
490
{
491
	struct namespace	*ns = data;
492
	struct request		*req;
493
494
	if (ns->data_db == NULL || ns->indx_db == NULL) {
495
		log_debug("%s: database is being reopened", ns->suffix);
496
		return;		/* Database is being reopened. */
497
	}
498
499
	if ((req = TAILQ_FIRST(&ns->request_queue)) == NULL)
500
		return;
501
	TAILQ_REMOVE(&ns->request_queue, req, next);
502
503
	log_debug("replaying queued request");
504
	req->replayed = 1;
505
	request_dispatch(req);
506
	ns->queued_requests--;
507
508
	if (!evtimer_pending(&ns->ev_queue, NULL))
509
		namespace_queue_schedule(ns, 0);
510
}
511
512
void
513
namespace_queue_schedule(struct namespace *ns, unsigned int usec)
514
{
515
	struct timeval	 tv;
516
517
	tv.tv_sec = 0;
518
	tv.tv_usec = usec;
519
	evtimer_add(&ns->ev_queue, &tv);
520
}
521
522
/* Cancel all queued requests from the given connection. Drops matching
523
 * requests from all namespaces without sending a response.
524
 */
525
void
526
namespace_cancel_conn(struct conn *conn)
527
{
528
	struct namespace	*ns;
529
	struct request		*req, *next;
530
531
	TAILQ_FOREACH(ns, &conf->namespaces, next) {
532
		for (req = TAILQ_FIRST(&ns->request_queue); req != NULL;
533
		    req = next) {
534
			next = TAILQ_NEXT(req, next);
535
536
			if (req->conn == conn) {
537
				TAILQ_REMOVE(&ns->request_queue, req, next);
538
				request_free(req);
539
			}
540
		}
541
	}
542
}
543
544
int
545
namespace_conn_queue_count(struct conn *conn)
546
{
547
	struct namespace	*ns;
548
	struct request		*req;
549
	int			 count = 0;
550
551
	TAILQ_FOREACH(ns, &conf->namespaces, next) {
552
		TAILQ_FOREACH(req, &ns->request_queue, next) {
553
			if (req->conn == conn)
554
				count++;
555
		}
556
	}
557
558
	return count;
559
}