From 9b0e3bb0c36abd9396f07de988e5c402d8503681 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Fri, 27 Jun 2008 15:36:19 +0200 Subject: net_vampire: add code to vampire to a Kerberos keytab file using DRSUAPI. Guenther (This used to be commit 0ef420c3a478a8adce7483f14b45e9995bfa5e5d) --- source3/Makefile.in | 1 + source3/libnet/libnet_dssync.h | 6 + source3/libnet/libnet_dssync_keytab.c | 240 ++++++++++++++++++++++++++++++++++ source3/utils/net_rpc_samsync.c | 50 +++++++ 4 files changed, 297 insertions(+) create mode 100644 source3/libnet/libnet_dssync_keytab.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 7651cb2af5..cbd34afb1c 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -900,6 +900,7 @@ LIBNET_OBJ = libnet/libnet_join.o \ libnet/libnet_samsync_display.o \ libnet/libnet_samsync_keytab.o \ libnet/libnet_dssync.o \ + libnet/libnet_dssync_keytab.o \ librpc/gen_ndr/ndr_libnet_join.o NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_help.o \ diff --git a/source3/libnet/libnet_dssync.h b/source3/libnet/libnet_dssync.h index 6a56566c19..c98e650fcc 100644 --- a/source3/libnet/libnet_dssync.h +++ b/source3/libnet/libnet_dssync.h @@ -39,3 +39,9 @@ struct dssync_context { char *result_message; char *error_message; }; + +NTSTATUS libnet_dssync_dump_keytab(TALLOC_CTX *mem_ctx, + struct drsuapi_DsReplicaObjectListItemEx *cur, + struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr, + bool last_query, + struct dssync_context *ctx); diff --git a/source3/libnet/libnet_dssync_keytab.c b/source3/libnet/libnet_dssync_keytab.c new file mode 100644 index 0000000000..132a58d353 --- /dev/null +++ b/source3/libnet/libnet_dssync_keytab.c @@ -0,0 +1,240 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Guenther Deschner 2008 + + 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 + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "libnet/libnet.h" + +#if defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC) + +/**************************************************************** +****************************************************************/ + +static NTSTATUS parse_object(TALLOC_CTX *mem_ctx, + struct libnet_keytab_context *ctx, + struct drsuapi_DsReplicaObjectListItemEx *cur) +{ + NTSTATUS status = NT_STATUS_OK; + uchar nt_passwd[16]; + struct libnet_keytab_entry entry; + DATA_BLOB *blob; + int i = 0; + struct drsuapi_DsReplicaAttribute *attr; + bool got_pwd = false; + + char *upn = NULL; + char *name = NULL; + uint32_t kvno = 0; + uint32_t uacc = 0; + uint32_t sam_type = 0; + + uint32_t pwd_history_len = 0; + uint8_t *pwd_history = NULL; + + ZERO_STRUCT(nt_passwd); + + for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) { + + attr = &cur->object.attribute_ctr.attributes[i]; + + if (attr->value_ctr.num_values != 1) { + continue; + } + + if (!attr->value_ctr.values[0].blob) { + continue; + } + + blob = attr->value_ctr.values[0].blob; + + switch (attr->attid) { + case DRSUAPI_ATTRIBUTE_unicodePwd: + + if (blob->length != 16) { + break; + } + + memcpy(&nt_passwd, blob->data, 16); + got_pwd = true; + + /* pick the kvno from the meta_data version, + * thanks, metze, for explaining this */ + + if (!cur->meta_data_ctr) { + break; + } + if (cur->meta_data_ctr->count != + cur->object.attribute_ctr.num_attributes) { + break; + } + kvno = cur->meta_data_ctr->meta_data[i].version; + break; + case DRSUAPI_ATTRIBUTE_ntPwdHistory: + pwd_history_len = blob->length / 16; + pwd_history = blob->data; + break; + case DRSUAPI_ATTRIBUTE_msDS_KeyVersionNumber: + kvno = IVAL(blob->data, 0); + break; + case DRSUAPI_ATTRIBUTE_userPrincipalName: + pull_string_talloc(mem_ctx, NULL, 0, &upn, + blob->data, blob->length, + STR_UNICODE); + break; + case DRSUAPI_ATTRIBUTE_sAMAccountName: + pull_string_talloc(mem_ctx, NULL, 0, &name, + blob->data, blob->length, + STR_UNICODE); + break; + case DRSUAPI_ATTRIBUTE_sAMAccountType: + sam_type = IVAL(blob->data, 0); + break; + case DRSUAPI_ATTRIBUTE_userAccountControl: + uacc = IVAL(blob->data, 0); + break; + default: + break; + } + } + + if (!got_pwd || !name) { + return NT_STATUS_OK; + } + + DEBUG(1,("#%02d: %s:%d, ", ctx->count, name, kvno)); + DEBUGADD(1,("sAMAccountType: 0x%08x, userAccountControl: 0x%08x ", + sam_type, uacc)); + if (upn) { + DEBUGADD(1,("upn: %s", upn)); + } + DEBUGADD(1,("\n")); + + entry.kvno = kvno; + entry.name = talloc_strdup(mem_ctx, name); + entry.principal = talloc_asprintf(mem_ctx, "%s@%s", + name, ctx->dns_domain_name); + entry.password = data_blob_talloc(mem_ctx, nt_passwd, 16); + NT_STATUS_HAVE_NO_MEMORY(entry.name); + NT_STATUS_HAVE_NO_MEMORY(entry.principal); + NT_STATUS_HAVE_NO_MEMORY(entry.password.data); + + ADD_TO_ARRAY(mem_ctx, struct libnet_keytab_entry, entry, + &ctx->entries, &ctx->count); + + if ((kvno < 0) && (kvno < pwd_history_len)) { + return status; + } + + /* add password history */ + + /* skip first entry */ + if (got_pwd) { + kvno--; + i = 1; + } else { + i = 0; + } + + for (; idns_domain_name); + entry.password = data_blob_talloc(mem_ctx, &pwd_history[i*16], 16); + NT_STATUS_HAVE_NO_MEMORY(entry.name); + NT_STATUS_HAVE_NO_MEMORY(entry.principal); + NT_STATUS_HAVE_NO_MEMORY(entry.password.data); + + ADD_TO_ARRAY(mem_ctx, struct libnet_keytab_entry, entry, + &ctx->entries, &ctx->count); + } + + return status; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS libnet_dssync_dump_keytab(TALLOC_CTX *mem_ctx, + struct drsuapi_DsReplicaObjectListItemEx *cur, + struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr, + bool last_query, + struct dssync_context *ctx) +{ + NTSTATUS status = NT_STATUS_OK; + krb5_error_code ret = 0; + static struct libnet_keytab_context *keytab_ctx = NULL; + + if (!keytab_ctx) { + ret = libnet_keytab_init(mem_ctx, + ctx->output_filename, + &keytab_ctx); + if (ret) { + status = krb5_to_nt_status(ret); + goto out; + } + + keytab_ctx->dns_domain_name = ctx->dns_domain_name; + } + + for (; cur; cur = cur->next_object) { + status = parse_object(mem_ctx, keytab_ctx, cur); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + } + + if (last_query) { + + ret = libnet_keytab_add(keytab_ctx); + if (ret) { + status = krb5_to_nt_status(ret); + ctx->error_message = talloc_asprintf(mem_ctx, + "Failed to add entries to keytab %s: %s", + keytab_ctx->keytab_name, error_message(ret)); + goto out; + } + + ctx->result_message = talloc_asprintf(mem_ctx, + "Vampired %d accounts to keytab %s", + keytab_ctx->count, + keytab_ctx->keytab_name); + + TALLOC_FREE(keytab_ctx); + } + + return NT_STATUS_OK; + out: + TALLOC_FREE(keytab_ctx); + + return status; +} + +#else + +NTSTATUS libnet_dssync_dump_keytab(TALLOC_CTX *mem_ctx, + struct drsuapi_DsReplicaObjectListItemEx *cur, + struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr, + bool last_query, + struct dssync_context *ctx) +{ + return NT_STATUS_NOT_SUPPORTED; +} + +#endif /* defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC) */ diff --git a/source3/utils/net_rpc_samsync.c b/source3/utils/net_rpc_samsync.c index e4aa343d06..583984405f 100644 --- a/source3/utils/net_rpc_samsync.c +++ b/source3/utils/net_rpc_samsync.c @@ -278,6 +278,48 @@ NTSTATUS rpc_vampire_keytab_internals(struct net_context *c, return status; } +NTSTATUS rpc_vampire_keytab_ds_internals(struct net_context *c, + const DOM_SID *domain_sid, + const char *domain_name, + struct cli_state *cli, + struct rpc_pipe_client *pipe_hnd, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status; + struct dssync_context *ctx = NULL; + + status = libnet_dssync_init_context(mem_ctx, + &ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (argc >= 1) { + ctx->output_filename = argv[0]; + } + + ctx->cli = pipe_hnd; + ctx->domain_name = domain_name; + ctx->processing_fn = libnet_dssync_dump_keytab; + + status = libnet_dssync(mem_ctx, ctx); + if (!NT_STATUS_IS_OK(status) && ctx->error_message) { + d_fprintf(stderr, "%s\n", ctx->error_message); + goto out; + } + + if (ctx->result_message) { + d_fprintf(stdout, "%s\n", ctx->result_message); + } + + out: + TALLOC_FREE(ctx); + + return status; +} + /** * Basic function for 'net rpc vampire keytab' * @@ -289,6 +331,8 @@ NTSTATUS rpc_vampire_keytab_internals(struct net_context *c, int rpc_vampire_keytab(struct net_context *c, int argc, const char **argv) { + int ret = 0; + if (c->display_usage) { d_printf("Usage\n" "net rpc vampire keytab\n" @@ -296,6 +340,12 @@ int rpc_vampire_keytab(struct net_context *c, int argc, const char **argv) return 0; } + ret = run_rpc_command(c, NULL, PI_DRSUAPI, NET_FLAGS_SEAL, + rpc_vampire_keytab_ds_internals, argc, argv); + if (ret == 0) { + return 0; + } + return run_rpc_command(c, NULL, PI_NETLOGON, 0, rpc_vampire_keytab_internals, argc, argv); } -- cgit