s4:provision Use code to store domain join in 'net join' as well
authorAndrew Bartlett <abartlet@samba.org>
Sun, 20 Sep 2009 23:27:24 +0000 (16:27 -0700)
committerAndrew Bartlett <abartlet@samba.org>
Sun, 20 Sep 2009 23:29:38 +0000 (16:29 -0700)
This ensures we only have one codepath to store the secret, and
therefore that we have a single choke point for setting the
saltPrincipal, which we were previously skipping.

Andrew Bartlett

source4/libnet/libnet_join.c
source4/libnet/libnet_vampire.c
source4/librpc/ndr/py_security.c
source4/param/config.mk
source4/param/provision.c
source4/param/provision.h
source4/scripting/python/samba/provision.py

index 86ad685c5161479b820e227629f06f58fb795eaa..fc7de10506bc8258416521d6903c1e5d307aa02d 100644 (file)
@@ -33,6 +33,7 @@
 #include "auth/credentials/credentials_krb5.h"
 #include "librpc/gen_ndr/ndr_samr_c.h"
 #include "param/param.h"
+#include "param/provision.h"
 
 /*
  * complete a domain join, when joining to a AD domain:
@@ -860,254 +861,6 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
        return status;
 }
 
-NTSTATUS libnet_set_join_secrets(struct libnet_context *ctx, 
-                                TALLOC_CTX *mem_ctx, 
-                                struct libnet_set_join_secrets *r)
-{
-       TALLOC_CTX *tmp_mem;
-       int ret, rtn;
-       struct ldb_context *ldb;
-       struct ldb_dn *base_dn;
-       struct ldb_message **msgs, *msg;
-       const char *sct;
-       const char * const attrs[] = {
-               "whenChanged",
-               "secret",
-               "priorSecret",
-               "priorChanged",
-               "krb5Keytab",
-               "privateKeytab",
-               NULL
-       };
-
-       tmp_mem = talloc_new(mem_ctx);
-       if (!tmp_mem) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       /* Open the secrets database */
-       ldb = secrets_db_connect(tmp_mem, ctx->event_ctx, ctx->lp_ctx);
-       if (!ldb) {
-               r->out.error_string
-                       = talloc_asprintf(mem_ctx, 
-                                         "Could not open secrets database");
-               talloc_free(tmp_mem);
-               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-       }
-
-       /*
-        * now prepare the record for secrets.ldb
-        */
-       sct = talloc_asprintf(tmp_mem, "%d", r->in.join_type); 
-       if (!sct) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-       
-       msg = ldb_msg_new(tmp_mem);
-       if (!msg) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       base_dn = ldb_dn_new(tmp_mem, ldb, "cn=Primary Domains");
-       if (!base_dn) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       msg->dn = ldb_dn_copy(tmp_mem, base_dn);
-       if ( ! ldb_dn_add_child_fmt(msg->dn, "flatname=%s", r->in.domain_name)) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-       
-       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "flatname", r->in.domain_name);
-       if (rtn == -1) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       if (r->in.realm) {
-               rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "realm", r->in.realm);
-               if (rtn == -1) {
-                       r->out.error_string = NULL;
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_NO_MEMORY;
-               }
-       }
-
-       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "objectClass", "primaryDomain");
-       if (rtn == -1) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "objectClass", "kerberosSecret");
-       if (rtn == -1) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "secret", r->in.join_password);
-       if (rtn == -1) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "samAccountName", r->in.account_name);
-       if (rtn == -1) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "secureChannelType", sct);
-       if (rtn == -1) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       if (r->in.kvno) {
-               rtn = samdb_msg_add_uint(ldb, tmp_mem, msg, "msDS-KeyVersionNumber",
-                                        r->in.kvno);
-               if (rtn == -1) {
-                       r->out.error_string = NULL;
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_NO_MEMORY;
-               }
-       }
-
-       if (r->in.domain_sid) {
-               rtn = samdb_msg_add_dom_sid(ldb, tmp_mem, msg, "objectSid",
-                                           r->in.domain_sid);
-               if (rtn == -1) {
-                       r->out.error_string = NULL;
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_NO_MEMORY;
-               }
-       }
-
-       /* 
-        * search for the secret record
-        * - remove the records we find
-        * - and fetch the old secret and store it under priorSecret
-        */
-       ret = gendb_search(ldb,
-                          tmp_mem, base_dn,
-                          &msgs, attrs,
-                          "(|" SECRETS_PRIMARY_DOMAIN_FILTER "(realm=%s))",
-                          r->in.domain_name, r->in.realm);
-       if (ret == 0) {
-               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "privateKeytab", "secrets.keytab");
-               if (rtn == -1) {
-                       r->out.error_string = NULL;
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_NO_MEMORY;
-               }
-       } else if (ret == -1) {
-               r->out.error_string
-                       = talloc_asprintf(mem_ctx, 
-                                         "Search for domain: %s and realm: %s failed: %s", 
-                                         r->in.domain_name, r->in.realm, ldb_errstring(ldb));
-               talloc_free(tmp_mem);
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       } else {
-               const struct ldb_val *private_keytab;
-               const struct ldb_val *krb5_main_keytab;
-               const struct ldb_val *prior_secret;
-               const struct ldb_val *prior_modified_time;
-               int i;
-
-               for (i = 0; i < ret; i++) {
-                       ldb_delete(ldb, msgs[i]->dn);
-               }
-
-               prior_secret = ldb_msg_find_ldb_val(msgs[0], "secret");
-               if (prior_secret) {
-                       rtn = samdb_msg_set_value(ldb, tmp_mem, msg, "priorSecret", prior_secret);
-                       if (rtn == -1) {
-                               r->out.error_string = NULL;
-                               talloc_free(tmp_mem);
-                               return NT_STATUS_NO_MEMORY;
-                       }
-               }
-               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "secret", r->in.join_password);
-               if (rtn == -1) {
-                       r->out.error_string = NULL;
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_NO_MEMORY;
-               }
-
-               prior_modified_time = ldb_msg_find_ldb_val(msgs[0], 
-                                                          "whenChanged");
-               if (prior_modified_time) {
-                       rtn = samdb_msg_set_value(ldb, tmp_mem, msg, "priorWhenChanged", 
-                                                 prior_modified_time);
-                       if (rtn == -1) {
-                               r->out.error_string = NULL;
-                               talloc_free(tmp_mem);
-                               return NT_STATUS_NO_MEMORY;
-                       }
-               }
-
-               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "samAccountName", r->in.account_name);
-               if (rtn == -1) {
-                       r->out.error_string = NULL;
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_NO_MEMORY;
-               }
-
-               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "secureChannelType", sct);
-               if (rtn == -1) {
-                       r->out.error_string = NULL;
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_NO_MEMORY;
-               }
-
-               /* We will want to keep the keytab names */
-               private_keytab = ldb_msg_find_ldb_val(msgs[0], "privateKeytab");
-               if (private_keytab) {
-                       rtn = samdb_msg_set_value(ldb, tmp_mem, msg, "privateKeytab", private_keytab);
-                       if (rtn == -1) {
-                               r->out.error_string = NULL;
-                               talloc_free(tmp_mem);
-                               return NT_STATUS_NO_MEMORY;
-                       }
-               }
-               krb5_main_keytab = ldb_msg_find_ldb_val(msgs[0], "krb5Keytab");
-               if (krb5_main_keytab) {
-                       rtn = samdb_msg_set_value(ldb, tmp_mem, msg,
-                                       "krb5Keytab", krb5_main_keytab);
-                       if (rtn == -1) {
-                               r->out.error_string = NULL;
-                               talloc_free(tmp_mem);
-                               return NT_STATUS_NO_MEMORY;
-                       }
-               }
-       }
-
-       /* create the secret */
-       ret = ldb_add(ldb, msg);
-       if (ret != 0) {
-               r->out.error_string = talloc_asprintf(mem_ctx, "Failed to create secret record %s", 
-                                                     ldb_dn_get_linearized(msg->dn));
-               talloc_free(tmp_mem);
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       return NT_STATUS_OK;
-}
-
 static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx, 
                                           TALLOC_CTX *mem_ctx, 
                                           struct libnet_Join *r)
