root/source3/lib/ldb/ldb_tdb/ldb_cache.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ltdb_attributes_unload
  2. ltdb_attributes_flags
  3. ltdb_attributes_load
  4. ltdb_subclasses_load
  5. ltdb_subclasses_unload
  6. ltdb_baseinfo_init
  7. ltdb_cache_free
  8. ltdb_cache_reload
  9. ltdb_cache_load
  10. ltdb_increase_sequence_number
  11. ltdb_attribute_flags
  12. ltdb_check_at_attributes_values

   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 
  44 int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name);
  45 
  46 /* valid attribute flags */
  47 static 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 */
  62 static void ltdb_attributes_unload(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
  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 */
  86 static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v)
     /* [<][>][^][v][top][bottom][index][help] */
  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 */
 110 static int ltdb_attributes_load(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 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;
 171 failed:
 172         return -1;
 173 }
 174 
 175 
 176 /*
 177   register any subclasses from @SUBCLASSES
 178 */
 179 static int ltdb_subclasses_load(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 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;
 207 failed:
 208         return -1;
 209 }
 210 
 211 
 212 /*
 213   de-register any @SUBCLASSES
 214 */
 215 static void ltdb_subclasses_unload(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 240 static int ltdb_baseinfo_init(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 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 = &el;
 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 
 285 failed:
 286         talloc_free(msg);
 287         errno = ENOMEM;
 288         return -1;
 289 }
 290 
 291 /*
 292   free any cache records
 293  */
 294 static void ltdb_cache_free(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 307 int ltdb_cache_reload(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 318 int ltdb_cache_load(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 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(&ltdb->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 
 408 done:
 409         talloc_free(baseinfo);
 410         talloc_free(baseinfo_dn);
 411         talloc_free(indexlist_dn);
 412         return 0;
 413 
 414 failed:
 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 */
 425 int ltdb_increase_sequence_number(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 503 int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 548 int ltdb_check_at_attributes_values(const struct ldb_val *value)
     /* [<][>][^][v][top][bottom][index][help] */
 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 

/* [<][>][^][v][top][bottom][index][help] */