LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - schema_util.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 96 133 72.2 %
Date: 2024-04-21 15:09:00 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    dsdb module schema utility functions
       5             : 
       6             :    Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
       7             :    Copyright (C) Andrew Tridgell 2010
       8             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2010
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program 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
      18             :    GNU General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "dsdb/common/util.h"
      26             : #include "dsdb/samdb/samdb.h"
      27             : #include "dsdb/samdb/ldb_modules/util.h"
      28             : #include <ldb_module.h>
      29             : #include "librpc/gen_ndr/ndr_drsuapi.h"
      30             : #include "librpc/gen_ndr/ndr_drsblobs.h"
      31             : #include "param/param.h"
      32             : 
      33             : /**
      34             :  * Reads schema_info structure from schemaInfo
      35             :  * attribute on SCHEMA partition
      36             :  *
      37             :  * @param dsdb_flags    DSDB_FLAG_... flag of 0
      38             :  */
      39        1818 : int dsdb_module_schema_info_blob_read(struct ldb_module *ldb_module,
      40             :                                       uint32_t dsdb_flags,
      41             :                                       TALLOC_CTX *mem_ctx,
      42             :                                       struct ldb_val *schema_info_blob,
      43             :                                       struct ldb_request *parent)
      44             : {
      45           3 :         int ldb_err;
      46           3 :         const struct ldb_val *blob_val;
      47           3 :         struct ldb_dn *schema_dn;
      48        1818 :         struct ldb_result *schema_res = NULL;
      49           3 :         static const char *schema_attrs[] = {
      50             :                 "schemaInfo",
      51             :                 NULL
      52             :         };
      53             : 
      54        1818 :         schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ldb_module));
      55        1818 :         if (!schema_dn) {
      56           0 :                 DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n"));
      57           0 :                 return ldb_operr(ldb_module_get_ctx(ldb_module));
      58             :         }
      59             : 
      60        1818 :         ldb_err = dsdb_module_search(ldb_module, mem_ctx, &schema_res, schema_dn,
      61             :                                      LDB_SCOPE_BASE, schema_attrs, dsdb_flags, parent,
      62             :                                      NULL);
      63        1818 :         if (ldb_err == LDB_ERR_NO_SUCH_OBJECT) {
      64           0 :                 DEBUG(0,("dsdb_module_schema_info_blob_read: Schema DN not found!\n"));
      65           0 :                 talloc_free(schema_res);
      66           0 :                 return ldb_err;
      67        1818 :         } else if (ldb_err != LDB_SUCCESS) {
      68           0 :                 DEBUG(0,("dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute\n"));
      69           0 :                 talloc_free(schema_res);
      70           0 :                 return ldb_err;
      71             :         }
      72             : 
      73        1818 :         blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
      74        1818 :         if (!blob_val) {
      75          18 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module),
      76             :                                        "dsdb_module_schema_info_blob_read: no schemaInfo attribute found");
      77          18 :                 talloc_free(schema_res);
      78          18 :                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
      79             :         }
      80             : 
      81             :         /* transfer .data ownership to mem_ctx */
      82        1800 :         schema_info_blob->length = blob_val->length;
      83        1800 :         schema_info_blob->data = talloc_steal(mem_ctx, blob_val->data);
      84             : 
      85        1800 :         talloc_free(schema_res);
      86             : 
      87        1800 :         return LDB_SUCCESS;
      88             : }
      89             : 
      90             : /**
      91             :  * Prepares ldb_msg to be used for updating schemaInfo value in DB
      92             :  */
      93        1817 : static int dsdb_schema_info_write_prepare(struct ldb_context *ldb,
      94             :                                           struct ldb_val *schema_info_blob,
      95             :                                           TALLOC_CTX *mem_ctx,
      96             :                                           struct ldb_message **_msg)
      97             : {
      98           2 :         int ldb_err;
      99           2 :         struct ldb_message *msg;
     100           2 :         struct ldb_dn *schema_dn;
     101           2 :         struct ldb_message_element *return_el;
     102             : 
     103        1817 :         schema_dn = ldb_get_schema_basedn(ldb);
     104        1817 :         if (!schema_dn) {
     105           0 :                 DEBUG(0,("dsdb_schema_info_write_prepare: no schema dn present\n"));
     106           0 :                 return ldb_operr(ldb);
     107             :         }
     108             : 
     109             :         /* prepare ldb_msg to update schemaInfo */
     110        1817 :         msg = ldb_msg_new(mem_ctx);
     111        1817 :         if (msg == NULL) {
     112           0 :                 return ldb_oom(ldb);
     113             :         }
     114             : 
     115        1817 :         msg->dn = schema_dn;
     116        1817 :         ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
     117        1817 :         if (ldb_err != 0) {
     118           0 :                 ldb_asprintf_errstring(ldb, "dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s\n",
     119             :                                        ldb_strerror(ldb_err));
     120           0 :                 talloc_free(msg);
     121           0 :                 return ldb_err;
     122             :         }
     123             : 
     124             :         /* mark schemaInfo element for replacement */
     125        1817 :         return_el->flags = LDB_FLAG_MOD_REPLACE;
     126             : 
     127        1817 :         *_msg = msg;
     128             : 
     129        1817 :         return LDB_SUCCESS;
     130             : }
     131             : 
     132             : 
     133             : 
     134             : /**
     135             :  * Writes schema_info structure into schemaInfo
     136             :  * attribute on SCHEMA partition
     137             :  *
     138             :  * @param dsdb_flags    DSDB_FLAG_... flag of 0
     139             :  */
     140        1817 : int dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module,
     141             :                                        uint32_t dsdb_flags,
     142             :                                        struct ldb_val *schema_info_blob,
     143             :                                        struct ldb_request *parent)
     144             : {
     145           2 :         int ldb_err;
     146        1817 :         struct ldb_message *msg = NULL;
     147           2 :         TALLOC_CTX *temp_ctx;
     148             : 
     149        1817 :         temp_ctx = talloc_new(ldb_module);
     150        1817 :         if (temp_ctx == NULL) {
     151           0 :                 return ldb_module_oom(ldb_module);
     152             :         }
     153             : 
     154             :         /* write serialized schemaInfo into LDB */
     155        1817 :         ldb_err = dsdb_schema_info_write_prepare(ldb_module_get_ctx(ldb_module),
     156             :                                                  schema_info_blob,
     157             :                                                  temp_ctx, &msg);
     158        1817 :         if (ldb_err != LDB_SUCCESS) {
     159           0 :                 talloc_free(temp_ctx);
     160           0 :                 return ldb_err;
     161             :         }
     162             : 
     163             : 
     164        1817 :         ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags, parent);
     165             : 
     166        1817 :         talloc_free(temp_ctx);
     167             : 
     168        1817 :         if (ldb_err != LDB_SUCCESS) {
     169           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module),
     170             :                                        "dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s)\n",
     171             :                                        ldb_strerror(ldb_err),
     172             :                                        ldb_errstring(ldb_module_get_ctx(ldb_module)));
     173           0 :                 return ldb_err;
     174             :         }
     175             : 
     176        1815 :         return LDB_SUCCESS;
     177             : }
     178             : 
     179             : 
     180             : /**
     181             :  * Reads schema_info structure from schemaInfo
     182             :  * attribute on SCHEMA partition
     183             :  */
     184        1816 : static int dsdb_module_schema_info_read(struct ldb_module *ldb_module,
     185             :                                         uint32_t dsdb_flags,
     186             :                                         TALLOC_CTX *mem_ctx,
     187             :                                         struct dsdb_schema_info **_schema_info,
     188             :                                         struct ldb_request *parent)
     189             : {
     190           1 :         int ret;
     191           1 :         DATA_BLOB ndr_blob;
     192           1 :         TALLOC_CTX *temp_ctx;
     193           1 :         WERROR werr;
     194             : 
     195        1816 :         temp_ctx = talloc_new(mem_ctx);
     196        1816 :         if (temp_ctx == NULL) {
     197           0 :                 return ldb_module_oom(ldb_module);
     198             :         }
     199             : 
     200             :         /* read serialized schemaInfo from LDB  */
     201        1816 :         ret = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob, parent);
     202        1816 :         if (ret != LDB_SUCCESS) {
     203          18 :                 talloc_free(temp_ctx);
     204          18 :                 return ret;
     205             :         }
     206             : 
     207             :         /* convert NDR blob to dsdb_schema_info object */
     208        1798 :         werr = dsdb_schema_info_from_blob(&ndr_blob,
     209             :                                           mem_ctx,
     210             :                                           _schema_info);
     211        1798 :         talloc_free(temp_ctx);
     212             : 
     213        1798 :         if (W_ERROR_EQUAL(werr, WERR_DS_NO_ATTRIBUTE_OR_VALUE)) {
     214           0 :                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
     215             :         }
     216             : 
     217        1798 :         if (!W_ERROR_IS_OK(werr)) {
     218           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), __location__ ": failed to get schema_info");
     219           0 :                 return ldb_operr(ldb_module_get_ctx(ldb_module));
     220             :         }
     221             : 
     222        1797 :         return LDB_SUCCESS;
     223             : }
     224             : 
     225             : /**
     226             :  * Writes schema_info structure into schemaInfo
     227             :  * attribute on SCHEMA partition
     228             :  *
     229             :  * @param dsdb_flags    DSDB_FLAG_... flag of 0
     230             :  */
     231        1816 : static int dsdb_module_schema_info_write(struct ldb_module *ldb_module,
     232             :                                          uint32_t dsdb_flags,
     233             :                                          const struct dsdb_schema_info *schema_info,
     234             :                                          struct ldb_request *parent)
     235             : {
     236           1 :         WERROR werr;
     237           1 :         int ret;
     238           1 :         DATA_BLOB ndr_blob;
     239           1 :         TALLOC_CTX *temp_ctx;
     240             : 
     241        1816 :         temp_ctx = talloc_new(ldb_module);
     242        1816 :         if (temp_ctx == NULL) {
     243           0 :                 return ldb_module_oom(ldb_module);
     244             :         }
     245             : 
     246             :         /* convert schema_info to a blob */
     247        1816 :         werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob);
     248        1816 :         if (!W_ERROR_IS_OK(werr)) {
     249           0 :                 talloc_free(temp_ctx);
     250           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), __location__ ": failed to get schema_info");
     251           0 :                 return ldb_operr(ldb_module_get_ctx(ldb_module));
     252             :         }
     253             : 
     254             :         /* write serialized schemaInfo into LDB */
     255        1816 :         ret = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob, parent);
     256             : 
     257        1816 :         talloc_free(temp_ctx);
     258             : 
     259        1816 :         return ret;
     260             : }
     261             : 
     262             : 
     263             : /**
     264             :  * Increments schemaInfo revision and save it to DB
     265             :  * setting our invocationID in the process
     266             :  * NOTE: this function should be called in a transaction
     267             :  * much in the same way prefixMap update function is called
     268             :  *
     269             :  * @param ldb_module    current module
     270             :  * @param schema        schema cache
     271             :  * @param dsdb_flags    DSDB_FLAG_... flag of 0
     272             :  */
     273        1816 : int dsdb_module_schema_info_update(struct ldb_module *ldb_module,
     274             :                                    struct dsdb_schema *schema,
     275             :                                    int dsdb_flags, struct ldb_request *parent)
     276             : {
     277           1 :         int ret;
     278           1 :         const struct GUID *invocation_id;
     279           1 :         struct dsdb_schema_info *schema_info;
     280           1 :         WERROR werr;
     281        1816 :         TALLOC_CTX *temp_ctx = talloc_new(schema);
     282        1816 :         if (temp_ctx == NULL) {
     283           0 :                 return ldb_module_oom(ldb_module);
     284             :         }
     285             : 
     286        1816 :         invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
     287        1816 :         if (!invocation_id) {
     288           0 :                 talloc_free(temp_ctx);
     289           0 :                 return ldb_operr(ldb_module_get_ctx(ldb_module));
     290             :         }
     291             : 
     292             :         /* read serialized schemaInfo from LDB  */
     293        1816 :         ret = dsdb_module_schema_info_read(ldb_module, dsdb_flags, temp_ctx, &schema_info, parent);
     294        1816 :         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
     295             :                 /* make default value in case
     296             :                  * we have no schemaInfo value yet */
     297          18 :                 werr = dsdb_schema_info_new(temp_ctx, &schema_info);
     298          18 :                 if (!W_ERROR_IS_OK(werr)) {
     299           0 :                         talloc_free(temp_ctx);
     300           0 :                         return ldb_module_oom(ldb_module);
     301             :                 }
     302          18 :                 ret = LDB_SUCCESS;
     303             :         }
     304        1816 :         if (ret != LDB_SUCCESS) {
     305           0 :                 talloc_free(temp_ctx);
     306           0 :                 return ret;
     307             :         }
     308             : 
     309             :         /* update schemaInfo */
     310        1816 :         schema_info->revision++;
     311        1816 :         schema_info->invocation_id = *invocation_id;
     312             : 
     313        1816 :         ret = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info, parent);
     314        1816 :         if (ret != LDB_SUCCESS) {
     315           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module),
     316             :                                        "dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
     317             :                                        ldb_strerror(ret));
     318           0 :                 talloc_free(temp_ctx);
     319           0 :                 return ret;
     320             :         }
     321             : 
     322             :         /*
     323             :          * We don't update the schema->schema_info!
     324             :          * as that would not represent the other information
     325             :          * in schema->*
     326             :          *
     327             :          * We're not sure if the current transaction will go through!
     328             :          * E.g. schema changes are only allowed on the schema master,
     329             :          * otherwise they result in a UNWILLING_TO_PERFORM and a
     330             :          *
     331             :          * Note that schema might a global variable shared between
     332             :          * multiple ldb_contexts. With process model "single" it
     333             :          * means the drsuapi server also uses it.
     334             :          *
     335             :          * We keep it simple and just try to update the
     336             :          * stored value.
     337             :          *
     338             :          * The next schema reload will pick it up, which
     339             :          * then works for originating and replicated changes
     340             :          * in the same way.
     341             :          */
     342             : 
     343        1816 :         talloc_free(temp_ctx);
     344        1816 :         return LDB_SUCCESS;
     345             : }

Generated by: LCOV version 1.14