@@ -1115,11 +868,12 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
        NTSTATUS status;
        TALLOC_CTX *tmp_mem;
        struct libnet_JoinDomain *r2;
-       struct libnet_set_join_secrets *r3;
+       struct provision_store_self_join_settings *set_secrets;
        uint32_t acct_type = 0;
        const char *account_name;
        const char *netbios_name;
-       
+       const char *error_string;
+
        r->out.error_string = NULL;
 
        tmp_mem = talloc_new(mem_ctx);
@@ -1179,26 +933,26 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                return status;
        }
 
-       r3 = talloc(tmp_mem, struct libnet_set_join_secrets);
-       if (!r3) {
+       set_secrets = talloc(tmp_mem, struct provision_store_self_join_settings);
+       if (!set_secrets) {
                r->out.error_string = NULL;
                talloc_free(tmp_mem);
                return NT_STATUS_NO_MEMORY;
        }
        
-       ZERO_STRUCTP(r3);
-       r3->in.domain_name = r2->out.domain_name;
-       r3->in.realm = r2->out.realm;
-       r3->in.account_name = account_name;
-       r3->in.netbios_name = netbios_name;
-       r3->in.join_type = r->in.join_type;
-       r3->in.join_password = r2->out.join_password;
-       r3->in.kvno = r2->out.kvno;
-       r3->in.domain_sid = r2->out.domain_sid;
+       ZERO_STRUCTP(set_secrets);
+       set_secrets->domain_name = r2->out.domain_name;
+       set_secrets->realm = r2->out.realm;
+       set_secrets->account_name = account_name;
+       set_secrets->netbios_name = netbios_name;
+       set_secrets->secure_channel_type = r->in.join_type;
+       set_secrets->machine_password = r2->out.join_password;
+       set_secrets->key_version_number = r2->out.kvno;
+       set_secrets->domain_sid = r2->out.domain_sid;
        
-       status = libnet_set_join_secrets(ctx, r3, r3);
+       status = provision_store_self_join(ctx, ctx->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
        if (!NT_STATUS_IS_OK(status)) {
-               r->out.error_string = talloc_steal(mem_ctx, r3->out.error_string);
+               r->out.error_string = talloc_steal(mem_ctx, error_string);
                talloc_free(tmp_mem);
                return status;
        }
@@ -1206,11 +960,11 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
        /* move all out parameter to the callers TALLOC_CTX */
        r->out.error_string     = NULL;
        r->out.join_password    = r2->out.join_password;
-       talloc_steal(mem_ctx, r2->out.join_password);
+       talloc_reparent(r2, mem_ctx, r2->out.join_password);
        r->out.domain_sid       = r2->out.domain_sid;
-       talloc_steal(mem_ctx, r2->out.domain_sid);
+       talloc_reparent(r2, mem_ctx, r2->out.domain_sid);
        r->out.domain_name      = r2->out.domain_name;
-       talloc_steal(mem_ctx, r2->out.domain_name);
+       talloc_reparent(r2, mem_ctx, r2->out.domain_name);
        talloc_free(tmp_mem);
        return NT_STATUS_OK;
 }
index 327a64daea3bf0932a7728b82fced206dcc88f74..19453a4d650723dffd310185f8a7741b3ed0c000 100644 (file)
@@ -595,10 +595,11 @@ NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
                        struct libnet_Vampire *r)
 {
        struct libnet_JoinDomain *join;
-       struct libnet_set_join_secrets *set_secrets;
+       struct provision_store_self_join_settings *set_secrets;
        struct libnet_BecomeDC b;
        struct vampire_state *s;
        struct ldb_message *msg;
+       const char *error_string;
        int ldb_ret;
        uint32_t i;
        NTSTATUS status;
@@ -709,40 +710,52 @@ NTSTATUS libnet_Vampire(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
                return NT_STATUS_INTERNAL_DB_ERROR;
        }
 
-       /* commit the transaction - this commits all the changes in
-          the ldb from the whole vampire.  Note that this commit
+       /* prepare the transaction - this prepares to commit all the changes in
+          the ldb from the whole vampire.  Note that this 
           triggers the writing of the linked attribute backlinks.
        */
-       if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
-               printf("Failed to commit vampire transaction\n");
+       if (ldb_transaction_prepare_commit(s->ldb) != LDB_SUCCESS) {
+               printf("Failed to prepare_commit vampire transaction\n");
                return NT_STATUS_INTERNAL_DB_ERROR;
        }
 
-       set_secrets = talloc_zero(s, struct libnet_set_join_secrets);
+       set_secrets = talloc(s, struct provision_store_self_join_settings);
        if (!set_secrets) {
+               r->out.error_string = NULL;
+               talloc_free(s);
                return NT_STATUS_NO_MEMORY;
        }
-               
-       set_secrets->in.domain_name = join->out.domain_name;
-       set_secrets->in.realm = join->out.realm;
-       set_secrets->in.account_name = account_name;
-       set_secrets->in.netbios_name = netbios_name;
-       set_secrets->in.join_type = SEC_CHAN_BDC;
-       set_secrets->in.join_password = join->out.join_password;
-       set_secrets->in.kvno = join->out.kvno;
-       set_secrets->in.domain_sid = join->out.domain_sid;
        
-       status = libnet_set_join_secrets(ctx, set_secrets, set_secrets);
+       ZERO_STRUCTP(set_secrets);
+       set_secrets->domain_name = join->out.domain_name;
+       set_secrets->realm = join->out.realm;
+       set_secrets->account_name = account_name;
+       set_secrets->netbios_name = netbios_name;
+       set_secrets->secure_channel_type = SEC_CHAN_BDC;
+       set_secrets->machine_password = join->out.join_password;
+       set_secrets->key_version_number = join->out.kvno;
+       set_secrets->domain_sid = join->out.domain_sid;
+       
+       status = provision_store_self_join(ctx, ctx->lp_ctx, ctx->event_ctx, set_secrets, &error_string);
        if (!NT_STATUS_IS_OK(status)) {
-               r->out.error_string = talloc_steal(mem_ctx, set_secrets->out.error_string);
+               r->out.error_string = talloc_steal(mem_ctx, error_string);
                talloc_free(s);
                return status;
        }
 
        r->out.domain_name = talloc_steal(r, join->out.domain_name);
        r->out.domain_sid = talloc_steal(r, join->out.domain_sid);
-       talloc_free(s);
        
+       /* commit the transaction now we know the secrets were written
+        * out properly
+       */
+       if (ldb_transaction_commit(s->ldb) != LDB_SUCCESS) {
+               printf("Failed to commit vampire transaction\n");
+               return NT_STATUS_INTERNAL_DB_ERROR;
+       }
+
+       talloc_free(s);
+
        return NT_STATUS_OK;
 
 }
