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 "ldb_tdb.h" 35#include "ldb_private.h" 36 37#define LTDB_FLAG_CASE_INSENSITIVE (1<<0) 38#define LTDB_FLAG_INTEGER (1<<1) 39#define LTDB_FLAG_HIDDEN (1<<2) 40 41/* valid attribute flags */ 42static const struct { 43 const char *name; 44 int value; 45} ltdb_valid_attr_flags[] = { 46 { "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE }, 47 { "INTEGER", LTDB_FLAG_INTEGER }, 48 { "HIDDEN", LTDB_FLAG_HIDDEN }, 49 { "NONE", 0 }, 50 { NULL, 0 } 51}; 52 53 54/* 55 de-register any special handlers for @ATTRIBUTES 56*/ 57static void ltdb_attributes_unload(struct ldb_module *module) 58{ 59 struct ldb_context *ldb; 60 void *data = ldb_module_get_private(module); 61 struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); 62 struct ldb_message *msg; 63 int i; 64 65 ldb = ldb_module_get_ctx(module); 66 67 if (ltdb->cache->attributes == NULL) { 68 /* no previously loaded attributes */ 69 return; 70 } 71 72 msg = ltdb->cache->attributes; 73 for (i=0;i<msg->num_elements;i++) { 74 ldb_schema_attribute_remove(ldb, msg->elements[i].name); 75 } 76 77 talloc_free(ltdb->cache->attributes); 78 ltdb->cache->attributes = NULL; 79} 80 81/* 82 add up the attrib flags for a @ATTRIBUTES element 83*/ 84static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v) 85{ 86 int i; 87 unsigned value = 0; 88 for (i=0;i<el->num_values;i++) { 89 int j; 90 for (j=0;ltdb_valid_attr_flags[j].name;j++) { 91 if (strcmp(ltdb_valid_attr_flags[j].name, 92 (char *)el->values[i].data) == 0) { 93 value |= ltdb_valid_attr_flags[j].value; 94 break; 95 } 96 } 97 if (ltdb_valid_attr_flags[j].name == NULL) { 98 return -1; 99 } 100 } 101 *v = value; 102 return 0; 103} 104 105/* 106 register any special handlers from @ATTRIBUTES 107*/ 108static int ltdb_attributes_load(struct ldb_module *module) 109{ 110 struct ldb_context *ldb; 111 void *data = ldb_module_get_private(module); 112 struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); 113 struct ldb_message *msg = ltdb->cache->attributes; 114 struct ldb_dn *dn; 115 int i, r; 116 117 ldb = ldb_module_get_ctx(module); 118 119 if (ldb->schema.attribute_handler_override) { 120 /* we skip loading the @ATTRIBUTES record when a module is supplying 121 its own attribute handling */ 122 return LDB_SUCCESS; 123 } 124 125 dn = ldb_dn_new(module, ldb, LTDB_ATTRIBUTES); 126 if (dn == NULL) goto failed; 127 128 r = ltdb_search_dn1(module, dn, msg); 129 talloc_free(dn); 130 if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { 131 goto failed; 132 } 133 if (r == LDB_ERR_NO_SUCH_OBJECT) { 134 return 0; 135 } 136 /* mapping these flags onto ldap 'syntaxes' isn't strictly correct, 137 but its close enough for now */ 138 for (i=0;i<msg->num_elements;i++) { 139 unsigned flags; 140 const char *syntax; 141 const struct ldb_schema_syntax *s; 142 143 if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) { 144 ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'", msg->elements[i].name); 145 goto failed; 146 } 147 switch (flags & ~LTDB_FLAG_HIDDEN) { 148 case 0: 149 syntax = LDB_SYNTAX_OCTET_STRING; 150 break; 151 case LTDB_FLAG_CASE_INSENSITIVE: 152 syntax = LDB_SYNTAX_DIRECTORY_STRING; 153 break; 154 case LTDB_FLAG_INTEGER: 155 syntax = LDB_SYNTAX_INTEGER; 156 break; 157 default: 158 ldb_debug(ldb, LDB_DEBUG_ERROR, 159 "Invalid flag combination 0x%x for '%s' in @ATTRIBUTES", 160 flags, msg->elements[i].name); 161 goto failed; 162 } 163 164 s = ldb_standard_syntax_by_name(ldb, syntax); 165 if (s == NULL) { 166 ldb_debug(ldb, LDB_DEBUG_ERROR, 167 "Invalid attribute syntax '%s' for '%s' in @ATTRIBUTES", 168 syntax, msg->elements[i].name); 169 goto failed; 170 } 171 172 flags |= LDB_ATTR_FLAG_ALLOCATED; 173 if (ldb_schema_attribute_add_with_syntax(ldb, msg->elements[i].name, flags, s) != 0) { 174 goto failed; 175 } 176 } 177 178 return 0; 179failed: 180 return -1; 181} 182 183 184/* 185 initialise the baseinfo record 186*/ 187static int ltdb_baseinfo_init(struct ldb_module *module) 188{ 189 struct ldb_context *ldb; 190 void *data = ldb_module_get_private(module); 191 struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); 192 struct ldb_message *msg; 193 struct ldb_message_element el; 194 struct ldb_val val; 195 int ret; 196 /* the initial sequence number must be different from the one 197 set in ltdb_cache_free(). Thanks to Jon for pointing this 198 out. */ 199 const char *initial_sequence_number = "1"; 200 201 ldb = ldb_module_get_ctx(module); 202 203 ltdb->sequence_number = atof(initial_sequence_number); 204 205 msg = talloc(ltdb, struct ldb_message); 206 if (msg == NULL) { 207 goto failed; 208 } 209 210 msg->num_elements = 1; 211 msg->elements = ⪙ 212 msg->dn = ldb_dn_new(msg, ldb, LTDB_BASEINFO); 213 if (!msg->dn) { 214 goto failed; 215 } 216 el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER); 217 if (!el.name) { 218 goto failed; 219 } 220 el.values = &val; 221 el.num_values = 1; 222 el.flags = 0; 223 val.data = (uint8_t *)talloc_strdup(msg, initial_sequence_number); 224 if (!val.data) { 225 goto failed; 226 } 227 val.length = 1; 228 229 ret = ltdb_store(module, msg, TDB_INSERT); 230 231 talloc_free(msg); 232 233 return ret; 234 235failed: 236 talloc_free(msg); 237 errno = ENOMEM; 238 return LDB_ERR_OPERATIONS_ERROR; 239} 240 241/* 242 free any cache records 243 */ 244static void ltdb_cache_free(struct ldb_module *module) 245{ 246 void *data = ldb_module_get_private(module); 247 struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); 248 249 ltdb->sequence_number = 0; 250 talloc_free(ltdb->cache); 251 ltdb->cache = NULL; 252} 253 254/* 255 force a cache reload 256*/ 257int ltdb_cache_reload(struct ldb_module *module) 258{ 259 ltdb_attributes_unload(module); 260 ltdb_cache_free(module); 261 return ltdb_cache_load(module); 262} 263 264/* 265 load the cache records 266*/ 267int ltdb_cache_load(struct ldb_module *module) 268{ 269 struct ldb_context *ldb; 270 void *data = ldb_module_get_private(module); 271 struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); 272 struct ldb_dn *baseinfo_dn = NULL, *options_dn = NULL; 273 struct ldb_dn *indexlist_dn = NULL; 274 uint64_t seq; 275 struct ldb_message *baseinfo = NULL, *options = NULL; 276 int r; 277 278 ldb = ldb_module_get_ctx(module); 279 280 /* a very fast check to avoid extra database reads */ 281 if (ltdb->cache != NULL && 282 tdb_get_seqnum(ltdb->tdb) == ltdb->tdb_seqnum) { 283 return 0; 284 } 285 286 if (ltdb->cache == NULL) { 287 ltdb->cache = talloc_zero(ltdb, struct ltdb_cache); 288 if (ltdb->cache == NULL) goto failed; 289 ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message); 290 ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message); 291 if (ltdb->cache->indexlist == NULL || 292 ltdb->cache->attributes == NULL) { 293 goto failed; 294 } 295 } 296 297 baseinfo = talloc(ltdb->cache, struct ldb_message); 298 if (baseinfo == NULL) goto failed; 299 300 baseinfo_dn = ldb_dn_new(module, ldb, LTDB_BASEINFO); 301 if (baseinfo_dn == NULL) goto failed; 302 303 r= ltdb_search_dn1(module, baseinfo_dn, baseinfo); 304 if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { 305 goto failed; 306 } 307 308 /* possibly initialise the baseinfo */ 309 if (r == LDB_ERR_NO_SUCH_OBJECT) { 310 if (ltdb_baseinfo_init(module) != LDB_SUCCESS) { 311 goto failed; 312 } 313 if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) != LDB_SUCCESS) { 314 goto failed; 315 } 316 } 317 318 ltdb->tdb_seqnum = tdb_get_seqnum(ltdb->tdb); 319 320 /* if the current internal sequence number is the same as the one 321 in the database then assume the rest of the cache is OK */ 322 seq = ldb_msg_find_attr_as_uint64(baseinfo, LTDB_SEQUENCE_NUMBER, 0); 323 if (seq == ltdb->sequence_number) { 324 goto done; 325 } 326 ltdb->sequence_number = seq; 327 328 /* Read an interpret database options */ 329 options = talloc(ltdb->cache, struct ldb_message); 330 if (options == NULL) goto failed; 331 332 options_dn = ldb_dn_new(options, ldb, LTDB_OPTIONS); 333 if (options_dn == NULL) goto failed; 334 335 r= ltdb_search_dn1(module, options_dn, options); 336 if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { 337 goto failed; 338 } 339 340 /* set flag for checking base DN on searches */ 341 if (r == LDB_SUCCESS) { 342 ltdb->check_base = ldb_msg_find_attr_as_bool(options, LTDB_CHECK_BASE, false); 343 } else { 344 ltdb->check_base = false; 345 } 346 347 talloc_free(ltdb->cache->last_attribute.name); 348 memset(<db->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute)); 349 350 ltdb_attributes_unload(module); 351 352 talloc_free(ltdb->cache->indexlist); 353 354 ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message); 355 ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message); 356 if (ltdb->cache->indexlist == NULL || 357 ltdb->cache->attributes == NULL) { 358 goto failed; 359 } 360 361 indexlist_dn = ldb_dn_new(module, ldb, LTDB_INDEXLIST); 362 if (indexlist_dn == NULL) goto failed; 363 364 r = ltdb_search_dn1(module, indexlist_dn, ltdb->cache->indexlist); 365 if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { 366 goto failed; 367 } 368 369 if (ltdb_attributes_load(module) == -1) { 370 goto failed; 371 } 372 373done: 374 talloc_free(options); 375 talloc_free(baseinfo); 376 talloc_free(baseinfo_dn); 377 talloc_free(indexlist_dn); 378 return 0; 379 380failed: 381 talloc_free(options); 382 talloc_free(baseinfo); 383 talloc_free(baseinfo_dn); 384 talloc_free(indexlist_dn); 385 return -1; 386} 387 388 389/* 390 increase the sequence number to indicate a database change 391*/ 392int ltdb_increase_sequence_number(struct ldb_module *module) 393{ 394 struct ldb_context *ldb; 395 void *data = ldb_module_get_private(module); 396 struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); 397 struct ldb_message *msg; 398 struct ldb_message_element el[2]; 399 struct ldb_val val; 400 struct ldb_val val_time; 401 time_t t = time(NULL); 402 char *s = NULL; 403 int ret; 404 405 ldb = ldb_module_get_ctx(module); 406 407 msg = talloc(ltdb, struct ldb_message); 408 if (msg == NULL) { 409 errno = ENOMEM; 410 return LDB_ERR_OPERATIONS_ERROR; 411 } 412 413 s = talloc_asprintf(msg, "%llu", ltdb->sequence_number+1); 414 if (!s) { 415 errno = ENOMEM; 416 return LDB_ERR_OPERATIONS_ERROR; 417 } 418 419 msg->num_elements = ARRAY_SIZE(el); 420 msg->elements = el; 421 msg->dn = ldb_dn_new(msg, ldb, LTDB_BASEINFO); 422 if (msg->dn == NULL) { 423 talloc_free(msg); 424 errno = ENOMEM; 425 return LDB_ERR_OPERATIONS_ERROR; 426 } 427 el[0].name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER); 428 if (el[0].name == NULL) { 429 talloc_free(msg); 430 errno = ENOMEM; 431 return LDB_ERR_OPERATIONS_ERROR; 432 } 433 el[0].values = &val; 434 el[0].num_values = 1; 435 el[0].flags = LDB_FLAG_MOD_REPLACE; 436 val.data = (uint8_t *)s; 437 val.length = strlen(s); 438 439 el[1].name = talloc_strdup(msg, LTDB_MOD_TIMESTAMP); 440 if (el[1].name == NULL) { 441 talloc_free(msg); 442 errno = ENOMEM; 443 return LDB_ERR_OPERATIONS_ERROR; 444 } 445 el[1].values = &val_time; 446 el[1].num_values = 1; 447 el[1].flags = LDB_FLAG_MOD_REPLACE; 448 449 s = ldb_timestring(msg, t); 450 if (s == NULL) { 451 return LDB_ERR_OPERATIONS_ERROR; 452 } 453 454 val_time.data = (uint8_t *)s; 455 val_time.length = strlen(s); 456 457 ret = ltdb_modify_internal(module, msg); 458 459 talloc_free(msg); 460 461 if (ret == LDB_SUCCESS) { 462 ltdb->sequence_number += 1; 463 } 464 465 /* updating the tdb_seqnum here avoids us reloading the cache 466 records due to our own modification */ 467 ltdb->tdb_seqnum = tdb_get_seqnum(ltdb->tdb); 468 469 return ret; 470} 471 472int ltdb_check_at_attributes_values(const struct ldb_val *value) 473{ 474 int i; 475 476 for (i = 0; ltdb_valid_attr_flags[i].name != NULL; i++) { 477 if ((strcmp(ltdb_valid_attr_flags[i].name, (char *)value->data) == 0)) { 478 return 0; 479 } 480 } 481 482 return -1; 483} 484 485