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

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