[SCM] Samba Shared Repository - branch v3-3-test updated - release-3-2-0pre2-2975-gee6e422

Günther Deschner gd at samba.org
Tue Jun 24 21:42:00 GMT 2008


The branch, v3-3-test has been updated
       via  ee6e422c0e035aa4779fa718bb6f142827cc2de0 (commit)
      from  e884304206b512a1ffc70b7a4da8db3c6dfd4f11 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-3-test


- Log -----------------------------------------------------------------
commit ee6e422c0e035aa4779fa718bb6f142827cc2de0
Author: Günther Deschner <gd at samba.org>
Date:   Wed Jun 18 12:52:00 2008 +0200

    net_vampire: add code to vampire a SAM database to a keytab file.
    
    Guenther

-----------------------------------------------------------------------

Summary of changes:
 source/Makefile.in                    |    1 +
 source/libnet/libnet_samsync.c        |    3 +
 source/libnet/libnet_samsync.h        |    8 +-
 source/libnet/libnet_samsync_keytab.c |  319 +++++++++++++++++++++++++++++++++
 source/utils/net_proto.h              |    9 +
 source/utils/net_rpc.c                |    9 +
 source/utils/net_rpc_samsync.c        |   77 ++++++++-
 7 files changed, 423 insertions(+), 3 deletions(-)
 create mode 100644 source/libnet/libnet_samsync_keytab.c


Changeset truncated at 500 lines:

diff --git a/source/Makefile.in b/source/Makefile.in
index 67d4ed1..4f680cc 100644
--- a/source/Makefile.in
+++ b/source/Makefile.in
@@ -896,6 +896,7 @@ LIBNET_OBJ = libnet/libnet_join.o \
 	     libnet/libnet_samsync_ldif.o \
 	     libnet/libnet_samsync_passdb.o \
 	     libnet/libnet_samsync_display.o \
+	     libnet/libnet_samsync_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/source/libnet/libnet_samsync.c b/source/libnet/libnet_samsync.c
index e170acc..dcf5f9c 100644
--- a/source/libnet/libnet_samsync.c
+++ b/source/libnet/libnet_samsync.c
@@ -254,6 +254,9 @@ static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
 		case NET_SAMSYNC_MODE_FETCH_LDIF:
 			action = "Fetching (to ldif)";
 			break;
+		case NET_SAMSYNC_MODE_FETCH_KEYTAB:
+			action = "Fetching (to keytab)";
+			break;
 		default:
 			action = "Unknown";
 			break;
diff --git a/source/libnet/libnet_samsync.h b/source/libnet/libnet_samsync.h
index de0225c..8559043 100644
--- a/source/libnet/libnet_samsync.h
+++ b/source/libnet/libnet_samsync.h
@@ -21,7 +21,8 @@
 enum net_samsync_mode {
 	NET_SAMSYNC_MODE_FETCH_PASSDB = 0,
 	NET_SAMSYNC_MODE_FETCH_LDIF = 1,
-	NET_SAMSYNC_MODE_DUMP = 2
+	NET_SAMSYNC_MODE_FETCH_KEYTAB = 2,
+	NET_SAMSYNC_MODE_DUMP = 3
 };
 
 struct samsync_context;
@@ -65,3 +66,8 @@ NTSTATUS display_sam_entries(TALLOC_CTX *mem_ctx,
 			     struct netr_DELTA_ENUM_ARRAY *r,
 			     NTSTATUS status,
 			     struct samsync_context *ctx);
