root/source4/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

   1 /* 
   2    ldb database library
   3 
   4    Copyright (C) Andrew Tridgell 2005
   5    Copyright (C) Simo Sorce 2006-2008
   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,$SCHEMADN
  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 "ldb_includes.h"
  77 #include "ldb_module.h"
  78 
  79 #ifndef ARRAY_SIZE
  80 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
  81 #endif
  82 
  83 /*
  84   construct a canonical name from a message
  85 */
  86 static int construct_canonical_name(struct ldb_module *module, struct ldb_message *msg)
     /* [<][>][^][v][top][bottom][index][help] */
  87 {
  88         char *canonicalName;
  89         canonicalName = ldb_dn_canonical_string(msg, msg->dn);
  90         if (canonicalName == NULL) {
  91                 return -1;
  92         }
  93         return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName);
  94 }
  95 
  96 /*
  97   a list of attribute names that should be substituted in the parse
  98   tree before the search is done
  99 */
 100 static const struct {
 101         const char *attr;
 102         const char *replace;
 103 } parse_tree_sub[] = {
 104         { "createTimestamp", "whenCreated" },
 105         { "modifyTimestamp", "whenChanged" }
 106 };
 107 
 108 
 109 /*
 110   a list of attribute names that are hidden, but can be searched for
 111   using another (non-hidden) name to produce the correct result
 112 */
 113 static const struct {
 114         const char *attr;
 115         const char *replace;
 116         int (*constructor)(struct ldb_module *, struct ldb_message *);
 117 } search_sub[] = {
 118         { "createTimestamp", "whenCreated", NULL },
 119         { "modifyTimestamp", "whenChanged", NULL },
 120         { "structuralObjectClass", "objectClass", NULL },
 121         { "canonicalName", "distinguishedName", construct_canonical_name }
 122 };
 123 
 124 /*
 125   post process a search result record. For any search_sub[] attributes that were
 126   asked for, we need to call the appropriate copy routine to copy the result
 127   into the message, then remove any attributes that we added to the search but were
 128   not asked for by the user
 129 */
 130 static int operational_search_post_process(struct ldb_module *module,
     /* [<][>][^][v][top][bottom][index][help] */
 131                                            struct ldb_message *msg, 
 132                                            const char * const *attrs)
 133 {
 134         struct ldb_context *ldb;
 135         int i, a=0;
 136 
 137         ldb = ldb_module_get_ctx(module);
 138 
 139         for (a=0;attrs && attrs[a];a++) {
 140                 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
 141                         if (ldb_attr_cmp(attrs[a], search_sub[i].attr) != 0) {
 142                                 continue;
 143                         }
 144 
 145                         /* construct the new attribute, using either a supplied 
 146                            constructor or a simple copy */
 147                         if (search_sub[i].constructor) {
 148                                 if (search_sub[i].constructor(module, msg) != 0) {
 149                                         goto failed;
 150                                 }
 151                         } else if (ldb_msg_copy_attr(msg,
 152                                                      search_sub[i].replace,
 153                                                      search_sub[i].attr) != 0) {
 154                                 goto failed;
 155                         }
 156 
 157                         /* remove the added search attribute, unless it was asked for 
 158                            by the user */
 159                         if (search_sub[i].replace == NULL ||
 160                             ldb_attr_in_list(attrs, search_sub[i].replace) ||
 161                             ldb_attr_in_list(attrs, "*")) {
 162                                 continue;
 163                         }
 164 
 165                         ldb_msg_remove_attr(msg, search_sub[i].replace);
 166                 }
 167         }
 168 
 169         return 0;
 170 
 171 failed:
 172         ldb_debug_set(ldb, LDB_DEBUG_WARNING, 
 173                       "operational_search_post_process failed for attribute '%s'\n", 
 174                       attrs[a]);
 175         return -1;
 176 }
 177 
 178 
 179 /*
 180   hook search operations
 181 */
 182 
 183 struct operational_context {
 184         struct ldb_module *module;
 185         struct ldb_request *req;
 186 
 187         const char * const *attrs;
 188 };
 189 
 190 static int operational_callback(struct ldb_request *req, struct ldb_reply *ares)
     /* [<][>][^][v][top][bottom][index][help] */
 191 {
 192         struct operational_context *ac;
 193         int ret;
 194 
 195         ac = talloc_get_type(req->context, struct operational_context);
 196 
 197         if (!ares) {
 198                 return ldb_module_done(ac->req, NULL, NULL,
 199                                         LDB_ERR_OPERATIONS_ERROR);
 200         }
 201         if (ares->error != LDB_SUCCESS) {
 202                 return ldb_module_done(ac->req, ares->controls,
 203                                         ares->response, ares->error);
 204         }
 205 
 206         switch (ares->type) {
 207         case LDB_REPLY_ENTRY:
 208                 /* for each record returned post-process to add any derived
 209                    attributes that have been asked for */
 210                 ret = operational_search_post_process(ac->module,
 211                                                         ares->message,
 212                                                         ac->attrs);
 213                 if (ret != 0) {
 214                         return ldb_module_done(ac->req, NULL, NULL,
 215                                                 LDB_ERR_OPERATIONS_ERROR);
 216                 }
 217                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
 218 
 219         case LDB_REPLY_REFERRAL:
 220                 /* ignore referrals */
 221                 break;
 222 
 223         case LDB_REPLY_DONE:
 224 
 225                 return ldb_module_done(ac->req, ares->controls,
 226                                         ares->response, LDB_SUCCESS);
 227         }
 228 
 229         talloc_free(ares);
 230         return LDB_SUCCESS;
 231 }
 232 
 233 static int operational_search(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 234 {
 235         struct ldb_context *ldb;
 236         struct operational_context *ac;
 237         struct ldb_request *down_req;
 238         const char **search_attrs = NULL;
 239         int i, a;
 240         int ret;
 241 
 242         ldb = ldb_module_get_ctx(module);
 243 
 244         ac = talloc(req, struct operational_context);
 245         if (ac == NULL) {
 246                 return LDB_ERR_OPERATIONS_ERROR;
 247         }
 248 
 249         ac->module = module;
 250         ac->req = req;
 251         ac->attrs = req->op.search.attrs;
 252 
 253         /*  FIXME: We must copy the tree and keep the original
 254          *  unmodified. SSS */
 255         /* replace any attributes in the parse tree that are
 256            searchable, but are stored using a different name in the
 257            backend */
 258         for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
 259                 ldb_parse_tree_attr_replace(req->op.search.tree, 
 260                                             parse_tree_sub[i].attr, 
 261                                             parse_tree_sub[i].replace);
 262         }
 263 
 264         /* in the list of attributes we are looking for, rename any
 265            attributes to the alias for any hidden attributes that can
 266            be fetched directly using non-hidden names */
 267         for (a=0;ac->attrs && ac->attrs[a];a++) {
 268                 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
 269                         if (ldb_attr_cmp(ac->attrs[a], search_sub[i].attr) == 0 &&
 270                             search_sub[i].replace) {
 271                                 if (!search_attrs) {
 272                                         search_attrs = ldb_attr_list_copy(req, ac->attrs);
 273                                         if (search_attrs == NULL) {
 274                                                 return LDB_ERR_OPERATIONS_ERROR;
 275                                         }
 276                                 }
 277                                 search_attrs[a] = search_sub[i].replace;
 278                         }
 279                 }
 280         }
 281 
 282         ret = ldb_build_search_req_ex(&down_req, ldb, ac,
 283                                         req->op.search.base,
 284                                         req->op.search.scope,
 285                                         req->op.search.tree,
 286                                         /* use new set of attrs if any */
 287                                         search_attrs == NULL?req->op.search.attrs:search_attrs,
 288                                         req->controls,
 289                                         ac, operational_callback,
 290                                         req);
 291         if (ret != LDB_SUCCESS) {
 292                 return LDB_ERR_OPERATIONS_ERROR;
 293         }
 294 
 295         /* perform the search */
 296         return ldb_next_request(module, down_req);
 297 }
 298 
 299 static int operational_init(struct ldb_module *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 300 {
 301         int ret = 0;
 302 
 303         if (ret != 0) {
 304                 return ret;
 305         }
 306 
 307         return ldb_next_init(ctx);
 308 }
 309 
 310 const struct ldb_module_ops ldb_operational_module_ops = {
 311         .name              = "operational",
 312         .search            = operational_search,
 313         .init_context      = operational_init
 314 };

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