root/source4/dsdb/samdb/ldb_modules/objectguid.c

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

DEFINITIONS

This source file includes following definitions.
  1. objectguid_find_attribute
  2. add_time_element
  3. add_uint64_element
  4. og_op_callback
  5. objectguid_add
  6. objectguid_modify

   1 /* 
   2    ldb database library
   3 
   4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
   5    Copyright (C) Andrew Tridgell 2005
   6    Copyright (C) Simo Sorce  2004-2008
   7 
   8      ** NOTE! The following LGPL license applies to the ldb
   9      ** library. This does NOT imply that all of Samba is released
  10      ** under the LGPL
  11    
  12    This library is free software; you can redistribute it and/or
  13    modify it under the terms of the GNU Lesser General Public
  14    License as published by the Free Software Foundation; either
  15    version 3 of the License, or (at your option) any later version.
  16 
  17    This library is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  20    Lesser General Public License for more details.
  21 
  22    You should have received a copy of the GNU Lesser General Public
  23    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  24 */
  25 
  26 /*
  27  *  Name: ldb
  28  *
  29  *  Component: ldb objectguid module
  30  *
  31  *  Description: add a unique objectGUID onto every new record
  32  *
  33  *  Author: Simo Sorce
  34  */
  35 
  36 #include "includes.h"
  37 #include "ldb_module.h"
  38 #include "librpc/gen_ndr/ndr_misc.h"
  39 #include "param/param.h"
  40 
  41 static struct ldb_message_element *objectguid_find_attribute(const struct ldb_message *msg, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
  42 {
  43         int i;
  44 
  45         for (i = 0; i < msg->num_elements; i++) {
  46                 if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
  47                         return &msg->elements[i];
  48                 }
  49         }
  50 
  51         return NULL;
  52 }
  53 
  54 /*
  55   add a time element to a record
  56 */
  57 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
     /* [<][>][^][v][top][bottom][index][help] */
  58 {
  59         struct ldb_message_element *el;
  60         char *s;
  61 
  62         if (ldb_msg_find_element(msg, attr) != NULL) {
  63                 return 0;
  64         }
  65 
  66         s = ldb_timestring(msg, t);
  67         if (s == NULL) {
  68                 return -1;
  69         }
  70 
  71         if (ldb_msg_add_string(msg, attr, s) != 0) {
  72                 return -1;
  73         }
  74 
  75         el = ldb_msg_find_element(msg, attr);
  76         /* always set as replace. This works because on add ops, the flag
  77            is ignored */
  78         el->flags = LDB_FLAG_MOD_REPLACE;
  79 
  80         return 0;
  81 }
  82 
  83 /*
  84   add a uint64_t element to a record
  85 */
  86 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
     /* [<][>][^][v][top][bottom][index][help] */
  87 {
  88         struct ldb_message_element *el;
  89 
  90         if (ldb_msg_find_element(msg, attr) != NULL) {
  91                 return 0;
  92         }
  93 
  94         if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != 0) {
  95                 return -1;
  96         }
  97 
  98         el = ldb_msg_find_element(msg, attr);
  99         /* always set as replace. This works because on add ops, the flag
 100            is ignored */
 101         el->flags = LDB_FLAG_MOD_REPLACE;
 102 
 103         return 0;
 104 }
 105 
 106 struct og_context {
 107         struct ldb_module *module;
 108         struct ldb_request *req;
 109 };
 110 
 111 static int og_op_callback(struct ldb_request *req, struct ldb_reply *ares)
     /* [<][>][^][v][top][bottom][index][help] */
 112 {
 113         struct og_context *ac;
 114 
 115         ac = talloc_get_type(req->context, struct og_context);
 116 
 117         if (!ares) {
 118                 return ldb_module_done(ac->req, NULL, NULL,
 119                                         LDB_ERR_OPERATIONS_ERROR);
 120         }
 121         if (ares->error != LDB_SUCCESS) {
 122                 return ldb_module_done(ac->req, ares->controls,
 123                                         ares->response, ares->error);
 124         }
 125 
 126         if (ares->type != LDB_REPLY_DONE) {
 127                 talloc_free(ares);
 128                 return ldb_module_done(ac->req, NULL, NULL,
 129                                         LDB_ERR_OPERATIONS_ERROR);
 130         }
 131 
 132         return ldb_module_done(ac->req, ares->controls,
 133                                 ares->response, ares->error);
 134 }
 135 
 136 /* add_record: add objectGUID attribute */
 137 static int objectguid_add(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 138 {
 139         struct ldb_context *ldb;
 140         struct ldb_request *down_req;
 141         struct ldb_message_element *attribute;
 142         struct ldb_message *msg;
 143         struct ldb_val v;
 144         struct GUID guid;
 145         uint64_t seq_num;
 146         enum ndr_err_code ndr_err;
 147         int ret;
 148         time_t t = time(NULL);
 149         struct og_context *ac;
 150 
 151         ldb = ldb_module_get_ctx(module);
 152 
 153         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
 154 
 155         /* do not manipulate our control entries */
 156         if (ldb_dn_is_special(req->op.add.message->dn)) {
 157                 return ldb_next_request(module, req);
 158         }
 159 
 160         if ((attribute = objectguid_find_attribute(req->op.add.message, "objectGUID")) != NULL ) {
 161                 return ldb_next_request(module, req);
 162         }
 163 
 164         ac = talloc(req, struct og_context);
 165         if (ac == NULL) {
 166                 return LDB_ERR_OPERATIONS_ERROR;
 167         }
 168         ac->module = module;
 169         ac->req = req;
 170 
 171         /* we have to copy the message as the caller might have it as a const */
 172         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
 173         if (msg == NULL) {
 174                 talloc_free(down_req);
 175                 return LDB_ERR_OPERATIONS_ERROR;
 176         }
 177 
 178         /* a new GUID */
 179         guid = GUID_random();
 180 
 181         ndr_err = ndr_push_struct_blob(&v, msg, 
 182                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
 183                                        &guid,
 184                                        (ndr_push_flags_fn_t)ndr_push_GUID);
 185         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 186                 return LDB_ERR_OPERATIONS_ERROR;
 187         }
 188 
 189         ret = ldb_msg_add_value(msg, "objectGUID", &v, NULL);
 190         if (ret) {
 191                 return ret;
 192         }
 193         
 194         if (add_time_element(msg, "whenCreated", t) != 0 ||
 195             add_time_element(msg, "whenChanged", t) != 0) {
 196                 return LDB_ERR_OPERATIONS_ERROR;
 197         }
 198 
 199         /* Get a sequence number from the backend */
 200         /* FIXME: ldb_sequence_number is a semi-async call,
 201          * make sure this function is split and a callback is used */
 202         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
 203         if (ret == LDB_SUCCESS) {
 204                 if (add_uint64_element(msg, "uSNCreated", seq_num) != 0 ||
 205                     add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
 206                         return LDB_ERR_OPERATIONS_ERROR;
 207                 }
 208         }
 209 
 210         ret = ldb_build_add_req(&down_req, ldb, ac,
 211                                 msg,
 212                                 req->controls,
 213                                 ac, og_op_callback,
 214                                 req);
 215         if (ret != LDB_SUCCESS) {
 216                 return LDB_ERR_OPERATIONS_ERROR;
 217         }
 218 
 219         /* go on with the call chain */
 220         return ldb_next_request(module, down_req);
 221 }
 222 
 223 /* modify_record: update timestamps */
 224 static int objectguid_modify(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 225 {
 226         struct ldb_context *ldb;
 227         struct ldb_request *down_req;
 228         struct ldb_message *msg;
 229         int ret;
 230         time_t t = time(NULL);
 231         uint64_t seq_num;
 232         struct og_context *ac;
 233 
 234         ldb = ldb_module_get_ctx(module);
 235 
 236         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
 237 
 238         /* do not manipulate our control entries */
 239         if (ldb_dn_is_special(req->op.add.message->dn)) {
 240                 return ldb_next_request(module, req);
 241         }
 242 
 243         ac = talloc(req, struct og_context);
 244         if (ac == NULL) {
 245                 return LDB_ERR_OPERATIONS_ERROR;
 246         }
 247         ac->module = module;
 248         ac->req = req;
 249 
 250         /* we have to copy the message as the caller might have it as a const */
 251         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
 252         if (msg == NULL) {
 253                 return LDB_ERR_OPERATIONS_ERROR;
 254         }
 255 
 256         if (add_time_element(msg, "whenChanged", t) != 0) {
 257                 return LDB_ERR_OPERATIONS_ERROR;
 258         }
 259 
 260         /* Get a sequence number from the backend */
 261         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
 262         if (ret == LDB_SUCCESS) {
 263                 if (add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
 264                         return LDB_ERR_OPERATIONS_ERROR;
 265                 }
 266         }
 267 
 268         ret = ldb_build_mod_req(&down_req, ldb, ac,
 269                                 msg,
 270                                 req->controls,
 271                                 ac, og_op_callback,
 272                                 req);
 273         if (ret != LDB_SUCCESS) {
 274                 return LDB_ERR_OPERATIONS_ERROR;
 275         }
 276 
 277         /* go on with the call chain */
 278         return ldb_next_request(module, down_req);
 279 }
 280 
 281 _PUBLIC_ const struct ldb_module_ops ldb_objectguid_module_ops = {
 282         .name          = "objectguid",
 283         .add           = objectguid_add,
 284         .modify        = objectguid_modify,
 285 };

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