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

          Line data    Source code
       1             : /* 
       2             :    ldb database library
       3             : 
       4             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
       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 update_keytabs module
      24             :  *
      25             :  *  Description: Update keytabs whenever their 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             : 
      41             : struct dn_list {
      42             :         struct ldb_message *msg;
      43             :         bool do_delete;
      44             :         struct dn_list *prev, *next;
      45             : };
      46             : 
      47             : struct update_kt_private {
      48             :         struct dn_list *changed_dns;
      49             : };
      50             : 
      51             : struct update_kt_ctx {
      52             :         struct ldb_module *module;
      53             :         struct ldb_request *req;
      54             : 
      55             :         struct ldb_dn *dn;
      56             :         bool do_delete;
      57             : 
      58             :         struct ldb_reply *op_reply;
      59             :         bool found;
      60             : };
      61             : 
      62        5181 : static struct update_kt_ctx *update_kt_ctx_init(struct ldb_module *module,
      63             :                                                 struct ldb_request *req)
      64             : {
      65          83 :         struct update_kt_ctx *ac;
      66             : 
      67        5181 :         ac = talloc_zero(req, struct update_kt_ctx);
      68        5181 :         if (ac == NULL) {
      69           0 :                 ldb_oom(ldb_module_get_ctx(module));
      70           0 :                 return NULL;
      71             :         }
      72             : 
      73        5181 :         ac->module = module;
      74        5181 :         ac->req = req;
      75             : 
      76        5181 :         return ac;
      77             : }
      78             : 
      79             : /* FIXME: too many semi-async searches here for my taste, direct and indirect as
      80             :  * cli_credentials_set_secrets() performs a sync ldb search.
      81             :  * Just hope we are lucky and nothing breaks (using the tdb backend masks a lot
      82             :  * of async issues). -SSS
      83             :  */
      84         251 : static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool do_delete,
      85             :                         struct ldb_request *parent)
      86             : {
      87         251 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
      88         251 :         struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
      89          26 :         struct dn_list *item;
      90          26 :         char *filter;
      91          26 :         struct ldb_result *res;
      92          26 :         int ret;
      93             : 
      94         251 :         filter = talloc_asprintf(data,
      95             :                                  "(&(objectClass=kerberosSecret)(privateKeytab=*))");
      96         251 :         if (!filter) {
      97           0 :                 return ldb_oom(ldb);
      98             :         }
      99             : 
     100         251 :         ret = dsdb_module_search(module, data, &res,
     101             :                                  dn, LDB_SCOPE_BASE, NULL,
     102             :                                  DSDB_FLAG_NEXT_MODULE, parent,
     103             :                                  "%s", filter);
     104         251 :         talloc_free(filter);
     105         251 :         if (ret != LDB_SUCCESS) {
     106           0 :                 return ret;
     107             :         }
     108             : 
     109         251 :         if (res->count != 1) {
     110             :                 /* if it's not a kerberosSecret then we don't have anything to update */
     111           0 :                 talloc_free(res);
     112           0 :                 return LDB_SUCCESS;
     113             :         }
     114             : 
     115         253 :         item = talloc(data->changed_dns? (void *)data->changed_dns: (void *)data, struct dn_list);
     116         251 :         if (!item) {
     117           0 :                 talloc_free(res);
     118           0 :                 return ldb_oom(ldb);
     119             :         }
     120             : 
     121         251 :         item->msg = talloc_steal(item, res->msgs[0]);
     122         251 :         item->do_delete = do_delete;
     123         251 :         talloc_free(res);
     124             : 
     125         251 :         DLIST_ADD_END(data->changed_dns, item);
     126         225 :         return LDB_SUCCESS;
     127             : }
     128             : 
     129             : static int ukt_search_modified(struct update_kt_ctx *ac);
     130             : 
     131        5181 : static int update_kt_op_callback(struct ldb_request *req,
     132             :                                  struct ldb_reply *ares)
     133             : {
     134          83 :         struct ldb_context *ldb;
     135          83 :         struct update_kt_ctx *ac;
     136          83 :         int ret;
     137             : 
     138        5181 :         ac = talloc_get_type(req->context, struct update_kt_ctx);
     139        5181 :         ldb = ldb_module_get_ctx(ac->module);
     140             : 
     141        5181 :         if (!ares) {
     142           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     143             :                                         LDB_ERR_OPERATIONS_ERROR);
     144             :         }
     145        5181 :         if (ares->error != LDB_SUCCESS) {
     146           9 :                 return ldb_module_done(ac->req, ares->controls,
     147             :                                         ares->response, ares->error);
     148             :         }
     149             : 
     150        5172 :         if (ares->type != LDB_REPLY_DONE) {
     151           0 :                 ldb_set_errstring(ldb, "Invalid request type!\n");
     152           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     153             :                                         LDB_ERR_OPERATIONS_ERROR);
     154             :         }
     155             : 
     156        5172 :         if (ac->do_delete) {
     157        1643 :                 return ldb_module_done(ac->req, ares->controls,
     158             :                                         ares->response, LDB_SUCCESS);
     159             :         }
     160             : 
     161        3529 :         ac->op_reply = talloc_steal(ac, ares);
     162             : 
     163        3529 :         ret = ukt_search_modified(ac);
     164        3529 :         if (ret != LDB_SUCCESS) {
     165           0 :                 return ldb_module_done(ac->req, NULL, NULL, ret);
     166             :         }
     167             : 
     168        3446 :         return LDB_SUCCESS;
     169             : }
     170             : 
     171        1652 : static int ukt_del_op(struct update_kt_ctx *ac)
     172             : {
     173           0 :         struct ldb_context *ldb;
     174           0 :         struct ldb_request *down_req;
     175           0 :         int ret;
     176             : 
     177        1652 :         ldb = ldb_module_get_ctx(ac->module);
     178             : 
     179        1652 :         ret = ldb_build_del_req(&down_req, ldb, ac,
     180             :                                 ac->dn,
     181        1652 :                                 ac->req->controls,
     182             :                                 ac, update_kt_op_callback,
     183             :                                 ac->req);
     184        1652 :         LDB_REQ_SET_LOCATION(down_req);
     185        1652 :         if (ret != LDB_SUCCESS) {
     186           0 :                 return ret;
     187             :         }
     188        1652 :         return ldb_next_request(ac->module, down_req);
     189             : }
     190             : 
     191        5432 : static int ukt_search_modified_callback(struct ldb_request *req,
     192             :                                         struct ldb_reply *ares)
     193             : {
     194         109 :         struct update_kt_ctx *ac;
     195         109 :         int ret;
     196             : 
     197        5432 :         ac = talloc_get_type(req->context, struct update_kt_ctx);
     198             : 
     199        5432 :         if (!ares) {
     200           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     201             :                                         LDB_ERR_OPERATIONS_ERROR);
     202             :         }
     203        5432 :         if (ares->error != LDB_SUCCESS) {
     204           0 :                 return ldb_module_done(ac->req, ares->controls,
     205             :                                         ares->response, ares->error);
     206             :         }
     207             : 
     208        5432 :         switch (ares->type) {
     209         251 :         case LDB_REPLY_ENTRY:
     210             : 
     211         251 :                 ac->found = true;
     212         251 :                 break;
     213             : 
     214           0 :         case LDB_REPLY_REFERRAL:
     215             :                 /* ignore */
     216           0 :                 break;
     217             : 
     218        5181 :         case LDB_REPLY_DONE:
     219             : 
     220        5181 :                 if (ac->found) {
     221             :                         /* do the dirty sync job here :/ */
     222         251 :                         ret = add_modified(ac->module, ac->dn, ac->do_delete, ac->req);
     223             :                 }
     224             : 
     225        5181 :                 if (ac->do_delete) {
     226        1652 :                         ret = ukt_del_op(ac);
     227        1652 :                         if (ret != LDB_SUCCESS) {
     228           0 :                                 return ldb_module_done(ac->req,
     229             :                                                         NULL, NULL, ret);
     230             :                         }
     231        1652 :                         break;
     232             :                 }
     233             : 
     234        3529 :                 return ldb_module_done(ac->req, ac->op_reply->controls,
     235        3529 :                                         ac->op_reply->response, LDB_SUCCESS);
     236             :         }
     237             : 
     238        1903 :         talloc_free(ares);
     239        1903 :         return LDB_SUCCESS;
     240             : }
     241             : 
     242        5181 : static int ukt_search_modified(struct update_kt_ctx *ac)
     243             : {
     244          83 :         struct ldb_context *ldb;
     245          83 :         static const char * const no_attrs[] = { NULL };
     246          83 :         struct ldb_request *search_req;
     247          83 :         int ret;
     248             : 
     249        5181 :         ldb = ldb_module_get_ctx(ac->module);
     250             : 
     251        5181 :         ret = ldb_build_search_req(&search_req, ldb, ac,
     252             :                                    ac->dn, LDB_SCOPE_BASE,
     253             :                                    "(&(objectClass=kerberosSecret)"
     254             :                                      "(privateKeytab=*))", no_attrs,
     255             :                                    NULL,
     256             :                                    ac, ukt_search_modified_callback,
     257             :                                    ac->req);
     258        5181 :         LDB_REQ_SET_LOCATION(search_req);
     259        5181 :         if (ret != LDB_SUCCESS) {
     260           0 :                 return ret;
     261             :         }
     262        5181 :         return ldb_next_request(ac->module, search_req);
     263             : }
     264             : 
     265             : 
     266             : /* add */
     267        2272 : static int update_kt_add(struct ldb_module *module, struct ldb_request *req)
     268             : {
     269          76 :         struct ldb_context *ldb;
     270          76 :         struct update_kt_ctx *ac;
     271          76 :         struct ldb_request *down_req;
     272          76 :         int ret;
     273             : 
     274        2272 :         ldb = ldb_module_get_ctx(module);
     275             : 
     276        2272 :         ac = update_kt_ctx_init(module, req);
     277        2272 :         if (ac == NULL) {
     278           0 :                 return ldb_operr(ldb);
     279             :         }
     280             : 
     281        2272 :         ac->dn = req->op.add.message->dn;
     282             : 
     283        2272 :         ret = ldb_build_add_req(&down_req, ldb, ac,
     284             :                                 req->op.add.message,
     285             :                                 req->controls,
     286             :                                 ac, update_kt_op_callback,
     287             :                                 req);
     288        2272 :         LDB_REQ_SET_LOCATION(down_req);
     289        2272 :         if (ret != LDB_SUCCESS) {
     290           0 :                 return ret;
     291             :         }
     292             : 
     293        2272 :         return ldb_next_request(module, down_req);
     294             : }
     295             : 
     296             : /* modify */
     297        1232 : static int update_kt_modify(struct ldb_module *module, struct ldb_request *req)
     298             : {
     299           5 :         struct ldb_context *ldb;
     300           5 :         struct update_kt_ctx *ac;
     301           5 :         struct ldb_request *down_req;
     302           5 :         int ret;
     303             : 
     304        1232 :         ldb = ldb_module_get_ctx(module);
     305             : 
     306        1232 :         ac = update_kt_ctx_init(module, req);
     307        1232 :         if (ac == NULL) {
     308           0 :                 return ldb_operr(ldb);
     309             :         }
     310             : 
     311        1232 :         ac->dn = req->op.mod.message->dn;
     312             : 
     313        1232 :         ret = ldb_build_mod_req(&down_req, ldb, ac,
     314             :                                 req->op.mod.message,
     315             :                                 req->controls,
     316             :                                 ac, update_kt_op_callback,
     317             :                                 req);
     318        1232 :         LDB_REQ_SET_LOCATION(down_req);
     319        1232 :         if (ret != LDB_SUCCESS) {
     320           0 :                 return ret;
     321             :         }
     322             : 
     323        1232 :         return ldb_next_request(module, down_req);
     324             : }
     325             : 
     326             : /* delete */
     327        1652 : static int update_kt_delete(struct ldb_module *module, struct ldb_request *req)
     328             : {
     329           0 :         struct update_kt_ctx *ac;
     330             : 
     331        1652 :         ac = update_kt_ctx_init(module, req);
     332        1652 :         if (ac == NULL) {
     333           0 :                 return ldb_operr(ldb_module_get_ctx(module));
     334             :         }
     335             : 
     336        1652 :         ac->dn = req->op.del.dn;
     337        1652 :         ac->do_delete = true;
     338             : 
     339        1652 :         return ukt_search_modified(ac);
     340             : }
     341             : 
     342             : /* rename */
     343          25 : static int update_kt_rename(struct ldb_module *module, struct ldb_request *req)
     344             : {
     345           2 :         struct ldb_context *ldb;
     346           2 :         struct update_kt_ctx *ac;
     347           2 :         struct ldb_request *down_req;
     348           2 :         int ret;
     349             : 
     350          25 :         ldb = ldb_module_get_ctx(module);
     351             : 
     352          25 :         ac = update_kt_ctx_init(module, req);
     353          25 :         if (ac == NULL) {
     354           0 :                 return ldb_operr(ldb);
     355             :         }
     356             : 
     357          25 :         ac->dn = req->op.rename.newdn;
     358             : 
     359          25 :         ret = ldb_build_rename_req(&down_req, ldb, ac,
     360             :                                 req->op.rename.olddn,
     361             :                                 req->op.rename.newdn,
     362             :                                 req->controls,
     363             :                                 ac, update_kt_op_callback,
     364             :                                 req);
     365          25 :         LDB_REQ_SET_LOCATION(down_req);
     366          25 :         if (ret != LDB_SUCCESS) {
     367           0 :                 return ret;
     368             :         }
     369             : 
     370          25 :         return ldb_next_request(module, down_req);
     371             : }
     372             : 
     373             : /* prepare for a commit */
     374        4815 : static int update_kt_prepare_commit(struct ldb_module *module)
     375             : {
     376        4815 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     377        4815 :         struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
     378          32 :         struct dn_list *p;
     379          32 :         struct smb_krb5_context *smb_krb5_context;
     380        4815 :         int krb5_ret = smb_krb5_init_context(data,
     381        4815 :                                              ldb_get_opaque(ldb, "loadparm"),
     382             :                                              &smb_krb5_context);
     383        4815 :         TALLOC_CTX *tmp_ctx = NULL;
     384             : 
     385        4815 :         if (krb5_ret != 0) {
     386           0 :                 ldb_asprintf_errstring(ldb, "Failed to setup krb5_context: %s", error_message(krb5_ret));
     387           0 :                 goto fail;
     388             :         }
     389             : 
     390        4815 :         tmp_ctx = talloc_new(data);
     391        4815 :         if (!tmp_ctx) {
     392           0 :                 ldb_oom(ldb);
     393           0 :                 goto fail;
     394             :         }
     395             : 
     396        5066 :         for (p=data->changed_dns; p; p = p->next) {
     397          26 :                 const char *error_string;
     398          26 :                 const char *realm;
     399          26 :                 char *upper_realm;
     400         251 :                 struct ldb_message_element *spn_el = ldb_msg_find_element(p->msg, "servicePrincipalName");
     401         251 :                 const char **SPNs = NULL;
     402         251 :                 int num_SPNs = 0;
     403          26 :                 int i;
     404             : 
     405         251 :                 realm = ldb_msg_find_attr_as_string(p->msg, "realm", NULL);
     406             : 
     407         251 :                 if (spn_el) {
     408         251 :                         upper_realm = strupper_talloc(tmp_ctx, realm);
     409         251 :                         if (!upper_realm) {
     410           0 :                                 ldb_oom(ldb);
     411           0 :                                 goto fail;
     412             :                         }
     413             : 
     414         251 :                         num_SPNs = spn_el->num_values;
     415         251 :                         SPNs = talloc_array(tmp_ctx, const char *, num_SPNs);
     416         251 :                         if (!SPNs) {
     417           0 :                                 ldb_oom(ldb);
     418           0 :                                 goto fail;
     419             :                         }
     420         733 :                         for (i = 0; i < num_SPNs; i++) {
     421         964 :                                 SPNs[i] = talloc_asprintf(SPNs, "%*.*s@%s",
     422         431 :                                                           (int)spn_el->values[i].length,
     423         482 :                                                           (int)spn_el->values[i].length,
     424         482 :                                                           (const char *)spn_el->values[i].data,
     425             :                                                           upper_realm);
     426         482 :                                 if (!SPNs[i]) {
     427           0 :                                         ldb_oom(ldb);
     428           0 :                                         goto fail;
     429             :                                 }
     430             :                         }
     431             :                 }
     432             : 
     433         251 :                 krb5_ret = smb_krb5_update_keytab(tmp_ctx, smb_krb5_context->krb5_context,
     434         251 :                                                   keytab_name_from_msg(tmp_ctx, ldb, p->msg),
     435         251 :                                                   ldb_msg_find_attr_as_string(p->msg, "samAccountName", NULL),
     436             :                                                   realm, SPNs, num_SPNs,
     437         251 :                                                   ldb_msg_find_attr_as_string(p->msg, "saltPrincipal", NULL),
     438         251 :                                                   ldb_msg_find_attr_as_string(p->msg, "secret", NULL),
     439         251 :                                                   ldb_msg_find_attr_as_string(p->msg, "priorSecret", NULL),
     440         251 :                                                   ldb_msg_find_attr_as_int(p->msg, "msDS-KeyVersionNumber", 0),
     441         251 :                                                   (uint32_t)ldb_msg_find_attr_as_int(p->msg, "msDS-SupportedEncryptionTypes", ENC_ALL_TYPES),
     442         251 :                                                   p->do_delete, NULL, &error_string);
     443         251 :                 if (krb5_ret != 0) {
     444           0 :                         ldb_asprintf_errstring(ldb, "Failed to update keytab from entry %s in %s: %s",
     445           0 :                                                ldb_dn_get_linearized(p->msg->dn),
     446           0 :                                                (const char *)ldb_get_opaque(ldb, "ldb_url"),
     447             :                                                error_string);
     448           0 :                         goto fail;
     449             :                 }
     450             :         }
     451             : 
     452        4815 :         talloc_free(data->changed_dns);
     453        4815 :         data->changed_dns = NULL;
     454        4815 :         talloc_free(tmp_ctx);
     455             : 
     456        4815 :         return ldb_next_prepare_commit(module);
     457             : 
     458           0 : fail:
     459           0 :         talloc_free(data->changed_dns);
     460           0 :         data->changed_dns = NULL;
     461           0 :         talloc_free(tmp_ctx);
     462           0 :         return LDB_ERR_OPERATIONS_ERROR;
     463             : }
     464             : 
     465             : /* end a transaction */
     466          38 : static int update_kt_del_trans(struct ldb_module *module)
     467             : {
     468          38 :         struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
     469             : 
     470          38 :         talloc_free(data->changed_dns);
     471          38 :         data->changed_dns = NULL;
     472             : 
     473          38 :         return ldb_next_del_trans(module);
     474             : }
     475             : 
     476       69623 : static int update_kt_init(struct ldb_module *module)
     477             : {
     478        2687 :         struct ldb_context *ldb;
     479        2687 :         struct update_kt_private *data;
     480             : 
     481       69623 :         ldb = ldb_module_get_ctx(module);
     482             : 
     483       69623 :         data = talloc(module, struct update_kt_private);
     484       69623 :         if (data == NULL) {
     485           0 :                 return ldb_oom(ldb);
     486             :         }
     487             : 
     488       69623 :         data->changed_dns = NULL;
     489             : 
     490       69623 :         ldb_module_set_private(module, data);
     491             : 
     492       69623 :         return ldb_next_init(module);
     493             : }
     494             : 
     495             : static const struct ldb_module_ops ldb_update_keytab_module_ops = {
     496             :         .name              = "update_keytab",
     497             :         .init_context      = update_kt_init,
     498             :         .add               = update_kt_add,
     499             :         .modify            = update_kt_modify,
     500             :         .rename            = update_kt_rename,
     501             :         .del               = update_kt_delete,
     502             :         .prepare_commit    = update_kt_prepare_commit,
     503             :         .del_transaction   = update_kt_del_trans,
     504             : };
     505             : 
     506        6040 : int ldb_update_keytab_module_init(const char *version)
     507             : {
     508        6040 :         LDB_MODULE_CHECK_VERSION(version);
     509        6040 :         return ldb_register_module(&ldb_update_keytab_module_ops);
     510             : }

Generated by: LCOV version 1.14