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