root/source4/dsdb/schema/schema_set.c

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

DEFINITIONS

This source file includes following definitions.
  1. dsdb_schema_set_attributes
  2. dsdb_set_schema
  3. dsdb_set_global_schema
  4. dsdb_get_schema
  5. dsdb_make_schema_global
  6. dsdb_attach_schema_from_ldif_file

   1 /* 
   2    Unix SMB/CIFS mplementation.
   3    DSDB schema header
   4    
   5    Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
   6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
   7 
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12    
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17    
  18    You should have received a copy of the GNU General Public License
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20    
  21 */
  22 
  23 #include "includes.h"
  24 #include "dlinklist.h"
  25 #include "dsdb/samdb/samdb.h"
  26 #include "lib/ldb/include/ldb_module.h"
  27 #include "param/param.h"
  28 
  29 
  30 static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_attributes)
     /* [<][>][^][v][top][bottom][index][help] */
  31 {
  32         int ret = LDB_SUCCESS;
  33         struct ldb_result *res;
  34         struct ldb_result *res_idx;
  35         struct dsdb_attribute *attr;
  36         struct ldb_message *mod_msg;
  37         TALLOC_CTX *mem_ctx = talloc_new(ldb);
  38         
  39         struct ldb_message *msg;
  40         struct ldb_message *msg_idx;
  41 
  42         if (!mem_ctx) {
  43                 return LDB_ERR_OPERATIONS_ERROR;
  44         }
  45 
  46         msg = ldb_msg_new(mem_ctx);
  47         if (!msg) {
  48                 ldb_oom(ldb);
  49                 return LDB_ERR_OPERATIONS_ERROR;
  50         }
  51         msg_idx = ldb_msg_new(mem_ctx);
  52         if (!msg_idx) {
  53                 ldb_oom(ldb);
  54                 return LDB_ERR_OPERATIONS_ERROR;
  55         }
  56         msg->dn = ldb_dn_new(msg, ldb, "@ATTRIBUTES");
  57         if (!msg->dn) {
  58                 ldb_oom(ldb);
  59                 return LDB_ERR_OPERATIONS_ERROR;
  60         }
  61         msg_idx->dn = ldb_dn_new(msg, ldb, "@INDEXLIST");
  62         if (!msg_idx->dn) {
  63                 ldb_oom(ldb);
  64                 return LDB_ERR_OPERATIONS_ERROR;
  65         }
  66 
  67         for (attr = schema->attributes; attr; attr = attr->next) {
  68                 const struct ldb_schema_syntax *s;
  69                 const char *syntax = attr->syntax->ldb_syntax;
  70                 if (!syntax) {
  71                         syntax = attr->syntax->ldap_oid;
  72                 }
  73 
  74                 /* Write out a rough approximation of the schema as an @ATTRIBUTES value, for bootstrapping */
  75                 if (strcmp(syntax, LDB_SYNTAX_INTEGER) == 0) {
  76                         ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "INTEGER");
  77                 } else if (strcmp(syntax, LDB_SYNTAX_DIRECTORY_STRING) == 0) {
  78                         ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "CASE_INSENSITIVE");
  79                 } 
  80                 if (ret != LDB_SUCCESS) {
  81                         break;
  82                 }
  83 
  84                 if (attr->searchFlags & SEARCH_FLAG_ATTINDEX) {
  85                         ret = ldb_msg_add_string(msg_idx, "@IDXATTR", attr->lDAPDisplayName);
  86                         if (ret != LDB_SUCCESS) {
  87                                 break;
  88                         }
  89                 }
  90 
  91                 if (!attr->syntax) {
  92                         continue;
  93                 }
  94 
  95                 ret = ldb_schema_attribute_add(ldb, attr->lDAPDisplayName, LDB_ATTR_FLAG_FIXED,
  96                                                syntax);
  97                 if (ret != LDB_SUCCESS) {
  98                         s = ldb_samba_syntax_by_name(ldb, attr->syntax->ldap_oid);
  99                         if (s) {
 100                                 ret = ldb_schema_attribute_add_with_syntax(ldb, attr->lDAPDisplayName, LDB_ATTR_FLAG_FIXED, s);
 101                         } else {
 102                                 ret = LDB_SUCCESS; /* Nothing to do here */
 103                         }
 104                 }
 105                 
 106                 if (ret != LDB_SUCCESS) {
 107                         break;
 108                 }
 109         }
 110 
 111         if (!write_attributes || ret != LDB_SUCCESS) {
 112                 talloc_free(mem_ctx);
 113                 return ret;
 114         }
 115 
 116 
 117         /* Try to avoid churning the attributes too much - we only want to do this if they have changed */
 118         ret = ldb_search(ldb, mem_ctx, &res, msg->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg->dn));
 119         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
 120                 ret = ldb_add(ldb, msg);
 121         } else if (ret != LDB_SUCCESS) {
 122         } else if (res->count != 1) {
 123                 ret = ldb_add(ldb, msg);
 124         } else {
 125                 ret = LDB_SUCCESS;
 126                 /* Annoyingly added to our search results */
 127                 ldb_msg_remove_attr(res->msgs[0], "distinguishedName");
 128                 
 129                 mod_msg = ldb_msg_diff(ldb, res->msgs[0], msg);
 130                 if (mod_msg->num_elements > 0) {
 131                         ret = ldb_modify(ldb, mod_msg);
 132                 }
 133         }
 134 
 135         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
 136                 /* We might be on a read-only DB */
 137                 ret = LDB_SUCCESS;
 138         }
 139         if (ret != LDB_SUCCESS) {
 140                 talloc_free(mem_ctx);
 141                 return ret;
 142         }
 143 
 144         /* Now write out the indexs, as found in the schema (if they have changed) */
 145 
 146         ret = ldb_search(ldb, mem_ctx, &res_idx, msg_idx->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg_idx->dn));
 147         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
 148                 ret = ldb_add(ldb, msg_idx);
 149         } else if (ret != LDB_SUCCESS) {
 150         } else if (res->count != 1) {
 151                 ret = ldb_add(ldb, msg_idx);
 152         } else {
 153                 ret = LDB_SUCCESS;
 154                 /* Annoyingly added to our search results */
 155                 ldb_msg_remove_attr(res_idx->msgs[0], "distinguishedName");
 156 
 157                 mod_msg = ldb_msg_diff(ldb, res_idx->msgs[0], msg_idx);
 158                 if (mod_msg->num_elements > 0) {
 159                         ret = ldb_modify(ldb, mod_msg);
 160                 }
 161         }
 162         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
 163                 /* We might be on a read-only DB */
 164                 ret = LDB_SUCCESS;
 165         }
 166         talloc_free(mem_ctx);
 167         return ret;
 168 }
 169 
 170 
 171 /**
 172  * Attach the schema to an opaque pointer on the ldb, so ldb modules
 173  * can find it 
 174  */
 175 
 176 int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema)
     /* [<][>][^][v][top][bottom][index][help] */
 177 {
 178         int ret;
 179 
 180         ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
 181         if (ret != LDB_SUCCESS) {
 182                 return ret;
 183         }
 184 
 185         /* Set the new attributes based on the new schema */
 186         ret = dsdb_schema_set_attributes(ldb, schema, true);
 187         if (ret != LDB_SUCCESS) {
 188                 return ret;
 189         }
 190 
 191         talloc_steal(ldb, schema);
 192 
 193         return LDB_SUCCESS;
 194 }
 195 
 196 /**
 197  * Global variable to hold one copy of the schema, used to avoid memory bloat
 198  */
 199 static struct dsdb_schema *global_schema;
 200 
 201 /**
 202  * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process
 203  */
 204 int dsdb_set_global_schema(struct ldb_context *ldb)
     /* [<][>][^][v][top][bottom][index][help] */
 205 {
 206         int ret;
 207         if (!global_schema) {
 208                 return LDB_SUCCESS;
 209         }
 210         ret = ldb_set_opaque(ldb, "dsdb_schema", global_schema);
 211         if (ret != LDB_SUCCESS) {
 212                 return ret;
 213         }
 214 
 215         /* Set the new attributes based on the new schema */
 216         ret = dsdb_schema_set_attributes(ldb, global_schema, false);
 217         if (ret != LDB_SUCCESS) {
 218                 return ret;
 219         }
 220 
 221         /* Keep a reference to this schema, just incase the global copy is replaced */
 222         if (talloc_reference(ldb, global_schema) == NULL) {
 223                 return LDB_ERR_OPERATIONS_ERROR;
 224         }
 225 
 226         return LDB_SUCCESS;
 227 }
 228 
 229 /**
 230  * Find the schema object for this ldb
 231  */
 232 
 233 struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb)
     /* [<][>][^][v][top][bottom][index][help] */
 234 {
 235         const void *p;
 236         struct dsdb_schema *schema;
 237 
 238         /* see if we have a cached copy */
 239         p = ldb_get_opaque(ldb, "dsdb_schema");
 240         if (!p) {
 241                 return NULL;
 242         }
 243 
 244         schema = talloc_get_type(p, struct dsdb_schema);
 245         if (!schema) {
 246                 return NULL;
 247         }
 248 
 249         return schema;
 250 }
 251 
 252 /**
 253  * Make the schema found on this ldb the 'global' schema
 254  */
 255 
 256 void dsdb_make_schema_global(struct ldb_context *ldb)
     /* [<][>][^][v][top][bottom][index][help] */
 257 {
 258         struct dsdb_schema *schema = dsdb_get_schema(ldb);
 259         if (!schema) {
 260                 return;
 261         }
 262 
 263         if (global_schema) {
 264                 talloc_unlink(talloc_autofree_context(), schema);
 265         }
 266 
 267         talloc_steal(talloc_autofree_context(), schema);
 268         global_schema = schema;
 269 
 270         dsdb_set_global_schema(ldb);
 271 }
 272 
 273 
 274 /**
 275  * Rather than read a schema from the LDB itself, read it from an ldif
 276  * file.  This allows schema to be loaded and used while adding the
 277  * schema itself to the directory.
 278  */
 279 
 280 WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df)
     /* [<][>][^][v][top][bottom][index][help] */
 281 {
 282         struct ldb_ldif *ldif;
 283         struct ldb_message *msg;
 284         TALLOC_CTX *mem_ctx;
 285         WERROR status;
 286         int ret;
 287         struct dsdb_schema *schema;
 288         const struct ldb_val *prefix_val;
 289         const struct ldb_val *info_val;
 290         struct ldb_val info_val_default;
 291 
 292         mem_ctx = talloc_new(ldb);
 293         if (!mem_ctx) {
 294                 goto nomem;
 295         }
 296 
 297         schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")));
 298 
 299         schema->fsmo.we_are_master = true;
 300         schema->fsmo.master_dn = ldb_dn_new_fmt(schema, ldb, "@PROVISION_SCHEMA_MASTER");
 301         if (!schema->fsmo.master_dn) {
 302                 goto nomem;
 303         }
 304 
 305         /*
 306          * load the prefixMap attribute from pf
 307          */
 308         ldif = ldb_ldif_read_string(ldb, &pf);
 309         if (!ldif) {
 310                 status = WERR_INVALID_PARAM;
 311                 goto failed;
 312         }
 313         talloc_steal(mem_ctx, ldif);
 314 
 315         msg = ldb_msg_canonicalize(ldb, ldif->msg);
 316         if (!msg) {
 317                 goto nomem;
 318         }
 319         talloc_steal(mem_ctx, msg);
 320         talloc_free(ldif);
 321 
 322         prefix_val = ldb_msg_find_ldb_val(msg, "prefixMap");
 323         if (!prefix_val) {
 324                 status = WERR_INVALID_PARAM;
 325                 goto failed;
 326         }
 327 
 328         info_val = ldb_msg_find_ldb_val(msg, "schemaInfo");
 329         if (!info_val) {
 330                 info_val_default = strhex_to_data_blob(mem_ctx, "FF0000000000000000000000000000000000000000");
 331                 if (!info_val_default.data) {
 332                         goto nomem;
 333                 }
 334                 info_val = &info_val_default;
 335         }
 336 
 337         status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
 338         if (!W_ERROR_IS_OK(status)) {
 339                 goto failed;
 340         }
 341 
 342         /*
 343          * load the attribute and class definitions outof df
 344          */
 345         while ((ldif = ldb_ldif_read_string(ldb, &df))) {
 346                 bool is_sa;
 347                 bool is_sc;
 348 
 349                 talloc_steal(mem_ctx, ldif);
 350 
 351                 msg = ldb_msg_canonicalize(ldb, ldif->msg);
 352                 if (!msg) {
 353                         goto nomem;
 354                 }
 355 
 356                 talloc_steal(mem_ctx, msg);
 357                 talloc_free(ldif);
 358 
 359                 is_sa = ldb_msg_check_string_attribute(msg, "objectClass", "attributeSchema");
 360                 is_sc = ldb_msg_check_string_attribute(msg, "objectClass", "classSchema");
 361 
 362                 if (is_sa) {
 363                         struct dsdb_attribute *sa;
 364 
 365                         sa = talloc_zero(schema, struct dsdb_attribute);
 366                         if (!sa) {
 367                                 goto nomem;
 368                         }
 369 
 370                         status = dsdb_attribute_from_ldb(schema, msg, sa, sa);
 371                         if (!W_ERROR_IS_OK(status)) {
 372                                 goto failed;
 373                         }
 374 
 375                         DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *);
 376                 } else if (is_sc) {
 377                         struct dsdb_class *sc;
 378 
 379                         sc = talloc_zero(schema, struct dsdb_class);
 380                         if (!sc) {
 381                                 goto nomem;
 382                         }
 383 
 384                         status = dsdb_class_from_ldb(schema, msg, sc, sc);
 385                         if (!W_ERROR_IS_OK(status)) {
 386                                 goto failed;
 387                         }
 388 
 389                         DLIST_ADD_END(schema->classes, sc, struct dsdb_class *);
 390                 }
 391         }
 392 
 393         ret = dsdb_set_schema(ldb, schema);
 394         if (ret != LDB_SUCCESS) {
 395                 status = WERR_FOOBAR;
 396                 goto failed;
 397         }
 398 
 399         goto done;
 400 
 401 nomem:
 402         status = WERR_NOMEM;
 403 failed:
 404 done:
 405         talloc_free(mem_ctx);
 406         return status;
 407 }

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