1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-26 21:57:41 +03:00

s3:pdb_samba_dsdb: implement pdb_samba_dsdb_set_trusteddom_pw()

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>
This commit is contained in:
Stefan Metzmacher 2015-02-05 09:26:23 +00:00 committed by Günther Deschner
parent e0a4f438d1
commit 7391416399

View File

@ -2569,7 +2569,284 @@ static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m,
const char* domain, const char* pwd,
const struct dom_sid *sid)
{
return false;
struct pdb_samba_dsdb_state *state = talloc_get_type_abort(
m->private_data, struct pdb_samba_dsdb_state);
TALLOC_CTX *tmp_ctx = talloc_stackframe();
const char * const attrs[] = {
"trustAuthOutgoing",
"trustDirection",
"trustType",
NULL
};
struct ldb_message *msg = NULL;
int trust_direction_flags;
int trust_type;
int i;
const struct ldb_val *old_val = NULL;
struct trustAuthInOutBlob old_blob = {};
uint32_t old_version = 0;
uint32_t new_version = 0;
DATA_BLOB new_utf16 = {};
struct trustAuthInOutBlob new_blob = {};
struct ldb_val new_val = {};
struct timeval tv = timeval_current();
NTTIME now = timeval_to_nttime(&tv);
enum ndr_err_code ndr_err;
NTSTATUS status;
bool ok;
int ret;
ret = ldb_transaction_start(state->ldb);
if (ret != LDB_SUCCESS) {
DEBUG(2, ("Failed to start transaction.\n"));
TALLOC_FREE(tmp_ctx);
return false;
}
ok = samdb_is_pdc(state->ldb);
if (!ok) {
DEBUG(2, ("Password changes for domain %s are only allowed on a PDC.\n",
domain));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
status = sam_get_results_trust(state->ldb, tmp_ctx, domain,
NULL, attrs, &msg);
if (!NT_STATUS_IS_OK(status)) {
/*
* This can be called to work out of a domain is
* trusted, rather than just to get the password
*/
DEBUG(2, ("Failed to get trusted domain password for %s. "
"It may not be a trusted domain.\n", domain));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) {
DEBUG(2, ("Trusted domain %s is is not an outbound trust, can't set a password.\n",
domain));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
trust_type = ldb_msg_find_attr_as_int(msg, "trustType", 0);
switch (trust_type) {
case LSA_TRUST_TYPE_DOWNLEVEL:
case LSA_TRUST_TYPE_UPLEVEL:
break;
default:
DEBUG(0, ("Trusted domain %s is of type 0x%X - "
"password changes are not supported\n",
domain, (unsigned)trust_type));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
old_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
if (old_val != NULL) {
ndr_err = ndr_pull_struct_blob(old_val, tmp_ctx, &old_blob,
(ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
DEBUG(0, ("Failed to get trusted domain password for %s, "
"attribute trustAuthOutgoing coult not be parsed %s.\n",
domain,
ndr_map_error2string(ndr_err)));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
}
for (i=0; i < old_blob.current.count; i++) {
struct AuthenticationInformation *a =
&old_blob.current.array[i];
switch (a->AuthType) {
case TRUST_AUTH_TYPE_NONE:
break;
case TRUST_AUTH_TYPE_VERSION:
old_version = a->AuthInfo.version.version;
break;
case TRUST_AUTH_TYPE_CLEAR:
break;
case TRUST_AUTH_TYPE_NT4OWF:
break;
}
}
new_version = old_version + 1;
ok = convert_string_talloc(tmp_ctx,
CH_UNIX, CH_UTF16,
pwd, strlen(pwd),
(void *)&new_utf16.data,
&new_utf16.length);
if (!ok) {
DEBUG(0, ("Failed to generate new_utf16 password for domain %s\n",
domain));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
if (new_utf16.length < 28) {
DEBUG(0, ("new_utf16[%zu] version[%u] for domain %s to short.\n",
new_utf16.length,
(unsigned)new_version,
domain));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
if (new_utf16.length > 498) {
DEBUG(0, ("new_utf16[%zu] version[%u] for domain %s to long.\n",
new_utf16.length,
(unsigned)new_version,
domain));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
new_blob.count = MAX(old_blob.current.count, 2);
new_blob.current.array = talloc_zero_array(tmp_ctx,
struct AuthenticationInformation,
new_blob.count);
if (new_blob.current.array == NULL) {
DEBUG(0, ("talloc_zero_array(%u) failed\n",
(unsigned)new_blob.count));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
new_blob.previous.array = talloc_zero_array(tmp_ctx,
struct AuthenticationInformation,
new_blob.count);
if (new_blob.current.array == NULL) {
DEBUG(0, ("talloc_zero_array(%u) failed\n",
(unsigned)new_blob.count));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
for (i = 0; i < old_blob.current.count; i++) {
struct AuthenticationInformation *o =
&old_blob.current.array[i];
struct AuthenticationInformation *p =
&new_blob.previous.array[i];
*p = *o;
new_blob.previous.count++;
}
for (; i < new_blob.count; i++) {
struct AuthenticationInformation *pi =
&new_blob.previous.array[i];
if (i == 0) {
/*
* new_blob.previous is still empty so
* we'll do new_blob.previous = new_blob.current
* below.
*/
break;
}
pi->LastUpdateTime = now;
pi->AuthType = TRUST_AUTH_TYPE_NONE;
new_blob.previous.count++;
}
for (i = 0; i < new_blob.count; i++) {
struct AuthenticationInformation *ci =
&new_blob.current.array[i];
ci->LastUpdateTime = now;
switch (i) {
case 0:
ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
ci->AuthInfo.clear.size = new_utf16.length;
ci->AuthInfo.clear.password = new_utf16.data;
break;
case 1:
ci->AuthType = TRUST_AUTH_TYPE_VERSION;
ci->AuthInfo.version.version = new_version;
break;
default:
ci->AuthType = TRUST_AUTH_TYPE_NONE;
break;
}
new_blob.current.count++;
}
if (new_blob.previous.count == 0) {
TALLOC_FREE(new_blob.previous.array);
new_blob.previous = new_blob.current;
}
ndr_err = ndr_push_struct_blob(&new_val, tmp_ctx, &new_blob,
(ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
DEBUG(0, ("Failed to generate trustAuthOutgoing for "
"trusted domain password for %s: %s.\n",
domain, ndr_map_error2string(ndr_err)));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
msg->num_elements = 0;
ret = ldb_msg_add_empty(msg, "trustAuthOutgoing",
LDB_FLAG_MOD_REPLACE, NULL);
if (ret != LDB_SUCCESS) {
DEBUG(0, ("ldb_msg_add_empty() failed\n"));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
ret = ldb_msg_add_value(msg, "trustAuthOutgoing",
&new_val, NULL);
if (ret != LDB_SUCCESS) {
DEBUG(0, ("ldb_msg_add_value() failed\n"));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
ret = ldb_modify(state->ldb, msg);
if (ret != LDB_SUCCESS) {
DEBUG(0, ("Failed to replace trustAuthOutgoing for "
"trusted domain password for %s: %s - %s\n",
domain, ldb_strerror(ret), ldb_errstring(state->ldb)));
TALLOC_FREE(tmp_ctx);
ldb_transaction_cancel(state->ldb);
return false;
}
ret = ldb_transaction_commit(state->ldb);
if (ret != LDB_SUCCESS) {
DEBUG(0, ("Failed to commit trustAuthOutgoing for "
"trusted domain password for %s: %s - %s\n",
domain, ldb_strerror(ret), ldb_errstring(state->ldb)));
TALLOC_FREE(tmp_ctx);
return false;
}
DEBUG(1, ("Added new_version[%u] to trustAuthOutgoing for "
"trusted domain password for %s.\n",
(unsigned)new_version, domain));
TALLOC_FREE(tmp_ctx);
return true;
}
static bool pdb_samba_dsdb_del_trusteddom_pw(struct pdb_methods *m,