1/* 2 ldb database library 3 4 Copyright (C) Andrew Tridgell 2004 5 6 ** NOTE! The following LGPL license applies to the ldb 7 ** library. This does NOT imply that all of Samba is released 8 ** under the LGPL 9 10 This library is free software; you can redistribute it and/or 11 modify it under the terms of the GNU Lesser General Public 12 License as published by the Free Software Foundation; either 13 version 3 of the License, or (at your option) any later version. 14 15 This library is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 Lesser General Public License for more details. 19 20 You should have received a copy of the GNU Lesser General Public 21 License along with this library; if not, see <http://www.gnu.org/licenses/>. 22*/ 23 24/* 25 * Name: ldb 26 * 27 * Component: ldb tdb cache functions 28 * 29 * Description: cache special records in a ldb/tdb 30 * 31 * Author: Andrew Tridgell 32 */ 33 34#include "includes.h" 35#include "ldb/include/includes.h" 36 37#include "ldb/ldb_tdb/ldb_tdb.h" 38 39#define LTDB_FLAG_CASE_INSENSITIVE (1<<0) 40#define LTDB_FLAG_INTEGER (1<<1) 41#define LTDB_FLAG_HIDDEN (1<<2) 42#define LTDB_FLAG_OBJECTCLASS (1<<3) 43 44int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name); 45 46/* valid attribute flags */ 47static const struct { 48 const char *name; 49 int value; 50} ltdb_valid_attr_flags[] = { 51 { "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE }, 52 { "INTEGER", LTDB_FLAG_INTEGER }, 53 { "HIDDEN", LTDB_FLAG_HIDDEN }, 54 { "NONE", 0 }, 55 { NULL, 0 } 56}; 57 58 59/* 60 de-register any special handlers for @ATTRIBUTES 61*/ 62static void ltdb_attributes_unload(struct ldb_module *module) 63{ 64 struct ltdb_private *ltdb = 65 (struct ltdb_private *)module->private_data; 66 struct ldb_message *msg; 67 int i; 68 69 if (ltdb->cache->attributes == NULL) { 70 /* no previously loaded attributes */ 71 return; 72 } 73 74 msg = ltdb->cache->attributes; 75 for (i=0;i<msg->num_elements;i++) { 76 ldb_remove_attrib_handler(module->ldb, msg->elements[i].name); 77 } 78 79 talloc_free(ltdb->cache->attributes); 80 ltdb->cache->attributes = NULL; 81} 82 83/* 84 add up the attrib flags for a @ATTRIBUTES element 85*/ 86static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v) 87{ 88 int i; 89 unsigned value = 0; 90 for (i=0;i<el->num_values;i++) { 91 int j; 92 for (j=0;ltdb_valid_attr_flags[j].name;j++) { 93 if (strcmp(ltdb_valid_attr_flags[j].name, 94 (char *)el->values[i].data) == 0) { 95 value |= ltdb_valid_attr_flags[j].value; 96 break; 97 } 98 } 99 if (ltdb_valid_attr_flags[j].name == NULL) { 100 return -1; 101 } 102 } 103 *v = value; 104 return 0; 105} 106 107/* 108 register any special handlers from @ATTRIBUTES 109*/ 110static int ltdb_attributes_load(struct ldb_module *module) 111{ 112 struct ltdb_private *ltdb = 113 (struct ltdb_private *)module->private_data; 114 struct ldb_message *msg = ltdb->cache->attributes; 115 struct ldb_dn *dn; 116 int i; 117 118 dn = ldb_dn_explode(module->ldb, LTDB_ATTRIBUTES); 119 if (dn == NULL) goto failed; 120 121 if (ltdb_search_dn1(module, dn, msg) == -1) { 122 talloc_free(dn); 123 goto failed; 124 } 125 talloc_free(dn); 126 /* mapping these flags onto ldap 'syntaxes' isn't strictly correct, 127 but its close enough for now */ 128 for (i=0;i<msg->num_elements;i++) { 129 unsigned flags; 130 const char *syntax; 131 const struct ldb_attrib_handler *h; 132 struct ldb_attrib_handler h2; 133 134 if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) { 135 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'\n", msg->elements[i].name); 136 goto failed; 137 } 138 switch (flags & ~LTDB_FLAG_HIDDEN) { 139 case 0: 140 syntax = LDB_SYNTAX_OCTET_STRING; 141 break; 142 case LTDB_FLAG_CASE_INSENSITIVE: 143 syntax = LDB_SYNTAX_DIRECTORY_STRING; 144 break; 145 case LTDB_FLAG_INTEGER: 146 syntax = LDB_SYNTAX_INTEGER; 147 break; 148 default: 149 ldb_debug(module->ldb, LDB_DEBUG_ERROR, 150 "Invalid flag combination 0x%x for '%s' in @ATTRIBUTES\n", 151 flags, msg->elements[i].name); 152 goto failed; 153 } 154 155 h = ldb_attrib_handler_syntax(module->ldb, syntax); 156 if (h == NULL) { 157 ldb_debug(module->ldb, LDB_DEBUG_ERROR, 158 "Invalid attribute syntax '%s' for '%s' in @ATTRIBUTES\n", 159 syntax, msg->elements[i].name); 160 goto failed; 161 } 162 h2 = *h; 163 h2.attr = msg->elements[i].name; 164 h2.flags |= LDB_ATTR_FLAG_ALLOCATED; 165 if (ldb_set_attrib_handlers(module->ldb, &h2, 1) != 0) { 166 goto failed; 167 } 168 } 169 170 return 0; 171failed: 172 return -1; 173} 174 175 176/* 177 register any subclasses from @SUBCLASSES 178*/ 179static int ltdb_subclasses_load(struct ldb_module *module) 180{ 181 struct ltdb_private *ltdb = 182 (struct ltdb_private *)module->private_data; 183 struct ldb_message *msg = ltdb->cache->subclasses; 184 struct ldb_dn *dn; 185 int i, j; 186 187 dn = ldb_dn_explode(module->ldb, LTDB_SUBCLASSES); 188 if (dn == NULL) goto failed; 189 190 if (ltdb_search_dn1(module, dn, msg) == -1) { 191 talloc_free(dn); 192 goto failed; 193 } 194 talloc_free(dn); 195 196 for (i=0;i<msg->num_elements;i++) { 197 struct ldb_message_element *el = &msg->elements[i]; 198 for (j=0;j<el->num_values;j++) { 199 if (ldb_subclass_add(module->ldb, el->name, 200 (char *)el->values[j].data) != 0) { 201 goto failed; 202 } 203 } 204 } 205 206 return 0; 207failed: 208 return -1; 209} 210 211 212/* 213 de-register any @SUBCLASSES 214*/ 215static void ltdb_subclasses_unload(struct ldb_module *module) 216{ 217 struct ltdb_private *ltdb = 218 (struct ltdb_private *)module->private_data; 219 struct ldb_message *msg; 220 int i; 221 222 if (ltdb->cache->subclasses == NULL) { 223 /* no previously loaded subclasses */ 224 return; 225 } 226 227 msg = ltdb->cache->subclasses; 228 for (i=0;i<msg->num_elements;i++) { 229 ldb_subclass_remove(module->ldb, msg->elements[i].name); 230 } 231 232 talloc_free(ltdb->cache->subclasses); 233 ltdb->cache->subclasses = NULL; 234} 235 236 237/* 238 initialise the baseinfo record 239*/ 240static int ltdb_baseinfo_init(struct ldb_module *module) 241{ 242 struct ltdb_private *ltdb = 243 (struct ltdb_private *)module->private_data; 244 struct ldb_message *msg; 245 struct ldb_message_element el; 246 struct ldb_val val; 247 int ret; 248 /* the initial sequence number must be different from the one 249 set in ltdb_cache_free(). Thanks to Jon for pointing this 250 out. */ 251 const char *initial_sequence_number = "1"; 252 253 ltdb->sequence_number = atof(initial_sequence_number); 254 255 msg = talloc(ltdb, struct ldb_message); 256 if (msg == NULL) { 257 goto failed; 258 } 259 260 msg->num_elements = 1; 261 msg->elements = ⪙ 262 msg->dn = ldb_dn_explode(msg, LTDB_BASEINFO); 263 if (!msg->dn) { 264 goto failed; 265 } 266 el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER); 267 if (!el.name) { 268 goto failed; 269 } 270 el.values = &val; 271 el.num_values = 1; 272 el.flags = 0; 273 val.data = (uint8_t *)talloc_strdup(msg, initial_sequence_number); 274 if (!val.data) { 275 goto failed; 276 } 277 val.length = 1; 278 279 ret = ltdb_store(module, msg, TDB_INSERT); 280 281 talloc_free(msg); 282 283 return ret; 284 285failed: 286 talloc_free(msg); 287 errno = ENOMEM; 288 return -1; 289} 290 291/* 292 free any cache records 293 */ 294static void ltdb_cache_free(struct ldb_module *module) 295{ 296 struct ltdb_private *ltdb = 297 (struct ltdb_private *)module->private_data; 298 299 ltdb->sequence_number = 0; 300 talloc_free(ltdb->cache); 301 ltdb->cache = NULL; 302} 303 304/* 305 force a cache reload 306*/ 307int ltdb_cache_reload(struct ldb_module *module) 308{ 309 ltdb_attributes_unload(module); 310 ltdb_subclasses_unload(module); 311 ltdb_cache_free(module); 312 return ltdb_cache_load(module); 313} 314 315/* 316 load the cache records 317*/ 318int ltdb_cache_load(struct ldb_module *module) 319{ 320 struct ltdb_private *ltdb = 321 (struct ltdb_private *)module->private_data; 322 struct ldb_dn *baseinfo_dn = NULL; 323 struct ldb_dn *indexlist_dn = NULL; 324 uint64_t seq; 325 struct ldb_message *baseinfo = NULL; 326 327 /* a very fast check to avoid extra database reads */ 328 if (ltdb->cache != NULL && 329 tdb_get_seqnum(ltdb->tdb) == ltdb->tdb_seqnum) { 330 return 0; 331 } 332 333 if (ltdb->cache == NULL) { 334 ltdb->cache = talloc_zero(ltdb, struct ltdb_cache); 335 if (ltdb->cache == NULL) goto failed; 336 ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message); 337 ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message); 338 ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message); 339 if (ltdb->cache->indexlist == NULL || 340 ltdb->cache->subclasses == NULL || 341 ltdb->cache->attributes == NULL) { 342 goto failed; 343 } 344 } 345 346 baseinfo = talloc(ltdb->cache, struct ldb_message); 347 if (baseinfo == NULL) goto failed; 348 349 baseinfo_dn = ldb_dn_explode(module->ldb, LTDB_BASEINFO); 350 if (baseinfo_dn == NULL) goto failed; 351 352 if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) == -1) { 353 goto failed; 354 } 355 356 /* possibly initialise the baseinfo */ 357 if (!baseinfo->dn) { 358 if (ltdb_baseinfo_init(module) != 0) { 359 goto failed; 360 } 361 if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) != 1) { 362 goto failed; 363 } 364 } 365 366 ltdb->tdb_seqnum = tdb_get_seqnum(ltdb->tdb); 367 368 /* if the current internal sequence number is the same as the one 369 in the database then assume the rest of the cache is OK */ 370 seq = ldb_msg_find_attr_as_uint64(baseinfo, LTDB_SEQUENCE_NUMBER, 0); 371 if (seq == ltdb->sequence_number) { 372 goto done; 373 } 374 ltdb->sequence_number = seq; 375 376 talloc_free(ltdb->cache->last_attribute.name); 377 memset(<db->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute)); 378 379 ltdb_attributes_unload(module); 380 ltdb_subclasses_unload(module); 381 382 talloc_free(ltdb->cache->indexlist); 383 talloc_free(ltdb->cache->subclasses); 384 385 ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message); 386 ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message); 387 ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message); 388 if (ltdb->cache->indexlist == NULL || 389 ltdb->cache->subclasses == NULL || 390 ltdb->cache->attributes == NULL) { 391 goto failed; 392 } 393 394 indexlist_dn = ldb_dn_explode(module->ldb, LTDB_INDEXLIST); 395 if (indexlist_dn == NULL) goto failed; 396 397 if (ltdb_search_dn1(module, indexlist_dn, ltdb->cache->indexlist) == -1) { 398 goto failed; 399 } 400 401 if (ltdb_attributes_load(module) == -1) { 402 goto failed; 403 } 404 if (ltdb_subclasses_load(module) == -1) { 405 goto failed; 406 } 407 408done: 409 talloc_free(baseinfo); 410 talloc_free(baseinfo_dn); 411 talloc_free(indexlist_dn); 412 return 0; 413 414failed: 415 talloc_free(baseinfo); 416 talloc_free(baseinfo_dn); 417 talloc_free(indexlist_dn); 418 return -1; 419} 420 421 422/* 423 increase the sequence number to indicate a database change 424*/ 425int ltdb_increase_sequence_number(struct ldb_module *module) 426{ 427 struct ltdb_private *ltdb = 428 (struct ltdb_private *)module->private_data; 429 struct ldb_message *msg; 430 struct ldb_message_element el[2]; 431 struct ldb_val val; 432 struct ldb_val val_time; 433 time_t t = time(NULL); 434 char *s = NULL; 435 int ret; 436 437 msg = talloc(ltdb, struct ldb_message); 438 if (msg == NULL) { 439 errno = ENOMEM; 440 return -1; 441 } 442 443 s = talloc_asprintf(msg, "%llu", ltdb->sequence_number+1); 444 if (!s) { 445 errno = ENOMEM; 446 return -1; 447 } 448 449 msg->num_elements = ARRAY_SIZE(el); 450 msg->elements = el; 451 msg->dn = ldb_dn_explode(msg, LTDB_BASEINFO); 452 if (msg->dn == NULL) { 453 talloc_free(msg); 454 errno = ENOMEM; 455 return -1; 456 } 457 el[0].name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER); 458 if (el[0].name == NULL) { 459 talloc_free(msg); 460 errno = ENOMEM; 461 return -1; 462 } 463 el[0].values = &val; 464 el[0].num_values = 1; 465 el[0].flags = LDB_FLAG_MOD_REPLACE; 466 val.data = (uint8_t *)s; 467 val.length = strlen(s); 468 469 el[1].name = talloc_strdup(msg, LTDB_MOD_TIMESTAMP); 470 if (el[1].name == NULL) { 471 talloc_free(msg); 472 errno = ENOMEM; 473 return -1; 474 } 475 el[1].values = &val_time; 476 el[1].num_values = 1; 477 el[1].flags = LDB_FLAG_MOD_REPLACE; 478 479 s = ldb_timestring(msg, t); 480 if (s == NULL) { 481 return -1; 482 } 483 484 val_time.data = (uint8_t *)s; 485 val_time.length = strlen(s); 486 487 ret = ltdb_modify_internal(module, msg); 488 489 talloc_free(msg); 490 491 if (ret == 0) { 492 ltdb->sequence_number += 1; 493 } 494 495 return ret; 496} 497 498 499/* 500 return the attribute flags from the @ATTRIBUTES record 501 for the given attribute 502*/ 503int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name) 504{ 505 struct ltdb_private *ltdb = 506 (struct ltdb_private *)module->private_data; 507 const struct ldb_message_element *attr_el; 508 int i, j, ret=0; 509 510 if (ltdb->cache->last_attribute.name && 511 ldb_attr_cmp(ltdb->cache->last_attribute.name, attr_name) == 0) { 512 return ltdb->cache->last_attribute.flags; 513 } 514 515 /* objectclass is a special default case */ 516 if (ldb_attr_cmp(attr_name, LTDB_OBJECTCLASS) == 0) { 517 ret = LTDB_FLAG_OBJECTCLASS | LTDB_FLAG_CASE_INSENSITIVE; 518 } 519 520 attr_el = ldb_msg_find_element(ltdb->cache->attributes, attr_name); 521 522 if (!attr_el) { 523 /* check if theres a wildcard attribute */ 524 attr_el = ldb_msg_find_element(ltdb->cache->attributes, "*"); 525 526 if (!attr_el) { 527 return ret; 528 } 529 } 530 531 for (i = 0; i < attr_el->num_values; i++) { 532 for (j=0; ltdb_valid_attr_flags[j].name; j++) { 533 if (strcmp(ltdb_valid_attr_flags[j].name, 534 (char *)attr_el->values[i].data) == 0) { 535 ret |= ltdb_valid_attr_flags[j].value; 536 } 537 } 538 } 539 540 talloc_free(ltdb->cache->last_attribute.name); 541 542 ltdb->cache->last_attribute.name = talloc_strdup(ltdb->cache, attr_name); 543 ltdb->cache->last_attribute.flags = ret; 544 545 return ret; 546} 547 548int ltdb_check_at_attributes_values(const struct ldb_val *value) 549{ 550 int i; 551 552 for (i = 0; ltdb_valid_attr_flags[i].name != NULL; i++) { 553 if ((strcmp(ltdb_valid_attr_flags[i].name, (char *)value->data) == 0)) { 554 return 0; 555 } 556 } 557 558 return -1; 559} 560 561