xref: /openbsd/usr.sbin/ldapd/namespace.c (revision 403185e4)
1 /*	$OpenBSD: namespace.c,v 1.20 2020/03/05 07:39:25 martijn 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 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
namespace_begin_txn(struct namespace * ns,struct btree_txn ** data_txn,struct btree_txn ** indx_txn,int rdonly)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
namespace_begin(struct namespace * ns)72 namespace_begin(struct namespace *ns)
73 {
74 	return namespace_begin_txn(ns, &ns->data_txn, &ns->indx_txn, 0);
75 }
76 
77 int
namespace_commit(struct namespace * ns)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
namespace_abort(struct namespace * ns)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
namespace_open(struct namespace * ns)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) == -1)
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) == -1)
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
namespace_reopen(const char * path)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
namespace_reopen_data(struct namespace * ns)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
namespace_reopen_indx(struct namespace * ns)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
namespace_set_fd(struct namespace * ns,struct btree ** bt,int fd,unsigned int flags)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
namespace_set_data_fd(struct namespace * ns,int fd)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
namespace_set_indx_fd(struct namespace * ns,int fd)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
namespace_close(struct namespace * ns)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
namespace_remove(struct namespace * ns)249 namespace_remove(struct namespace *ns)
250 {
251 	TAILQ_REMOVE(&conf->namespaces, ns, next);
252 	namespace_close(ns);
253 }
254 
255 static struct btval *
namespace_find(struct namespace * ns,char * dn)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 *
namespace_get(struct namespace * ns,char * dn)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
namespace_exists(struct namespace * ns,char * dn)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
namespace_ber2db(struct namespace * ns,struct ber_element * root,struct btval * val)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 *
namespace_db2ber(struct namespace * ns,struct btval * val)320 namespace_db2ber(struct namespace *ns, struct btval *val)
321 {
322 	return db2ber(val, ns->compression_level);
323 }
324 
325 static int
namespace_put(struct namespace * ns,char * dn,struct ber_element * root,int update)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
namespace_add(struct namespace * ns,char * dn,struct ber_element * root)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
namespace_update(struct namespace * ns,char * dn,struct ber_element * root)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
namespace_del(struct namespace * ns,char * dn)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
namespace_has_referrals(struct namespace * ns)403 namespace_has_referrals(struct namespace *ns)
404 {
405 	return !SLIST_EMPTY(&ns->referrals);
406 }
407 
408 struct namespace *
namespace_lookup_base(const char * basedn,int include_referrals)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 *
namespace_for_base(const char * basedn)433 namespace_for_base(const char *basedn)
434 {
435 	return namespace_lookup_base(basedn, 0);
436 }
437 
438 struct referrals *
namespace_referrals(const char * basedn)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
namespace_has_index(struct namespace * ns,const char * attr,enum index_type type)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
namespace_queue_request(struct namespace * ns,struct request * req)472 namespace_queue_request(struct namespace *ns, struct request *req)
473 {
474 	if (ns->queued_requests > MAX_REQUEST_QUEUE) {
475 		log_warn("%u requests already queued, sorry",
476 		    ns->queued_requests);
477 		return -1;
478 	}
479 
480 	TAILQ_INSERT_TAIL(&ns->request_queue, req, next);
481 	ns->queued_requests++;
482 
483 	if (!evtimer_pending(&ns->ev_queue, NULL))
484 		namespace_queue_schedule(ns, 250000);
485 
486 	return 0;
487 }
488 
489 static void
namespace_queue_replay(int fd,short event,void * data)490 namespace_queue_replay(int fd, short event, void *data)
491 {
492 	struct namespace	*ns = data;
493 	struct request		*req;
494 
495 	if (ns->data_db == NULL || ns->indx_db == NULL) {
496 		log_debug("%s: database is being reopened", ns->suffix);
497 		return;		/* Database is being reopened. */
498 	}
499 
500 	if ((req = TAILQ_FIRST(&ns->request_queue)) == NULL)
501 		return;
502 	TAILQ_REMOVE(&ns->request_queue, req, next);
503 
504 	log_debug("replaying queued request");
505 	req->replayed = 1;
506 	request_dispatch(req);
507 	ns->queued_requests--;
508 
509 	if (!evtimer_pending(&ns->ev_queue, NULL))
510 		namespace_queue_schedule(ns, 0);
511 }
512 
513 void
namespace_queue_schedule(struct namespace * ns,unsigned int usec)514 namespace_queue_schedule(struct namespace *ns, unsigned int usec)
515 {
516 	struct timeval	 tv;
517 
518 	tv.tv_sec = 0;
519 	tv.tv_usec = usec;
520 	evtimer_add(&ns->ev_queue, &tv);
521 }
522 
523 /* Cancel all queued requests from the given connection. Drops matching
524  * requests from all namespaces without sending a response.
525  */
526 void
namespace_cancel_conn(struct conn * conn)527 namespace_cancel_conn(struct conn *conn)
528 {
529 	struct namespace	*ns;
530 	struct request		*req, *next;
531 
532 	TAILQ_FOREACH(ns, &conf->namespaces, next) {
533 		for (req = TAILQ_FIRST(&ns->request_queue); req != NULL;
534 		    req = next) {
535 			next = TAILQ_NEXT(req, next);
536 
537 			if (req->conn == conn) {
538 				TAILQ_REMOVE(&ns->request_queue, req, next);
539 				request_free(req);
540 			}
541 		}
542 	}
543 }
544 
545 int
namespace_conn_queue_count(struct conn * conn)546 namespace_conn_queue_count(struct conn *conn)
547 {
548 	struct namespace	*ns;
549 	struct request		*req;
550 	int			 count = 0;
551 
552 	TAILQ_FOREACH(ns, &conf->namespaces, next) {
553 		TAILQ_FOREACH(req, &ns->request_queue, next) {
554 			if (req->conn == conn)
555 				count++;
556 		}
557 	}
558 
559 	return count;
560 }
561