root/source4/dsdb/samdb/ldb_modules/update_keytab.c

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

DEFINITIONS

This source file includes following definitions.
  1. update_kt_ctx_init
  2. add_modified
  3. update_kt_op_callback
  4. ukt_del_op
  5. ukt_search_modified_callback
  6. ukt_search_modified
  7. update_kt_add
  8. update_kt_modify
  9. update_kt_delete
  10. update_kt_rename
  11. update_kt_end_trans
  12. update_kt_del_trans
  13. update_kt_init

   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 "dlinklist.h"
  33 #include "auth/credentials/credentials.h"
  34 #include "auth/credentials/credentials_krb5.h"
  35 #include "system/kerberos.h"
  36 
  37 struct dn_list {
  38         struct cli_credentials *creds;
  39         struct dn_list *prev, *next;
  40 };
  41 
  42 struct update_kt_private {
  43         struct dn_list *changed_dns;
  44 };
  45 
  46 struct update_kt_ctx {
  47         struct ldb_module *module;
  48         struct ldb_request *req;
  49 
  50         struct ldb_dn *dn;
  51         bool do_delete;
  52 
  53         struct ldb_reply *op_reply;
  54         bool found;
  55 };
  56 
  57 static struct update_kt_ctx *update_kt_ctx_init(struct ldb_module *module,
     /* [<][>][^][v][top][bottom][index][help] */
  58                                                 struct ldb_request *req)
  59 {
  60         struct update_kt_ctx *ac;
  61 
  62         ac = talloc_zero(req, struct update_kt_ctx);
  63         if (ac == NULL) {
  64                 ldb_oom(ldb_module_get_ctx(module));
  65                 return NULL;
  66         }
  67 
  68         ac->module = module;
  69         ac->req = req;
  70 
  71         return ac;
  72 }
  73 
  74 /* FIXME: too many semi-async searches here for my taste, direct and indirect as
  75  * cli_credentials_set_secrets() performs a sync ldb search.
  76  * Just hope we are lucky and nothing breaks (using the tdb backend masks a lot
  77  * of async issues). -SSS
  78  */
  79 static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool do_delete) {
     /* [<][>][^][v][top][bottom][index][help] */
  80         struct ldb_context *ldb = ldb_module_get_ctx(module);
  81         struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
  82         struct dn_list *item;
  83         char *filter;
  84         struct ldb_result *res;
  85         const char *attrs[] = { NULL };
  86         int ret;
  87         NTSTATUS status;
  88 
  89         filter = talloc_asprintf(data, "(&(dn=%s)(&(objectClass=kerberosSecret)(privateKeytab=*)))",
  90                                  ldb_dn_get_linearized(dn));
  91         if (!filter) {
  92                 ldb_oom(ldb);
  93                 return LDB_ERR_OPERATIONS_ERROR;
  94         }
  95 
  96         ret = ldb_search(ldb, data, &res,
  97                          dn, LDB_SCOPE_BASE, attrs, "%s", filter);
  98         if (ret != LDB_SUCCESS) {
  99                 talloc_free(filter);
 100                 return ret;
 101         }
 102 
 103         if (res->count != 1) {
 104                 /* if it's not a kerberosSecret then we don't have anything to update */
 105                 talloc_free(res);
 106                 talloc_free(filter);
 107                 return LDB_SUCCESS;
 108         }
 109         talloc_free(res);
 110 
 111         item = talloc(data->changed_dns? (void *)data->changed_dns: (void *)data, struct dn_list);
 112         if (!item) {
 113                 talloc_free(filter);
 114                 ldb_oom(ldb);
 115                 return LDB_ERR_OPERATIONS_ERROR;
 116         }
 117 
 118         item->creds = cli_credentials_init(item);
 119         if (!item->creds) {
 120                 DEBUG(1, ("cli_credentials_init failed!"));
 121                 talloc_free(filter);
 122                 ldb_oom(ldb);
 123                 return LDB_ERR_OPERATIONS_ERROR;
 124         }
 125 
 126         cli_credentials_set_conf(item->creds, ldb_get_opaque(ldb, "loadparm"));
 127         status = cli_credentials_set_secrets(item->creds, ldb_get_event_context(ldb), ldb_get_opaque(ldb, "loadparm"), ldb, NULL, filter);
 128         talloc_free(filter);
 129         if (NT_STATUS_IS_OK(status)) {
 130                 if (do_delete) {
 131                         /* Ensure we don't helpfully keep an old keytab entry */
 132                         cli_credentials_set_kvno(item->creds, cli_credentials_get_kvno(item->creds)+2); 
 133                         /* Wipe passwords */
 134                         cli_credentials_set_nt_hash(item->creds, NULL, 
 135                                                     CRED_SPECIFIED);
 136                 }
 137                 DLIST_ADD_END(data->changed_dns, item, struct dn_list *);
 138         }
 139         return LDB_SUCCESS;
 140 }
 141 
 142 static int ukt_search_modified(struct update_kt_ctx *ac);
 143 
 144 static int update_kt_op_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 145                                  struct ldb_reply *ares)
 146 {
 147         struct ldb_context *ldb;
 148         struct update_kt_ctx *ac;
 149         int ret;
 150 
 151         ac = talloc_get_type(req->context, struct update_kt_ctx);
 152         ldb = ldb_module_get_ctx(ac->module);
 153 
 154         if (!ares) {
 155                 return ldb_module_done(ac->req, NULL, NULL,
 156                                         LDB_ERR_OPERATIONS_ERROR);
 157         }
 158         if (ares->error != LDB_SUCCESS) {
 159                 return ldb_module_done(ac->req, ares->controls,
 160                                         ares->response, ares->error);
 161         }
 162 
 163         if (ares->type != LDB_REPLY_DONE) {
 164                 ldb_set_errstring(ldb, "Invalid request type!\n");
 165                 return ldb_module_done(ac->req, NULL, NULL,
 166                                         LDB_ERR_OPERATIONS_ERROR);
 167         }
 168 
 169         if (ac->do_delete) {
 170                 return ldb_module_done(ac->req, ares->controls,
 171                                         ares->response, LDB_SUCCESS);
 172         }
 173 
 174         ac->op_reply = talloc_steal(ac, ares);
 175 
 176         ret = ukt_search_modified(ac);
 177         if (ret != LDB_SUCCESS) {
 178                 return ldb_module_done(ac->req, NULL, NULL, ret);
 179         }
 180 
 181         return LDB_SUCCESS;
 182 }
 183 
 184 static int ukt_del_op(struct update_kt_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 185 {
 186         struct ldb_context *ldb;
 187         struct ldb_request *down_req;
 188         int ret;
 189 
 190         ldb = ldb_module_get_ctx(ac->module);
 191 
 192         ret = ldb_build_del_req(&down_req, ldb, ac,
 193                                 ac->dn,
 194                                 ac->req->controls,
 195                                 ac, update_kt_op_callback,
 196                                 ac->req);
 197         if (ret != LDB_SUCCESS) {
 198                 return ret;
 199         }
 200         return ldb_next_request(ac->module, down_req);
 201 }
 202 
 203 static int ukt_search_modified_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 204                                         struct ldb_reply *ares)
 205 {
 206         struct update_kt_ctx *ac;
 207         int ret;
 208 
 209         ac = talloc_get_type(req->context, struct update_kt_ctx);
 210 
 211         if (!ares) {
 212                 return ldb_module_done(ac->req, NULL, NULL,
 213                                         LDB_ERR_OPERATIONS_ERROR);
 214         }
 215         if (ares->error != LDB_SUCCESS) {
 216                 return ldb_module_done(ac->req, ares->controls,
 217                                         ares->response, ares->error);
 218         }
 219 
 220         switch (ares->type) {
 221         case LDB_REPLY_ENTRY:
 222 
 223                 ac->found = true;
 224                 break;
 225 
 226         case LDB_REPLY_REFERRAL:
 227                 /* ignore */
 228                 break;
 229 
 230         case LDB_REPLY_DONE:
 231 
 232                 if (ac->found) {
 233                         /* do the dirty sync job here :/ */
 234                         ret = add_modified(ac->module, ac->dn, ac->do_delete);
 235                 }
 236 
 237                 if (ac->do_delete) {
 238                         ret = ukt_del_op(ac);
 239                         if (ret != LDB_SUCCESS) {
 240                                 return ldb_module_done(ac->req,
 241                                                         NULL, NULL, ret);
 242                         }
 243                         break;
 244                 }
 245 
 246                 return ldb_module_done(ac->req, ac->op_reply->controls,
 247                                         ac->op_reply->response, LDB_SUCCESS);
 248         }
 249 
 250         talloc_free(ares);
 251         return LDB_SUCCESS;
 252 }
 253 
 254 static int ukt_search_modified(struct update_kt_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 255 {
 256         struct ldb_context *ldb;
 257         static const char * const attrs[] = { "distinguishedName", NULL };
 258         struct ldb_request *search_req;
 259         int ret;
 260 
 261         ldb = ldb_module_get_ctx(ac->module);
 262 
 263         ret = ldb_build_search_req(&search_req, ldb, ac,
 264                                    ac->dn, LDB_SCOPE_BASE,
 265                                    "(&(objectClass=kerberosSecret)"
 266                                      "(privateKeytab=*))", attrs,
 267                                    NULL,
 268                                    ac, ukt_search_modified_callback,
 269                                    ac->req);
 270         if (ret != LDB_SUCCESS) {
 271                 return ret;
 272         }
 273         return ldb_next_request(ac->module, search_req);
 274 }
 275 
 276 
 277 /* add */
 278 static int update_kt_add(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 279 {
 280         struct ldb_context *ldb;
 281         struct update_kt_ctx *ac;
 282         struct ldb_request *down_req;
 283         int ret;
 284 
 285         ldb = ldb_module_get_ctx(module);
 286 
 287         ac = update_kt_ctx_init(module, req);
 288         if (ac == NULL) {
 289                 return LDB_ERR_OPERATIONS_ERROR;
 290         }
 291 
 292         ac->dn = req->op.add.message->dn;
 293 
 294         ret = ldb_build_add_req(&down_req, ldb, ac,
 295                                 req->op.add.message,
 296                                 req->controls,
 297                                 ac, update_kt_op_callback,
 298                                 req);
 299         if (ret != LDB_SUCCESS) {
 300                 return ret;
 301         }
 302 
 303         return ldb_next_request(module, down_req);
 304 }
 305 
 306 /* modify */
 307 static int update_kt_modify(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 308 {
 309         struct ldb_context *ldb;
 310         struct update_kt_ctx *ac;
 311         struct ldb_request *down_req;
 312         int ret;
 313 
 314         ldb = ldb_module_get_ctx(module);
 315 
 316         ac = update_kt_ctx_init(module, req);
 317         if (ac == NULL) {
 318                 return LDB_ERR_OPERATIONS_ERROR;
 319         }
 320 
 321         ac->dn = req->op.mod.message->dn;
 322 
 323         ret = ldb_build_mod_req(&down_req, ldb, ac,
 324                                 req->op.mod.message,
 325                                 req->controls,
 326                                 ac, update_kt_op_callback,
 327                                 req);
 328         if (ret != LDB_SUCCESS) {
 329                 return ret;
 330         }
 331 
 332         return ldb_next_request(module, down_req);
 333 }
 334 
 335 /* delete */
 336 static int update_kt_delete(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 337 {
 338         struct update_kt_ctx *ac;
 339 
 340         ac = update_kt_ctx_init(module, req);
 341         if (ac == NULL) {
 342                 return LDB_ERR_OPERATIONS_ERROR;
 343         }
 344 
 345         ac->dn = req->op.del.dn;
 346         ac->do_delete = true;
 347 
 348         return ukt_search_modified(ac);
 349 }
 350 
 351 /* rename */
 352 static int update_kt_rename(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 353 {
 354         struct ldb_context *ldb;
 355         struct update_kt_ctx *ac;
 356         struct ldb_request *down_req;
 357         int ret;
 358 
 359         ldb = ldb_module_get_ctx(module);
 360 
 361         ac = update_kt_ctx_init(module, req);
 362         if (ac == NULL) {
 363                 return LDB_ERR_OPERATIONS_ERROR;
 364         }
 365 
 366         ac->dn = req->op.rename.newdn;
 367 
 368         ret = ldb_build_rename_req(&down_req, ldb, ac,
 369                                 req->op.rename.olddn,
 370                                 req->op.rename.newdn,
 371                                 req->controls,
 372                                 ac, update_kt_op_callback,
 373                                 req);
 374         if (ret != LDB_SUCCESS) {
 375                 return ret;
 376         }
 377 
 378         return ldb_next_request(module, down_req);
 379 }
 380 
 381 /* end a transaction */
 382 static int update_kt_end_trans(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 383 {
 384         struct ldb_context *ldb;
 385         struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
 386         struct dn_list *p;
 387 
 388         ldb = ldb_module_get_ctx(module);
 389 
 390         for (p=data->changed_dns; p; p = p->next) {
 391                 int kret;
 392                 kret = cli_credentials_update_keytab(p->creds, ldb_get_event_context(ldb), ldb_get_opaque(ldb, "loadparm"));
 393                 if (kret != 0) {
 394                         talloc_free(data->changed_dns);
 395                         data->changed_dns = NULL;
 396                         ldb_asprintf_errstring(ldb, "Failed to update keytab: %s", error_message(kret));
 397                         return LDB_ERR_OPERATIONS_ERROR;
 398                 }
 399         }
 400 
 401         talloc_free(data->changed_dns);
 402         data->changed_dns = NULL;
 403 
 404         return ldb_next_end_trans(module);
 405 }
 406 
 407 /* end a transaction */
 408 static int update_kt_del_trans(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 409 {
 410         struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
 411 
 412         talloc_free(data->changed_dns);
 413         data->changed_dns = NULL;
 414 
 415         return ldb_next_del_trans(module);
 416 }
 417 
 418 static int update_kt_init(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 419 {
 420         struct ldb_context *ldb;
 421         struct update_kt_private *data;
 422 
 423         ldb = ldb_module_get_ctx(module);
 424 
 425         data = talloc(module, struct update_kt_private);
 426         if (data == NULL) {
 427                 ldb_oom(ldb);
 428                 return LDB_ERR_OPERATIONS_ERROR;
 429         }
 430 
 431         data->changed_dns = NULL;
 432 
 433         ldb_module_set_private(module, data);
 434 
 435         return ldb_next_init(module);
 436 }
 437 
 438 _PUBLIC_ const struct ldb_module_ops ldb_update_keytab_module_ops = {
 439         .name              = "update_keytab",
 440         .init_context      = update_kt_init,
 441         .add               = update_kt_add,
 442         .modify            = update_kt_modify,
 443         .rename            = update_kt_rename,
 444         .del               = update_kt_delete,
 445         .end_transaction   = update_kt_end_trans,
 446         .del_transaction   = update_kt_del_trans,
 447 };

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