diff options
| -rw-r--r-- | source3/Makefile.in | 1 | ||||
| -rw-r--r-- | source3/libnet/libnet_dssync.h | 6 | ||||
| -rw-r--r-- | source3/libnet/libnet_dssync_keytab.c | 240 | ||||
| -rw-r--r-- | source3/utils/net_rpc_samsync.c | 50 | 
4 files changed, 297 insertions, 0 deletions
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 <gd@samba.org> 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 <http://www.gnu.org/licenses/>. +*/ + +#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 (; i<pwd_history_len; i++) { + +		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, &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);  }  | 
