net_vampire: add code to vampire a SAM database to a keytab file.
authorGünther Deschner <gd@samba.org>
Wed, 18 Jun 2008 10:52:00 +0000 (12:52 +0200)
committerGünther Deschner <gd@samba.org>
Tue, 24 Jun 2008 21:40:14 +0000 (23:40 +0200)
Guenther
(This used to be commit ee6e422c0e035aa4779fa718bb6f142827cc2de0)

source3/Makefile.in
source3/libnet/libnet_samsync.c
source3/libnet/libnet_samsync.h
source3/libnet/libnet_samsync_keytab.c [new file with mode: 0644]
source3/utils/net_proto.h
source3/utils/net_rpc.c
source3/utils/net_rpc_samsync.c

index 67d4ed1ac6e5f7525d07e93f33fd5bb7887b320f..4f680cc56fc9c4f83d0996d5c14e6e94701308af 100644 (file)
@@ -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 \
index e170acc56000495364e134eb5aae418067b8fd75..dcf5f9c39ffe1a576e0feaf4f3a910dd06ca882e 100644 (file)
@@ -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;
index de0225c6fc5cf259f0ce90eeb2af0b43ac217680..8559043f5ac86ba9cbbedd0ed36aea9583af0e13 100644 (file)
@@ -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/source3/libnet/libnet_samsync_keytab.c b/source3/libnet/libnet_samsync_keytab.c
new file mode 100644 (file)
index 0000000..2208a71
--- /dev/null
@@ -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) */
index a370d3d6b2decb13887e9197d3c0aa6af8250f5b..10b1e4709afd7c010ee7d03aab57c45e96345a7f 100644 (file)
@@ -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  */
 
index 6a7c638e2abf4b691738791fe1fb0e8f52234b15..19566bdf09cf07e6a9bc5c3843f2d29ab74ccebb 100644 (file)
@@ -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}
        };
 
index c941338b32ededba7e3620d10a9ef79c0ed7701d..e4aa343d06efcd0e7edf96ae4419dbab9bd109b3 100644 (file)
@@ -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) {
+               d_printf("Usage\n"
+                        "net rpc vampire keytab\n"
+                        "    Dump remote SAM database to Kerberos keytab file\n");
+               return 0;
+       }
+
+       return run_rpc_command(c, NULL, PI_NETLOGON, 0, rpc_vampire_keytab_internals,
+                              argc, argv);
+}