index 02dc059f0587b9f735a1ef7517f9001e2cd7875f..1b185a51b53d6c8de25837884724ed3608300404 100644 (file)
 #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
 #endif
 
+PyObject *py_dom_sid_FromSid(struct dom_sid *sid)
+{
+       return py_talloc_reference(&dom_sid_Type, sid);
+}
+
 static void PyType_AddMethods(PyTypeObject *type, PyMethodDef *methods)
 {
        PyObject *dict;
index 6e5290b64d96aaf77eaa3c444fd37e3d77079a7e..45eb836bb4d7b80e897e824c940eaf97899ddda6 100644 (file)
@@ -13,7 +13,7 @@ PUBLIC_HEADERS += param/param.h
 PC_FILES += $(paramsrcdir)/samba-hostconfig.pc
 
 [SUBSYSTEM::PROVISION]
-PRIVATE_DEPENDENCIES = LIBPYTHON pyldb pyparam_util
+PRIVATE_DEPENDENCIES = LIBPYTHON pyldb pyparam_util python_dcerpc_security
 
 PROVISION_OBJ_FILES = $(paramsrcdir)/provision.o $(param_OBJ_FILES)
 
index bbc6837a90c783166fe24555261473489afc4b9f..355af794d82017c17c9af54ccc6f478892e6505d 100644 (file)
@@ -2,7 +2,8 @@
    Unix SMB/CIFS implementation.
    Samba utility functions
    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
-   
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
 #include "includes.h"
 #include "auth/auth.h"
 #include "lib/ldb_wrap.h"
+#include "ldb/include/ldb.h"
+#include "ldb_errors.h"
 #include "libcli/raw/libcliraw.h"
 #include "librpc/ndr/libndr.h"
 
 #include "param/param.h"
 #include "param/provision.h"
+#include "param/secrets.h"
 #include <Python.h>
+#include "lib/talloc/pytalloc.h"
+#include "librpc/rpc/pyrpc.h"
 #include "scripting/python/modules.h"
 #include "lib/ldb/pyldb.h"
 #include "param/pyparam.h"
+#include "librpc/ndr/py_security.h"
 
 NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
                        struct provision_settings *settings, 
@@ -144,3 +151,125 @@ NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
 
        return NT_STATUS_OK;
 }
