root/source3/lib/ldb/modules/operational.c

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

DEFINITIONS

This source file includes following definitions.
  1. construct_canonical_name
  2. operational_search_post_process
  3. operational_callback
  4. operational_search
  5. operational_init
  6. ldb_operational_init

   1 /* 
   2    ldb database library
   3 
   4    Copyright (C) Andrew Tridgell 2005
   5    Copyright (C) Simo Sorce 2006
   6 
   7      ** NOTE! The following LGPL license applies to the ldb
   8      ** library. This does NOT imply that all of Samba is released
   9      ** under the LGPL
  10    
  11    This library is free software; you can redistribute it and/or
  12    modify it under the terms of the GNU Lesser General Public
  13    License as published by the Free Software Foundation; either
  14    version 3 of the License, or (at your option) any later version.
  15 
  16    This library is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19    Lesser General Public License for more details.
  20 
  21    You should have received a copy of the GNU Lesser General Public
  22    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  23 */
  24 /*
  25   handle operational attributes
  26  */
  27 
  28 /*
  29   createTimestamp: HIDDEN, searchable, ldaptime, alias for whenCreated
  30   modifyTimestamp: HIDDEN, searchable, ldaptime, alias for whenChanged
  31 
  32      for the above two, we do the search as normal, and if
  33      createTimestamp or modifyTimestamp is asked for, then do
  34      additional searches for whenCreated and whenChanged and fill in
  35      the resulting values
  36 
  37      we also need to replace these with the whenCreated/whenChanged
  38      equivalent in the search expression trees
  39 
  40   whenCreated: not-HIDDEN, CONSTRUCTED, SEARCHABLE
  41   whenChanged: not-HIDDEN, CONSTRUCTED, SEARCHABLE
  42 
  43      on init we need to setup attribute handlers for these so
  44      comparisons are done correctly. The resolution is 1 second.
  45 
  46      on add we need to add both the above, for current time
  47 
  48      on modify we need to change whenChanged
  49 
  50 
  51   subschemaSubentry: HIDDEN, not-searchable, 
  52                      points at DN CN=Aggregate,CN=Schema,CN=Configuration,$BASEDN
  53 
  54      for this one we do the search as normal, then add the static
  55      value if requested. How do we work out the $BASEDN from inside a
  56      module?
  57      
  58 
  59   structuralObjectClass: HIDDEN, CONSTRUCTED, not-searchable. always same as objectclass?
  60 
  61      for this one we do the search as normal, then if requested ask
  62      for objectclass, change the attribute name, and add it
  63 
  64   allowedAttributesEffective: HIDDEN, CONSTRUCTED, not-searchable, 
  65      list of attributes that can be modified - requires schema lookup
  66 
  67 
  68   attributeTypes: in schema only
  69   objectClasses: in schema only
  70   matchingRules: in schema only
  71   matchingRuleUse: in schema only
  72   creatorsName: not supported by w2k3?
  73   modifiersName: not supported by w2k3?
  74 */
  75 
  76 #include "includes.h"
  77 #include "ldb/include/includes.h"
  78 
  79 /*
  80   construct a canonical name from a message
  81 */
  82 static int construct_canonical_name(struct ldb_module *module, struct ldb_message *msg)
     /* [<][>][^][v][top][bottom][index][help] */
  83 {
  84         char *canonicalName;
  85         canonicalName = ldb_dn_canonical_string(msg, msg->dn);
  86         if (canonicalName == NULL) {
  87                 return -1;
  88         }
  89         return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName);
  90 }
  91 
  92 /*
  93   a list of attribute names that should be substituted in the parse
  94   tree before the search is done
  95 */
  96 static const struct {
  97         const char *attr;
  98         const char *replace;
  99 } parse_tree_sub[] = {
 100         { "createTimestamp", "whenCreated" },
 101         { "modifyTimestamp", "whenChanged" }
 102 };
 103 
 104 
 105 /*
 106   a list of attribute names that are hidden, but can be searched for
 107   using another (non-hidden) name to produce the correct result
 108 */
 109 static const struct {
 110         const char *attr;
 111         const char *replace;
 112         int (*constructor)(struct ldb_module *, struct ldb_message *);
 113 } search_sub[] = {
 114         { "createTimestamp", "whenCreated", NULL },
 115         { "modifyTimestamp", "whenChanged", NULL },
 116         { "structuralObjectClass", "objectClass", NULL },
 117         { "canonicalName", "distinguishedName", construct_canonical_name }
 118 };
 119 
 120 /*
 121   post process a search result record. For any search_sub[] attributes that were
 122   asked for, we need to call the appropriate copy routine to copy the result
 123   into the message, then remove any attributes that we added to the search but were
 124   not asked for by the user
 125 */
 126 static int operational_search_post_process(struct ldb_module *module,
     /* [<][>][^][v][top][bottom][index][help] */
 127                                            struct ldb_message *msg, 
 128                                            const char * const *attrs)
 129 {
 130         int i, a=0;
 131 
 132         for (a=0;attrs && attrs[a];a++) {
 133                 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
 134                         if (ldb_attr_cmp(attrs[a], search_sub[i].attr) != 0) {
 135                                 continue;
 136                         }
 137 
 138                         /* construct the new attribute, using either a supplied 
 139                            constructor or a simple copy */
 140                         if (search_sub[i].constructor) {
 141                                 if (search_sub[i].constructor(module, msg) != 0) {
 142                                         goto failed;
 143                                 }
 144                         } else if (ldb_msg_copy_attr(msg,
 145                                                      search_sub[i].replace,
 146                                                      search_sub[i].attr) != 0) {
 147                                 goto failed;
 148                         }
 149 
 150                         /* remove the added search attribute, unless it was asked for 
 151                            by the user */
 152                         if (search_sub[i].replace == NULL ||
 153                             ldb_attr_in_list(attrs, search_sub[i].replace) ||
 154                             ldb_attr_in_list(attrs, "*")) {
 155                                 continue;
 156                         }
 157 
 158                         ldb_msg_remove_attr(msg, search_sub[i].replace);
 159                 }
 160         }
 161 
 162         return 0;
 163 
 164 failed:
 165         ldb_debug_set(module->ldb, LDB_DEBUG_WARNING, 
 166                       "operational_search_post_process failed for attribute '%s'\n", 
 167                       attrs[a]);
 168         return -1;
 169 }
 170 
 171 
 172 /*
 173   hook search operations
 174 */
 175 
 176 struct operational_context {
 177 
 178         struct ldb_module *module;
 179         void *up_context;
 180         int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
 181 
 182         const char * const *attrs;
 183 };
 184 
 185 static int operational_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
     /* [<][>][^][v][top][bottom][index][help] */
 186 {
 187         struct operational_context *ac;
 188 
 189         if (!context || !ares) {
 190                 ldb_set_errstring(ldb, "NULL Context or Result in callback");
 191                 goto error;
 192         }
 193 
 194         ac = talloc_get_type(context, struct operational_context);
 195 
 196         if (ares->type == LDB_REPLY_ENTRY) {
 197                 /* for each record returned post-process to add any derived
 198                    attributes that have been asked for */
 199                 if (operational_search_post_process(ac->module, ares->message, ac->attrs) != 0) {
 200                         goto error;
 201                 }
 202         }
 203 
 204         return ac->up_callback(ldb, ac->up_context, ares);
 205 
 206 error:
 207         talloc_free(ares);
 208         return LDB_ERR_OPERATIONS_ERROR;
 209 }
 210 
 211 static int operational_search(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 212 {
 213         struct operational_context *ac;
 214         struct ldb_request *down_req;
 215         const char **search_attrs = NULL;
 216         int i, a, ret;
 217 
 218         req->handle = NULL;
 219 
 220         ac = talloc(req, struct operational_context);
 221         if (ac == NULL) {
 222                 return LDB_ERR_OPERATIONS_ERROR;
 223         }
 224 
 225         ac->module = module;
 226         ac->up_context = req->context;
 227         ac->up_callback = req->callback;
 228         ac->attrs = req->op.search.attrs;
 229 
 230         down_req = talloc_zero(req, struct ldb_request);
 231         if (down_req == NULL) {
 232                 return LDB_ERR_OPERATIONS_ERROR;
 233         }
 234 
 235         down_req->operation = req->operation;
 236         down_req->op.search.base = req->op.search.base;
 237         down_req->op.search.scope = req->op.search.scope;
 238         down_req->op.search.tree = req->op.search.tree;
 239 
 240         /*  FIXME: I hink we should copy the tree and keep the original
 241          *  unmodified. SSS */
 242         /* replace any attributes in the parse tree that are
 243            searchable, but are stored using a different name in the
 244            backend */
 245         for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
 246                 ldb_parse_tree_attr_replace(discard_const_p(struct ldb_parse_tree, req->op.search.tree), 
 247                                             parse_tree_sub[i].attr, 
 248                                             parse_tree_sub[i].replace);
 249         }
 250 
 251         /* in the list of attributes we are looking for, rename any
 252            attributes to the alias for any hidden attributes that can
 253            be fetched directly using non-hidden names */
 254         for (a=0;ac->attrs && ac->attrs[a];a++) {
 255                 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
 256                         if (ldb_attr_cmp(ac->attrs[a], search_sub[i].attr) == 0 &&
 257                             search_sub[i].replace) {
 258                                 if (!search_attrs) {
 259                                         search_attrs = ldb_attr_list_copy(req, ac->attrs);
 260                                         if (search_attrs == NULL) {
 261                                                 return LDB_ERR_OPERATIONS_ERROR;
 262                                         }
 263                                 }
 264                                 search_attrs[a] = search_sub[i].replace;
 265                         }
 266                 }
 267         }
 268         
 269         /* use new set of attrs if any */
 270         if (search_attrs) down_req->op.search.attrs = search_attrs;
 271         else down_req->op.search.attrs = req->op.search.attrs;
 272         
 273         down_req->controls = req->controls;
 274 
 275         down_req->context = ac;
 276         down_req->callback = operational_callback;
 277         ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
 278 
 279         /* perform the search */
 280         ret = ldb_next_request(module, down_req);
 281 
 282         /* do not free down_req as the call results may be linked to it,
 283          * it will be freed when the upper level request get freed */
 284         if (ret == LDB_SUCCESS) {
 285                 req->handle = down_req->handle;
 286         }
 287 
 288         return ret;
 289 }
 290 
 291 static int operational_init(struct ldb_module *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 292 {
 293         /* setup some standard attribute handlers */
 294         ldb_set_attrib_handler_syntax(ctx->ldb, "whenCreated", LDB_SYNTAX_UTC_TIME);
 295         ldb_set_attrib_handler_syntax(ctx->ldb, "whenChanged", LDB_SYNTAX_UTC_TIME);
 296         ldb_set_attrib_handler_syntax(ctx->ldb, "subschemaSubentry", LDB_SYNTAX_DN);
 297         ldb_set_attrib_handler_syntax(ctx->ldb, "structuralObjectClass", LDB_SYNTAX_OBJECTCLASS);
 298 
 299         return ldb_next_init(ctx);
 300 }
 301 
 302 static const struct ldb_module_ops operational_ops = {
 303         .name              = "operational",
 304         .search            = operational_search,
 305         .init_context      = operational_init
 306 };
 307 
 308 int ldb_operational_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 309 {
 310         return ldb_register_module(&operational_ops);
 311 }

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