LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - secrets_tdb_sync.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 160 203 78.8 %
Date: 2021-09-23 10:06:22 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /*
       2             :    ldb database library
       3             : 
       4             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2012
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : /*
      21             :  *  Name: ldb
      22             :  *
      23             :  *  Component: ldb secrets_tdb_sync module
      24             :  *
      25             :  *  Description: Update secrets.tdb whenever the matching secret record changes
      26             :  *
      27             :  *  Author: Andrew Bartlett
      28             :  */
      29             : 
      30             : #include "includes.h"
      31             : #include "ldb_module.h"
      32             : #include "lib/util/dlinklist.h"
      33             : #include "auth/credentials/credentials.h"
      34             : #include "auth/credentials/credentials_krb5.h"
      35             : #include "system/kerberos.h"
      36             : #include "auth/kerberos/kerberos.h"
      37             : #include "auth/kerberos/kerberos_srv_keytab.h"
      38             : #include "dsdb/samdb/ldb_modules/util.h"
      39             : #include "param/secrets.h"
      40             : #include "source3/include/secrets.h"
      41             : #include "lib/dbwrap/dbwrap.h"
      42             : #include "dsdb/samdb/samdb.h"
      43             : 
      44             : struct dn_list {
      45             :         struct ldb_message *msg;
      46             :         bool do_delete;
      47             :         struct dn_list *prev, *next;
      48             : };
      49             : 
      50             : struct secrets_tdb_sync_private {
      51             :         struct dn_list *changed_dns;
      52             :         struct db_context *secrets_tdb;
      53             : };
      54             : 
      55             : struct secrets_tdb_sync_ctx {
      56             :         struct ldb_module *module;
      57             :         struct ldb_request *req;
      58             : 
      59             :         struct ldb_dn *dn;
      60             :         bool do_delete;
      61             : 
      62             :         struct ldb_reply *op_reply;
      63             :         bool found;
      64             : };
      65             : 
      66        5287 : static struct secrets_tdb_sync_ctx *secrets_tdb_sync_ctx_init(struct ldb_module *module,
      67             :                                                 struct ldb_request *req)
      68             : {
      69             :         struct secrets_tdb_sync_ctx *ac;
      70             : 
      71        5287 :         ac = talloc_zero(req, struct secrets_tdb_sync_ctx);
      72        5287 :         if (ac == NULL) {
      73           0 :                 ldb_oom(ldb_module_get_ctx(module));
      74           0 :                 return NULL;
      75             :         }
      76             : 
      77        5287 :         ac->module = module;
      78        5287 :         ac->req = req;
      79             : 
      80        5287 :         return ac;
      81             : }
      82             : 
      83             : /* FIXME: too many semi-async searches here for my taste, direct and indirect as
      84             :  * cli_credentials_set_secrets() performs a sync ldb search.
      85             :  * Just hope we are lucky and nothing breaks (using the tdb backend masks a lot
      86             :  * of async issues). -SSS
      87             :  */
      88         241 : static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool do_delete,
      89             :                         struct ldb_request *parent)
      90             : {
      91         241 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
      92         241 :         struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
      93             :         struct dn_list *item;
      94             :         char *filter;
      95             :         struct ldb_result *res;
      96             :         int ret;
      97             : 
      98         241 :         filter = talloc_asprintf(data,
      99             :                                  "(&(objectClass=primaryDomain)(flatname=*))");
     100         241 :         if (!filter) {
     101           0 :                 return ldb_oom(ldb);
     102             :         }
     103             : 
     104         241 :         ret = dsdb_module_search(module, data, &res,
     105             :                                  dn, LDB_SCOPE_BASE, NULL,
     106             :                                  DSDB_FLAG_NEXT_MODULE, parent,
     107             :                                  "%s", filter);
     108         241 :         talloc_free(filter);
     109         241 :         if (ret != LDB_SUCCESS) {
     110           0 :                 return ret;
     111             :         }
     112             : 
     113         241 :         if (res->count != 1) {
     114             :                 /* if it's not a primaryDomain then we don't have anything to update */
     115           9 :                 talloc_free(res);
     116           9 :                 return LDB_SUCCESS;
     117             :         }
     118             : 
     119         232 :         item = talloc(data->changed_dns? (void *)data->changed_dns: (void *)data, struct dn_list);
     120         232 :         if (!item) {
     121           0 :                 talloc_free(res);
     122           0 :                 return ldb_oom(ldb);
     123             :         }
     124             : 
     125         232 :         item->msg = talloc_steal(item, res->msgs[0]);
     126         232 :         item->do_delete = do_delete;
     127         232 :         talloc_free(res);
     128             : 
     129         232 :         DLIST_ADD_END(data->changed_dns, item);
     130         208 :         return LDB_SUCCESS;
     131             : }
     132             : 
     133             : static int ust_search_modified(struct secrets_tdb_sync_ctx *ac);
     134             : 
     135        5287 : static int secrets_tdb_sync_op_callback(struct ldb_request *req,
     136             :                                  struct ldb_reply *ares)
     137             : {
     138             :         struct ldb_context *ldb;
     139             :         struct secrets_tdb_sync_ctx *ac;
     140             :         int ret;
     141             : 
     142        5287 :         ac = talloc_get_type(req->context, struct secrets_tdb_sync_ctx);
     143        5287 :         ldb = ldb_module_get_ctx(ac->module);
     144             : 
     145        5287 :         if (!ares) {
     146           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     147             :                                         LDB_ERR_OPERATIONS_ERROR);
     148             :         }
     149        5287 :         if (ares->error != LDB_SUCCESS) {
     150          11 :                 return ldb_module_done(ac->req, ares->controls,
     151             :                                         ares->response, ares->error);
     152             :         }
     153             : 
     154        5276 :         if (ares->type != LDB_REPLY_DONE) {
     155           0 :                 ldb_set_errstring(ldb, "Invalid request type!\n");
     156           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     157             :                                         LDB_ERR_OPERATIONS_ERROR);
     158             :         }
     159             : 
     160        5276 :         if (ac->do_delete) {
     161        1693 :                 return ldb_module_done(ac->req, ares->controls,
     162             :                                         ares->response, LDB_SUCCESS);
     163             :         }
     164             : 
     165        3583 :         ac->op_reply = talloc_steal(ac, ares);
     166             : 
     167        3583 :         ret = ust_search_modified(ac);
     168        3583 :         if (ret != LDB_SUCCESS) {
     169           0 :                 return ldb_module_done(ac->req, NULL, NULL, ret);
     170             :         }
     171             : 
     172        3503 :         return LDB_SUCCESS;
     173             : }
     174             : 
     175        1704 : static int ust_del_op(struct secrets_tdb_sync_ctx *ac)
     176             : {
     177             :         struct ldb_context *ldb;
     178             :         struct ldb_request *down_req;
     179             :         int ret;
     180             : 
     181        1704 :         ldb = ldb_module_get_ctx(ac->module);
     182             : 
     183        2706 :         ret = ldb_build_del_req(&down_req, ldb, ac,
     184             :                                 ac->dn,
     185        1704 :                                 ac->req->controls,
     186             :                                 ac, secrets_tdb_sync_op_callback,
     187             :                                 ac->req);
     188        1704 :         LDB_REQ_SET_LOCATION(down_req);
     189        1704 :         if (ret != LDB_SUCCESS) {
     190           0 :                 return ret;
     191             :         }
     192        1704 :         return ldb_next_request(ac->module, down_req);
     193             : }
     194             : 
     195        5528 : static int ust_search_modified_callback(struct ldb_request *req,
     196             :                                         struct ldb_reply *ares)
     197             : {
     198             :         struct secrets_tdb_sync_ctx *ac;
     199             :         int ret;
     200             : 
     201        5528 :         ac = talloc_get_type(req->context, struct secrets_tdb_sync_ctx);
     202             : 
     203        5528 :         if (!ares) {
     204           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     205             :                                         LDB_ERR_OPERATIONS_ERROR);
     206             :         }
     207        5528 :         if (ares->error != LDB_SUCCESS) {
     208           0 :                 return ldb_module_done(ac->req, ares->controls,
     209             :                                         ares->response, ares->error);
     210             :         }
     211             : 
     212        5528 :         switch (ares->type) {
     213         241 :         case LDB_REPLY_ENTRY:
     214             : 
     215         241 :                 ac->found = true;
     216         241 :                 break;
     217             : 
     218           0 :         case LDB_REPLY_REFERRAL:
     219             :                 /* ignore */
     220           0 :                 break;
     221             : 
     222        5287 :         case LDB_REPLY_DONE:
     223             : 
     224        5287 :                 if (ac->found) {
     225             :                         /* do the dirty sync job here :/ */
     226         241 :                         ret = add_modified(ac->module, ac->dn, ac->do_delete, ac->req);
     227             :                 }
     228             : 
     229        5287 :                 if (ac->do_delete) {
     230        1704 :                         ret = ust_del_op(ac);
     231        1704 :                         if (ret != LDB_SUCCESS) {
     232           0 :                                 return ldb_module_done(ac->req,
     233             :                                                         NULL, NULL, ret);
     234             :                         }
     235        1704 :                         break;
     236             :                 }
     237             : 
     238        3583 :                 return ldb_module_done(ac->req, ac->op_reply->controls,
     239        3583 :                                         ac->op_reply->response, LDB_SUCCESS);
     240             :         }
     241             : 
     242        1945 :         talloc_free(ares);
     243        1945 :         return LDB_SUCCESS;
     244             : }
     245             : 
     246        5287 : static int ust_search_modified(struct secrets_tdb_sync_ctx *ac)
     247             : {
     248             :         struct ldb_context *ldb;
     249             :         static const char * const no_attrs[] = { NULL };
     250             :         struct ldb_request *search_req;
     251             :         int ret;
     252             : 
     253        5287 :         ldb = ldb_module_get_ctx(ac->module);
     254             : 
     255        5287 :         ret = ldb_build_search_req(&search_req, ldb, ac,
     256             :                                    ac->dn, LDB_SCOPE_BASE,
     257             :                                    "(&(objectClass=kerberosSecret)"
     258             :                                      "(privateKeytab=*))", no_attrs,
     259             :                                    NULL,
     260             :                                    ac, ust_search_modified_callback,
     261             :                                    ac->req);
     262        5287 :         LDB_REQ_SET_LOCATION(search_req);
     263        5287 :         if (ret != LDB_SUCCESS) {
     264           0 :                 return ret;
     265             :         }
     266        5287 :         return ldb_next_request(ac->module, search_req);
     267             : }
     268             : 
     269             : 
     270             : /* add */
     271        2288 : static int secrets_tdb_sync_add(struct ldb_module *module, struct ldb_request *req)
     272             : {
     273             :         struct ldb_context *ldb;
     274             :         struct secrets_tdb_sync_ctx *ac;
     275             :         struct ldb_request *down_req;
     276             :         int ret;
     277             : 
     278        2288 :         ldb = ldb_module_get_ctx(module);
     279             : 
     280        2288 :         ac = secrets_tdb_sync_ctx_init(module, req);
     281        2288 :         if (ac == NULL) {
     282           0 :                 return ldb_operr(ldb);
     283             :         }
     284             : 
     285        2288 :         ac->dn = req->op.add.message->dn;
     286             : 
     287        2288 :         ret = ldb_build_add_req(&down_req, ldb, ac,
     288             :                                 req->op.add.message,
     289             :                                 req->controls,
     290             :                                 ac, secrets_tdb_sync_op_callback,
     291             :                                 req);
     292        2288 :         LDB_REQ_SET_LOCATION(down_req);
     293        2288 :         if (ret != LDB_SUCCESS) {
     294           0 :                 return ret;
     295             :         }
     296             : 
     297        2288 :         return ldb_next_request(module, down_req);
     298             : }
     299             : 
     300             : /* modify */
     301        1270 : static int secrets_tdb_sync_modify(struct ldb_module *module, struct ldb_request *req)
     302             : {
     303             :         struct ldb_context *ldb;
     304             :         struct secrets_tdb_sync_ctx *ac;
     305             :         struct ldb_request *down_req;
     306             :         int ret;
     307             : 
     308        1270 :         ldb = ldb_module_get_ctx(module);
     309             : 
     310        1270 :         ac = secrets_tdb_sync_ctx_init(module, req);
     311        1270 :         if (ac == NULL) {
     312           0 :                 return ldb_operr(ldb);
     313             :         }
     314             : 
     315        1270 :         ac->dn = req->op.mod.message->dn;
     316             : 
     317        1270 :         ret = ldb_build_mod_req(&down_req, ldb, ac,
     318             :                                 req->op.mod.message,
     319             :                                 req->controls,
     320             :                                 ac, secrets_tdb_sync_op_callback,
     321             :                                 req);
     322        1270 :         LDB_REQ_SET_LOCATION(down_req);
     323        1270 :         if (ret != LDB_SUCCESS) {
     324           0 :                 return ret;
     325             :         }
     326             : 
     327        1270 :         return ldb_next_request(module, down_req);
     328             : }
     329             : 
     330             : /* delete */
     331        1704 : static int secrets_tdb_sync_delete(struct ldb_module *module, struct ldb_request *req)
     332             : {
     333             :         struct secrets_tdb_sync_ctx *ac;
     334             : 
     335        1704 :         ac = secrets_tdb_sync_ctx_init(module, req);
     336        1704 :         if (ac == NULL) {
     337           0 :                 return ldb_operr(ldb_module_get_ctx(module));
     338             :         }
     339             : 
     340        1704 :         ac->dn = req->op.del.dn;
     341        1704 :         ac->do_delete = true;
     342             : 
     343        1704 :         return ust_search_modified(ac);
     344             : }
     345             : 
     346             : /* rename */
     347          25 : static int secrets_tdb_sync_rename(struct ldb_module *module, struct ldb_request *req)
     348             : {
     349             :         struct ldb_context *ldb;
     350             :         struct secrets_tdb_sync_ctx *ac;
     351             :         struct ldb_request *down_req;
     352             :         int ret;
     353             : 
     354          25 :         ldb = ldb_module_get_ctx(module);
     355             : 
     356          25 :         ac = secrets_tdb_sync_ctx_init(module, req);
     357          25 :         if (ac == NULL) {
     358           0 :                 return ldb_operr(ldb);
     359             :         }
     360             : 
     361          25 :         ac->dn = req->op.rename.newdn;
     362             : 
     363          25 :         ret = ldb_build_rename_req(&down_req, ldb, ac,
     364             :                                 req->op.rename.olddn,
     365             :                                 req->op.rename.newdn,
     366             :                                 req->controls,
     367             :                                 ac, secrets_tdb_sync_op_callback,
     368             :                                 req);
     369          25 :         LDB_REQ_SET_LOCATION(down_req);
     370          25 :         if (ret != LDB_SUCCESS) {
     371           0 :                 return ret;
     372             :         }
     373             : 
     374          25 :         return ldb_next_request(module, down_req);
     375             : }
     376             : 
     377             : /* prepare for a commit */
     378        4937 : static int secrets_tdb_sync_prepare_commit(struct ldb_module *module)
     379             : {
     380        4937 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     381        4937 :         struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module),
     382             :                                                                 struct secrets_tdb_sync_private);
     383             :         struct dn_list *p;
     384             :         TALLOC_CTX *tmp_ctx;
     385             : 
     386        4937 :         tmp_ctx = talloc_new(data);
     387        4937 :         if (!tmp_ctx) {
     388           0 :                 ldb_oom(ldb);
     389           0 :                 goto fail;
     390             :         }
     391             : 
     392        5169 :         for (p=data->changed_dns; p; p = p->next) {
     393         232 :                 const struct ldb_val *whenChanged = ldb_msg_find_ldb_val(p->msg, "whenChanged");
     394         232 :                 time_t lct = 0;
     395             :                 bool ret;
     396             : 
     397         232 :                 if (whenChanged) {
     398         232 :                         ldb_val_to_time(whenChanged, &lct);
     399             :                 }
     400             : 
     401        1402 :                 ret = secrets_store_machine_pw_sync(ldb_msg_find_attr_as_string(p->msg, "secret", NULL),
     402         232 :                                                     ldb_msg_find_attr_as_string(p->msg, "priorSecret", NULL),
     403             : 
     404         232 :                                                     ldb_msg_find_attr_as_string(p->msg, "flatname", NULL),
     405         232 :                                                     ldb_msg_find_attr_as_string(p->msg, "realm", NULL),
     406         232 :                                                     ldb_msg_find_attr_as_string(p->msg, "saltPrincipal", NULL),
     407         232 :                                                     (uint32_t)ldb_msg_find_attr_as_int(p->msg, "msDS-SupportedEncryptionTypes", ENC_ALL_TYPES),
     408         232 :                                                     samdb_result_dom_sid(tmp_ctx, p->msg, "objectSid"),
     409             : 
     410             :                                                     lct,
     411         232 :                                                     (uint32_t)ldb_msg_find_attr_as_int(p->msg, "secureChannelType", 0),
     412         232 :                                                     p->do_delete);
     413         232 :                 if (ret == false) {
     414           0 :                         ldb_asprintf_errstring(ldb, "Failed to update secrets.tdb from entry %s in %s",
     415           0 :                                                ldb_dn_get_linearized(p->msg->dn),
     416           0 :                                                (const char *)ldb_get_opaque(ldb, "ldb_url"));
     417           0 :                         goto fail;
     418             :                 }
     419             :         }
     420             : 
     421        4937 :         talloc_free(data->changed_dns);
     422        4937 :         data->changed_dns = NULL;
     423        4937 :         talloc_free(tmp_ctx);
     424             : 
     425        4937 :         return ldb_next_prepare_commit(module);
     426             : 
     427           0 : fail:
     428           0 :         dbwrap_transaction_cancel(data->secrets_tdb);
     429           0 :         talloc_free(data->changed_dns);
     430           0 :         data->changed_dns = NULL;
     431           0 :         talloc_free(tmp_ctx);
     432           0 :         return LDB_ERR_OPERATIONS_ERROR;
     433             : }
     434             : 
     435             : /* start a transaction */
     436        4978 : static int secrets_tdb_sync_start_transaction(struct ldb_module *module)
     437             : {
     438        4978 :         struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
     439             : 
     440        4978 :         if (dbwrap_transaction_start(data->secrets_tdb) != 0) {
     441           0 :                 return ldb_module_operr(module);
     442             :         }
     443             : 
     444        4978 :         return ldb_next_start_trans(module);
     445             : }
     446             : 
     447             : /* end a transaction */
     448        4937 : static int secrets_tdb_sync_end_transaction(struct ldb_module *module)
     449             : {
     450        4937 :         struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
     451             : 
     452        4937 :         if (dbwrap_transaction_commit(data->secrets_tdb) != 0) {
     453           0 :                 return ldb_module_operr(module);
     454             :         }
     455             : 
     456        4937 :         return ldb_next_end_trans(module);
     457             : }
     458             : 
     459             : /* abandon a transaction */
     460          40 : static int secrets_tdb_sync_del_transaction(struct ldb_module *module)
     461             : {
     462          40 :         struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
     463             : 
     464          40 :         talloc_free(data->changed_dns);
     465          40 :         data->changed_dns = NULL;
     466          40 :         if (dbwrap_transaction_cancel(data->secrets_tdb) != 0) {
     467           0 :                 return ldb_module_operr(module);
     468             :         }
     469             : 
     470          40 :         return ldb_next_del_trans(module);
     471             : }
     472             : 
     473       55630 : static int secrets_tdb_sync_init(struct ldb_module *module)
     474             : {
     475             :         struct ldb_context *ldb;
     476             :         struct secrets_tdb_sync_private *data;
     477             :         char *private_dir, *p;
     478             :         const char *secrets_ldb;
     479             : 
     480       55630 :         ldb = ldb_module_get_ctx(module);
     481             : 
     482       55630 :         data = talloc(module, struct secrets_tdb_sync_private);
     483       55630 :         if (data == NULL) {
     484           0 :                 return ldb_oom(ldb);
     485             :         }
     486             : 
     487       55630 :         data->changed_dns = NULL;
     488             : 
     489       55630 :         ldb_module_set_private(module, data);
     490             : 
     491       55630 :         secrets_ldb = (const char *)ldb_get_opaque(ldb, "ldb_url");
     492       55630 :         if (!secrets_ldb) {
     493           0 :                 return ldb_operr(ldb);
     494             :         }
     495       55630 :         if (strncmp("tdb://", secrets_ldb, 6) == 0) {
     496           0 :                 secrets_ldb += 6;
     497             :         }
     498       55630 :         private_dir = talloc_strdup(data, secrets_ldb);
     499       55630 :         p = strrchr(private_dir, '/');
     500       55630 :         if (p) {
     501       55630 :                 *p = '\0';
     502             :         } else {
     503           0 :                 private_dir = talloc_strdup(data, ".");
     504             :         }
     505             : 
     506       55630 :         secrets_init_path(private_dir);
     507             : 
     508       55630 :         TALLOC_FREE(private_dir);
     509             : 
     510       55630 :         data->secrets_tdb = secrets_db_ctx();
     511             : 
     512       55630 :         return ldb_next_init(module);
     513             : }
     514             : 
     515             : static const struct ldb_module_ops ldb_secrets_tdb_sync_module_ops = {
     516             :         .name              = "secrets_tdb_sync",
     517             :         .init_context      = secrets_tdb_sync_init,
     518             :         .add               = secrets_tdb_sync_add,
     519             :         .modify            = secrets_tdb_sync_modify,
     520             :         .rename            = secrets_tdb_sync_rename,
     521             :         .del               = secrets_tdb_sync_delete,
     522             :         .start_transaction = secrets_tdb_sync_start_transaction,
     523             :         .prepare_commit    = secrets_tdb_sync_prepare_commit,
     524             :         .end_transaction   = secrets_tdb_sync_end_transaction,
     525             :         .del_transaction   = secrets_tdb_sync_del_transaction,
     526             : };
     527             : 
     528        5536 : int ldb_secrets_tdb_sync_module_init(const char *version)
     529             : {
     530        5536 :         LDB_MODULE_CHECK_VERSION(version);
     531        5536 :         return ldb_register_module(&ldb_secrets_tdb_sync_module_ops);
     532             : }

Generated by: LCOV version 1.13