+
+extern void initldb(void);
+extern void initsecurity(void);
+
+NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
+                                  struct tevent_context *event_ctx,
+                                  struct provision_store_self_join_settings *settings,
+                                  const char **error_string)
+{
+       int ret;
+       PyObject *provision_mod, *provision_dict, *provision_fn, *py_result, *parameters, *py_sid;
+       struct ldb_context *ldb;
+       TALLOC_CTX *tmp_mem = talloc_new(mem_ctx);
+       if (!tmp_mem) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* Open the secrets database */
+       ldb = secrets_db_connect(tmp_mem, event_ctx, lp_ctx);
+       if (!ldb) {
+               *error_string
+                       = talloc_asprintf(mem_ctx, 
+                                         "Could not open secrets database");
+               talloc_free(tmp_mem);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       ret = ldb_transaction_start(ldb);
+
+       if (ret != LDB_SUCCESS) {
+               *error_string
+                       = talloc_asprintf(mem_ctx, 
+                                         "Could not start transaction on secrets database: %s", ldb_errstring(ldb));
+               talloc_free(tmp_mem);
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+       py_load_samba_modules();
+       Py_Initialize();
+       py_update_path("bin"); /* FIXME: Can't assume this is always the case */
+       initldb();
+       initsecurity();
+       provision_mod = PyImport_Import(PyString_FromString("samba.provision"));
+
+       if (provision_mod == NULL) {
+               PyErr_Print();
+               *error_string
+                       = talloc_asprintf(mem_ctx, "Unable to import provision Python module.");
+               talloc_free(tmp_mem);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       provision_dict = PyModule_GetDict(provision_mod);
+
+       if (provision_dict == NULL) {
+               *error_string
+                       = talloc_asprintf(mem_ctx, "Unable to get dictionary for provision module");
+               talloc_free(tmp_mem);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       provision_fn = PyDict_GetItemString(provision_dict, "secretsdb_self_join");
+       if (provision_fn == NULL) {
+               PyErr_Print();
+               *error_string
+                       = talloc_asprintf(mem_ctx, "Unable to get provision_become_dc function");
+               talloc_free(tmp_mem);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       
+       parameters = PyDict_New();
+
+       PyDict_SetItemString(parameters, "secretsdb", 
+                            PyLdb_FromLdbContext(ldb));
+       PyDict_SetItemString(parameters, "domain", 
+                            PyString_FromString(settings->domain_name));
+       PyDict_SetItemString(parameters, "domain", 
+                            PyString_FromString(settings->domain_name));
+       PyDict_SetItemString(parameters, "realm", 
+                            PyString_FromString(settings->realm));
+       PyDict_SetItemString(parameters, "machinepass", 
+                            PyString_FromString(settings->machine_password));
+       PyDict_SetItemString(parameters, "netbiosname", 
+                            PyString_FromString(settings->netbios_name));
+
+       py_sid = py_dom_sid_FromSid(settings->domain_sid);
+
+       PyDict_SetItemString(parameters, "domainsid", 
+                            py_sid);
+
+       PyDict_SetItemString(parameters, "secure_channel_type", 
+                      PyInt_FromLong(settings->secure_channel_type));
+
+       PyDict_SetItemString(parameters, "key_version_number", 
+                      PyInt_FromLong(settings->key_version_number));
+
+       py_result = PyEval_CallObjectWithKeywords(provision_fn, NULL, parameters);
+
+       Py_DECREF(parameters);
+
+       if (py_result == NULL) {
+               ldb_transaction_cancel(ldb);
+               talloc_free(tmp_mem);
+
+               PyErr_Print();
+               PyErr_Clear();
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       ret = ldb_transaction_commit(ldb);
+       if (ret != LDB_SUCCESS) {
+               *error_string
+                       = talloc_asprintf(mem_ctx, 
+                                         "Could not commit transaction on secrets database: %s", ldb_errstring(ldb));
+               talloc_free(tmp_mem);
+               return NT_STATUS_INTERNAL_DB_ERROR;
+       }
+
+       talloc_free(tmp_mem);
+
+       return NT_STATUS_OK;
+}
index af9685d292f5aa9562e4eec03051dfb52f5a93a1..c3b3bb88d80a58fd2997ccb4786dfa41700e2f58 100644 (file)
@@ -44,8 +44,24 @@ struct provision_result {
         struct loadparm_context *lp_ctx;
 };
 
+struct provision_store_self_join_settings {
+       const char *domain_name;
+       const char *realm;
+       const char *netbios_name;
+       const char *account_name;
+       enum netr_SchannelType secure_channel_type;
+       const char *machine_password;
+       int key_version_number;
+       struct dom_sid *domain_sid;
+};
+
 NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
                                                struct provision_settings *settings,
                                                struct provision_result *result);
 
+NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
+                                  struct tevent_context *ev_ctx,
+                                  struct provision_store_self_join_settings *settings,
+                                  const char **error_string);
+
 #endif /* _PROVISION_H_ */
index 68a50b2e37df96580aaf21e90bdd0c3f6da0930d..8af24f21cf5912de36a0f86456d5cc962bdbad3f 100644 (file)
@@ -48,11 +48,13 @@ from samba import DS_DOMAIN_FUNCTION_2000, DS_DC_FUNCTION_2008_R2
 from samba.samdb import SamDB
 from samba.idmap import IDmapDB
 from samba.dcerpc import security
+from samba.ndr import ndr_pack
 import urllib
 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, timestring
 from ms_schema import read_ms_schema
 from ms_display_specifiers import read_ms_ldif
 from signal import SIGTERM
+from dcerpc.misc import SEC_CHAN_BDC, SEC_CHAN_WKSTA
 
 __docformat__ = "restructuredText"
 
@@ -318,7 +320,6 @@ def provision_paths_from_lp(lp, dnsdomain):
     """
     paths = ProvisionPaths()
     paths.private_dir = lp.get("private dir")
-    paths.keytab = "secrets.keytab"
     paths.dns_keytab = "dns.keytab"
 
     paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
@@ -658,12 +659,75 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
 
     samdb.transaction_commit()
     
+def secretsdb_self_join(secretsdb, domain, 
+                        netbiosname, domainsid, machinepass, 
+                        realm=None, dnsdomain=None,
+                        keytab_path=None, 
+                        key_version_number=1,
+                        secure_channel_type=SEC_CHAN_WKSTA):
+    """Add domain join-specific bits to a secrets database.
+    
+    :param secretsdb: Ldb Handle to the secrets database
+    :param machinepass: Machine password
+    """
+    attrs=["whenChanged",
+           "secret",
+           "priorSecret",
+           "priorChanged",
+           "krb5Keytab",
+           "privateKeytab"]
+    
+
+    msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain));
+    msg["secureChannelType"] = str(secure_channel_type)
+    msg["flatname"] = [domain]
+    msg["objectClass"] = ["top", "primaryDomain"]
+    if realm is not None:
+      if dnsdomain is None:
+        dnsdomain = realm.lower()
+      msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
+      msg["realm"] = realm
+      msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper())
+      msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
+      msg["privateKeytab"] = ["secrets.keytab"];
+
+
+    msg["secret"] = [machinepass]
+    msg["samAccountName"] = ["%s$" % netbiosname]
+    msg["secureChannelType"] = [str(secure_channel_type)]
+    msg["objectSid"] = [ndr_pack(domainsid)]
+    
+    res = secretsdb.search(base="cn=Primary Domains", 
+                           attrs=attrs, 
+                           expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))), 
+                           scope=SCOPE_ONELEVEL)
+    
+    for del_msg in res:
+      if del_msg.dn is not msg.dn:
+        secretsdb.delete(del_msg.dn)
+
+    res = secretsdb.search(base=msg.dn, attrs=attrs, scope=SCOPE_BASE)
+
+    if len(res) == 1:
+      msg["priorSecret"] = res[0]["secret"]
+      msg["priorWhenChanged"] = res[0]["whenChanged"]
+
+      if res["privateKeytab"] is not None:
+        msg["privateKeytab"] = res[0]["privateKeytab"]
 
+      if res["krb5Keytab"] is not None:
+        msg["krb5Keytab"] = res[0]["krb5Keytab"]
 
-def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain, 
-                        netbiosname, domainsid, keytab_path, samdb_url, 
-                        dns_keytab_path, dnspass, machinepass):
-    """Add DC-specific bits to a secrets database.
+      for el in msg:
+        el.set_flags(ldb.FLAG_MOD_REPLACE)
+        secretsdb.modify(msg)
+    else:
+      secretsdb.add(msg)
+
+
+def secretsdb_setup_dns(secretsdb, setup_path, realm, dnsdomain, 
+                        dns_keytab_path, dnspass):
+    """Add DNS specific bits to a secrets database.
     
     :param secretsdb: Ldb Handle to the secrets database
     :param setup_path: Setup path function
@@ -676,18 +740,6 @@ def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain,
             "DNSPASS_B64": b64encode(dnspass),
             })
 
-    setup_ldb(secretsdb, setup_path("secrets_self_join.ldif"), { 
-            "MACHINEPASS_B64": b64encode(machinepass),
-            "DOMAIN": domain,
-            "REALM": realm,
-            "DNSDOMAIN": dnsdomain,
-            "DOMAINSID": str(domainsid),
-            "SECRETS_KEYTAB": keytab_path,
-            "NETBIOSNAME": netbiosname,
-            "SALT_PRINCIPAL": "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper()),
-            "KEY_VERSION_NUMBER": "1"
-            })
-
 
 def setup_secretsdb(path, setup_path, session_info, credentials, lp):
     """Setup the secrets database.
@@ -707,6 +759,7 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp):
     secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
     secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
                       lp=lp)
+    secrets_ldb.transaction_start()
     secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
 
     if credentials is not None and credentials.authentication_requested():
@@ -1242,16 +1295,18 @@ def provision(setup_dir, message, session_info,
 
         # Only make a zone file on the first DC, it should be replicated with DNS replication
         if serverrole == "domain controller":
-            secrets_ldb = Ldb(paths.secrets, session_info=session_info, 
-                              credentials=credentials, lp=lp)
-            secretsdb_become_dc(secrets_ldb, setup_path, domain=domain,
+            secretsdb_self_join(secrets_ldb, domain=domain,
                                 realm=names.realm,
+                                dnsdomain=names.dnsdomain,
                                 netbiosname=names.netbiosname,
                                 domainsid=domainsid, 
-                                keytab_path=paths.keytab, samdb_url=paths.samdb,
+                                machinepass=machinepass,
+                                secure_channel_type=SEC_CHAN_BDC)
+
+            secretsdb_setup_dns(secrets_ldb, setup_path, 
+                                realm=names.realm, dnsdomain=names.dnsdomain,
                                 dns_keytab_path=paths.dns_keytab,
-                                dnspass=dnspass, machinepass=machinepass,
-                                dnsdomain=names.dnsdomain)
+                                dnspass=dnspass)
 
             domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
             assert isinstance(domainguid, str)
@@ -1276,6 +1331,8 @@ def provision(setup_dir, message, session_info,
                              realm=names.realm)
             message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
 
+    #Now commit the secrets.ldb to disk
+    secrets_ldb.transaction_commit()
 
     if provision_backend is not None: 
       if ldap_backend_type == "fedora-ds":