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