mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
s4:provision Use code to store domain join in 'net join' as well
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
This commit is contained in:
parent
1d4a16acd7
commit
bfddb6816f
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,11 @@
|
||||
#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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
@ -20,15 +21,21 @@
|
||||
#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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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"];
|
||||
|
||||
|
||||
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.
|
||||
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"]
|
||||
|
||||
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":
|
||||
|
Loading…
Reference in New Issue
Block a user