+NTSTATUS fetch_sam_entries_keytab(TALLOC_CTX *mem_ctx,
+				  enum netr_SamDatabaseID database_id,
+				  struct netr_DELTA_ENUM_ARRAY *r,
+				  NTSTATUS status,
+				  struct samsync_context *ctx);
diff --git a/source/libnet/libnet_samsync_keytab.c b/source/libnet/libnet_samsync_keytab.c
new file mode 100644
index 0000000..2208a71
--- /dev/null
+++ b/source/libnet/libnet_samsync_keytab.c
@@ -0,0 +1,319 @@
+/*
+   Unix SMB/CIFS implementation.
+   dump the remote SAM using rpc samsync operations
+
+   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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+#if defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC)
+
+/****************************************************************
+****************************************************************/
+
+struct samsync_keytab_entry {
+	const char *name;
+	const char *principal;
+	DATA_BLOB password;
+	uint32_t kvno;
+};
+
+struct samsync_keytab_context {
+	krb5_context context;
+	krb5_keytab keytab;
+	const char *keytab_name;
+	ADS_STRUCT *ads;
+	const char *dns_domain_name;
+	uint8_t zero_buf[16];
+	uint32_t count;
+	struct samsync_keytab_entry *entries;
+};
+
+/****************************************************************
+****************************************************************/
+
+static int keytab_close(struct samsync_keytab_context *ctx)
+{
+	if (!ctx) {
+		return 0;
+	}
+
+	if (ctx->keytab && ctx->context) {
+		krb5_kt_close(ctx->context, ctx->keytab);
+	}
+
+	if (ctx->context) {
+		krb5_free_context(ctx->context);
+	}
+
+	if (ctx->ads) {
+		ads_destroy(&ctx->ads);
+	}
+
+	TALLOC_FREE(ctx);
+
+	return 0;
+}
+
+/****************************************************************
+****************************************************************/
+
+static krb5_error_code keytab_init(TALLOC_CTX *mem_ctx,
+				   const char *keytab_name,
+				   struct samsync_keytab_context **ctx)
+{
+	krb5_error_code ret = 0;
+	krb5_context context = NULL;
+	krb5_keytab keytab = NULL;
+	const char *keytab_string = NULL;
+
+	struct samsync_keytab_context *r;
+
+	r = TALLOC_ZERO_P(mem_ctx, struct samsync_keytab_context);
+	if (!r) {
+		return ENOMEM;
+	}
+
+	talloc_set_destructor(r, keytab_close);
+
+	initialize_krb5_error_table();
+	ret = krb5_init_context(&context);
+	if (ret) {
+		DEBUG(1,("keytab_init: could not krb5_init_context: %s\n",
+			error_message(ret)));
+		return ret;
+	}
+
+	ret = smb_krb5_open_keytab(context, keytab_name, true, &keytab);
+	if (ret) {
+		DEBUG(1,("keytab_init: smb_krb5_open_keytab failed (%s)\n",
+			error_message(ret)));
+		krb5_free_context(context);
+		return ret;
+	}
+
+	ret = smb_krb5_keytab_name(mem_ctx, context, keytab, &keytab_string);
+	if (ret) {
+		krb5_kt_close(context, keytab);
+		krb5_free_context(context);
+		return ret;
+	}
+
+	r->context = context;
+	r->keytab = keytab;
+	r->keytab_name = keytab_string;
+
+	*ctx = r;
+
+	return 0;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS keytab_ad_connect(TALLOC_CTX *mem_ctx,
+				  const char *domain_name,
+				  const char *username,
+				  const char *password,
+				  struct samsync_keytab_context *ctx)
+{
+	NTSTATUS status;
+	ADS_STATUS ad_status;
+	ADS_STRUCT *ads;
+	struct netr_DsRGetDCNameInfo *info = NULL;
+	const char *dc;
+
+	status = dsgetdcname(mem_ctx, NULL, domain_name, NULL, NULL, 0, &info);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	dc = strip_hostname(info->dc_unc);
+
+	ads = ads_init(NULL, domain_name, dc);
+	NT_STATUS_HAVE_NO_MEMORY(ads);
+
+	if (getenv(KRB5_ENV_CCNAME) == NULL) {
+		setenv(KRB5_ENV_CCNAME, "MEMORY:libnet_samsync_keytab", 1);
+	}
+
+	ads->auth.user_name = SMB_STRDUP(username);
+	ads->auth.password = SMB_STRDUP(password);
+
+	ad_status = ads_connect_user_creds(ads);
+	if (!ADS_ERR_OK(ad_status)) {
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+
+	ctx->ads = ads;
+
+	ctx->dns_domain_name = talloc_strdup_upper(mem_ctx, ads->config.realm);
+	NT_STATUS_HAVE_NO_MEMORY(ctx->dns_domain_name);
+
+	return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static krb5_error_code keytab_add(struct samsync_keytab_context *ctx)
+{
+	krb5_error_code ret = 0;
+	krb5_enctype enctypes[2] = { ENCTYPE_ARCFOUR_HMAC, 0 };
+	int i;
+
+	for (i=0; i<ctx->count; i++) {
+
+		struct samsync_keytab_entry *entry = &ctx->entries[i];
+		krb5_data password;
+		krb5_kvno kvno;
+
+		kvno = ads_get_kvno(ctx->ads, entry->name);
+
+		password.data = (char *)entry->password.data;
+		password.length = entry->password.length;
+
+		ret = smb_krb5_kt_add_entry(ctx->context,
+					    ctx->keytab,
+					    kvno,
+					    entry->principal,
+					    enctypes,
+					    password,
+					    true);
+		if (ret) {
+			DEBUG(1,("keytab_add: Failed to add entry to keytab file\n"));
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS fetch_sam_entry_keytab(TALLOC_CTX *mem_ctx,
+				       enum netr_SamDatabaseID database_id,
+				       uint32_t rid,
+				       struct netr_DELTA_USER *r,
+				       NTSTATUS status,
+				       struct samsync_keytab_context *ctx)
+{
+	uchar nt_passwd[16];
+	struct samsync_keytab_entry *entry;
+
+	if (memcmp(r->ntpassword.hash, ctx->zero_buf, 16) == 0) {
+		return NT_STATUS_OK;
+	}
+
+	entry = TALLOC_ZERO_P(mem_ctx, struct samsync_keytab_entry);
+	NT_STATUS_HAVE_NO_MEMORY(entry);
+
+	sam_pwd_hash(rid, r->ntpassword.hash, nt_passwd, 0);
+
+	entry->name = talloc_strdup(mem_ctx, r->account_name.string);
+	entry->principal = talloc_asprintf(mem_ctx, "%s@%s",
+					   r->account_name.string,
+					   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);
+
+	ADD_TO_ARRAY(mem_ctx, struct samsync_keytab_entry, *entry,
+		     &ctx->entries, &ctx->count);
+
+	return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS fetch_sam_entries_keytab(TALLOC_CTX *mem_ctx,
+				  enum netr_SamDatabaseID database_id,
+				  struct netr_DELTA_ENUM_ARRAY *r,
+				  NTSTATUS result,
+				  struct samsync_context *ctx)
+{
+	NTSTATUS status = NT_STATUS_OK;
+	krb5_error_code ret = 0;
+	struct samsync_keytab_context *keytab_ctx = NULL;
+	int i;
+
+	ret = keytab_init(mem_ctx, ctx->output_filename, &keytab_ctx);
+	if (ret) {
+		status = krb5_to_nt_status(ret);
+		goto out;
+	}
+
+	status = keytab_ad_connect(mem_ctx,
+				   ctx->domain_name,
+				   ctx->username,
+				   ctx->password,
+				   keytab_ctx);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto out;
+	}
+
+	for (i = 0; i < r->num_deltas; i++) {
+
+		if (r->delta_enum[i].delta_type != NETR_DELTA_USER) {
+			continue;
+		}
+
+		status = fetch_sam_entry_keytab(mem_ctx, database_id,
+						r->delta_enum[i].delta_id_union.rid,
+						r->delta_enum[i].delta_union.user,
+						result,
+						keytab_ctx);
+		if (!NT_STATUS_IS_OK(status)) {
+			goto out;
+		}
+	}
+
+	ret = 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);
+ out:
+	TALLOC_FREE(keytab_ctx);
+
+	return status;
+}
+
+#else
+
+NTSTATUS fetch_sam_entries_keytab(TALLOC_CTX *mem_ctx,
+				  enum netr_SamDatabaseID database_id,
+				  struct netr_DELTA_ENUM_ARRAY *r,
+				  NTSTATUS result,
+				  struct samsync_context *ctx)
+{
+	return NT_STATUS_NOT_SUPPORTED;
+}
+
+#endif /* defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC) */
diff --git a/source/utils/net_proto.h b/source/utils/net_proto.h
index a370d3d..10b1e47 100644
--- a/source/utils/net_proto.h
+++ b/source/utils/net_proto.h
@@ -368,6 +368,15 @@ NTSTATUS rpc_vampire_ldif_internals(struct net_context *c,
 				    TALLOC_CTX *mem_ctx,
 				    int argc,
 				    const char **argv);
+NTSTATUS rpc_vampire_keytab_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);
+int rpc_vampire_keytab(struct net_context *c, int argc, const char **argv);
 
 /* The following definitions come from utils/net_rpc_service.c  */
 
diff --git a/source/utils/net_rpc.c b/source/utils/net_rpc.c
index 6a7c638..19566bd 100644
--- a/source/utils/net_rpc.c
+++ b/source/utils/net_rpc.c
@@ -6818,6 +6818,15 @@ static int rpc_vampire(struct net_context *c, int argc, const char **argv)
 			"net rpc vampire ldif\n"
 			"    Dump remote SAM database to LDIF file or stdout"
 		},
+		{
+			"keytab",
+			rpc_vampire_keytab,
+			NET_TRANSPORT_RPC,
+			"Dump remote SAM database to Kerberos Keytab",
+			"net rpc vampire keytab\n"
+			"    Dump remote SAM database to Kerberos keytab file"
+		},
+
 		{NULL, NULL, 0, NULL, NULL}
 	};
 
diff --git a/source/utils/net_rpc_samsync.c b/source/utils/net_rpc_samsync.c
index c941338..e4aa343 100644
--- a/source/utils/net_rpc_samsync.c
+++ b/source/utils/net_rpc_samsync.c
@@ -73,11 +73,13 @@ NTSTATUS rpc_samdump_internals(struct net_context *c,
 
 int rpc_vampire_usage(struct net_context *c, int argc, const char **argv)
 {
-	d_printf("net rpc vampire [ldif [<ldif-filename>] [options]\n"
+	d_printf("net rpc vampire ([ldif [<ldif-filename>] | [keytab] [<keytab-filename]) [options]\n"
 		 "\t to pull accounts from a remote PDC where we are a BDC\n"
 		 "\t\t no args puts accounts in local passdb from smb.conf\n"
 		 "\t\t ldif - put accounts in ldif format (file defaults to "
-		 "/tmp/tmp.ldif\n");
+		 "/tmp/tmp.ldif)\n"
+		 "\t\t keytab - put account passwords in krb5 keytab (defaults "
+		 "to system keytab)\n");
 
 	net_common_flags_usage(c, argc, argv);
 	return -1;
@@ -226,3 +228,74 @@ int rpc_vampire_ldif(struct net_context *c, int argc, const char **argv)
 	return run_rpc_command(c, NULL, PI_NETLOGON, 0, rpc_vampire_ldif_internals,
 			       argc, argv);
 }
+
+
+NTSTATUS rpc_vampire_keytab_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 samsync_context *ctx = NULL;
+
+	status = libnet_samsync_init_context(mem_ctx,
+					     domain_sid,
+					     &ctx);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	if (argc >= 1) {
+		ctx->output_filename = argv[0];
+	}
+
+	ctx->mode		= NET_SAMSYNC_MODE_FETCH_KEYTAB;
+	ctx->cli		= pipe_hnd;
+	ctx->delta_fn		= fetch_sam_entries_keytab;
+	ctx->domain_name	= domain_name;
+	ctx->username		= c->opt_user_name;
+	ctx->password		= c->opt_password;
+
+	/* fetch domain */
+	status = libnet_samsync(SAM_DATABASE_DOMAIN, 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'
+ *
+ * @param c	A net_context structure
+ * @param argc  Standard main() style argc
+ * @param argc  Standard main() style argv.  Initial components are already
+ *              stripped
+ **/
+
+int rpc_vampire_keytab(struct net_context *c, int argc, const char **argv)
+{
+	if (c->display_usage) {


-- 
Samba Shared Repository


More information about the samba-cvs mailing list