r12411: Add 'net samdump keytab <keytab>'.
authorAndrew Bartlett <abartlet@samba.org>
Wed, 21 Dec 2005 22:02:52 +0000 (22:02 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:47:35 +0000 (13:47 -0500)
This extracts a remote windows domain into a keytab, suitable for use
in ethereal for kerberos decryption.

For the moment, like net samdump and net samsync, the 'password
server' smb.conf option must be set to the binding string for the
server. eg:

password server = ncacn_np:mypdc

Andrew Bartlett

source/auth/credentials/credentials_files.c
source/auth/credentials/credentials_krb5.c
source/auth/kerberos/kerberos_util.c
source/include/structs.h
source/libnet/config.mk
source/libnet/libnet_samdump_keytab.c [new file with mode: 0644]
source/libnet/libnet_vampire.h
source/utils/net/net_vampire.c

index 1f7a7cf435d710a20286f33a034b3f4cfd503577..8d84e8cdb57cd212b3d9eee73611a13be94d443d 100644 (file)
@@ -301,13 +301,13 @@ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
         * (chewing CPU time) from the password */
        keytab = ldb_msg_find_string(msgs[0], "krb5Keytab", NULL);
        if (keytab) {
-               cli_credentials_set_keytab(cred, keytab, CRED_SPECIFIED);
+               cli_credentials_set_keytab_name(cred, keytab, CRED_SPECIFIED);
        } else {
                keytab = ldb_msg_find_string(msgs[0], "privateKeytab", NULL);
                if (keytab) {
                        keytab = talloc_asprintf(mem_ctx, "FILE:%s", private_path(mem_ctx, keytab));
                        if (keytab) {
-                               cli_credentials_set_keytab(cred, keytab, CRED_SPECIFIED);
+                               cli_credentials_set_keytab_name(cred, keytab, CRED_SPECIFIED);
                        }
                }
        }
index 173739e9b868089ca63335173e6f235cdb92fe5d..5f40ca10467a974538f95ab742cb8204f6928d89 100644 (file)
@@ -398,7 +398,7 @@ int cli_credentials_get_keytab(struct cli_credentials *cred,
                return ENOMEM;
        }
 
-       ret = create_memory_keytab(mem_ctx, cred, smb_krb5_context, &ktc);
+       ret = smb_krb5_create_memory_keytab(mem_ctx, cred, smb_krb5_context, &ktc);
        if (ret) {
                talloc_free(mem_ctx);
                return ret;
@@ -417,14 +417,13 @@ int cli_credentials_get_keytab(struct cli_credentials *cred,
 /* Given the name of a keytab (presumably in the format
  * FILE:/etc/krb5.keytab), open it and attach it */
 
-int cli_credentials_set_keytab(struct cli_credentials *cred, 
-                              const char *keytab_name, 
-                              enum credentials_obtained obtained) 
+int cli_credentials_set_keytab_name(struct cli_credentials *cred, 
+                                   const char *keytab_name, 
+                                   enum credentials_obtained obtained) 
 {
        krb5_error_code ret;
        struct keytab_container *ktc;
        struct smb_krb5_context *smb_krb5_context;
-       krb5_keytab keytab;
        TALLOC_CTX *mem_ctx;
 
        if (cred->keytab_obtained >= obtained) {
@@ -441,24 +440,12 @@ int cli_credentials_set_keytab(struct cli_credentials *cred,
                return ENOMEM;
        }
 
-       ret = krb5_kt_resolve(smb_krb5_context->krb5_context, keytab_name, &keytab);
+       ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context, 
+                                  keytab_name, &ktc);
        if (ret) {
-               DEBUG(1,("failed to open krb5 keytab: %s\n", 
-                        smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
-                                                   ret, mem_ctx)));
-               talloc_free(mem_ctx);
                return ret;
        }
 
-       ktc = talloc(mem_ctx, struct keytab_container);
-       if (!ktc) {
-               talloc_free(mem_ctx);
-               return ENOMEM;
-       }
-
-       ktc->smb_krb5_context = talloc_reference(ktc, smb_krb5_context);
-       ktc->keytab = keytab;
-
        cred->keytab_obtained = obtained;
 
        talloc_steal(cred, ktc);
@@ -492,7 +479,7 @@ int cli_credentials_update_keytab(struct cli_credentials *cred)
                return ret;
        }
 
-       ret = update_keytab(mem_ctx, cred, smb_krb5_context, ktc);
+       ret = smb_krb5_update_keytab(mem_ctx, cred, smb_krb5_context, ktc);
 
        talloc_free(mem_ctx);
        return ret;
index a9ea6f9db396c67b5f615f414e3ce5f3f2e3f71f..d8c650b0989acb68993343b64c186f4a46d53df0 100644 (file)
@@ -226,6 +226,32 @@ static int free_keytab(void *ptr) {
        return 0;
 }
 
+int smb_krb5_open_keytab(TALLOC_CTX *mem_ctx,
+                        struct smb_krb5_context *smb_krb5_context, 
+                        const char *keytab_name, struct keytab_container **ktc) 
+{
+       krb5_keytab keytab;
+       int ret;
+       ret = krb5_kt_resolve(smb_krb5_context->krb5_context, keytab_name, &keytab);
+       if (ret) {
+               DEBUG(1,("failed to open krb5 keytab: %s\n", 
+                        smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
+                                                   ret, mem_ctx)));
+               return ret;
+       }
+
+       *ktc = talloc(mem_ctx, struct keytab_container);
+       if (!*ktc) {
+               return ENOMEM;
+       }
+
+       (*ktc)->smb_krb5_context = talloc_reference(*ktc, smb_krb5_context);
+       (*ktc)->keytab = keytab;
+       talloc_set_destructor(*ktc, free_keytab);
+
+       return 0;
+}
+
 struct enctypes_container {
        struct smb_krb5_context *smb_krb5_context;
        krb5_enctype *enctypes;
@@ -574,10 +600,10 @@ static krb5_error_code remove_old_entries(TALLOC_CTX *parent_ctx,
        return ret;
 }
 
-int update_keytab(TALLOC_CTX *parent_ctx,
-                 struct cli_credentials *machine_account,
-                 struct smb_krb5_context *smb_krb5_context,
-                 struct keytab_container *keytab_container) 
+int smb_krb5_update_keytab(TALLOC_CTX *parent_ctx,
+                          struct cli_credentials *machine_account,
+                          struct smb_krb5_context *smb_krb5_context,
+                          struct keytab_container *keytab_container) 
 {
        krb5_error_code ret;
        BOOL found_previous;
@@ -604,16 +630,15 @@ int update_keytab(TALLOC_CTX *parent_ctx,
        return ret;
 }
 
-int create_memory_keytab(TALLOC_CTX *parent_ctx,
-                        struct cli_credentials *machine_account,
-                        struct smb_krb5_context *smb_krb5_context,
-                        struct keytab_container **keytab_container) 
+int smb_krb5_create_memory_keytab(TALLOC_CTX *parent_ctx,
+                                 struct cli_credentials *machine_account,
+                                 struct smb_krb5_context *smb_krb5_context,
+                                 struct keytab_container **keytab_container) 
 {
        krb5_error_code ret;
        TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
        const char *rand_string;
        const char *keytab_name;
-       krb5_keytab keytab;
        if (!mem_ctx) {
                return ENOMEM;
        }
@@ -633,23 +658,12 @@ int create_memory_keytab(TALLOC_CTX *parent_ctx,
                return ENOMEM;
        }
 
-       /* Find the keytab */
-       ret = krb5_kt_resolve(smb_krb5_context->krb5_context, keytab_name, &keytab);
+       ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context, keytab_name, keytab_container);
        if (ret) {
-               DEBUG(1,("failed to resolve keytab: %s: %s\n",
-                        keytab_name,
-                        smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
-                                                   ret, mem_ctx)));
-               talloc_free(mem_ctx);
                return ret;
        }
 
-       (*keytab_container)->smb_krb5_context = talloc_reference(*keytab_container, smb_krb5_context);
-       (*keytab_container)->keytab = keytab;
-
-       talloc_set_destructor(*keytab_container, free_keytab);
-       
-       ret = update_keytab(mem_ctx, machine_account, smb_krb5_context, *keytab_container);
+       ret = smb_krb5_update_keytab(mem_ctx, machine_account, smb_krb5_context, *keytab_container);
        if (ret == 0) {
                talloc_steal(parent_ctx, *keytab_container);
        } else {
index b6ccd0ce191862e36e21daf19ca0a52aca7e3026..b652579edd007e1c2abbafdf800bf15cb9e2e611 100644 (file)
@@ -192,6 +192,7 @@ struct libnet_AddShare;
 struct libnet_DelShare;
 struct libnet_Lookup;
 struct libnet_SamDump;
+struct libnet_SamDump_keytab;
 struct libnet_SamSync;
 struct libnet_samsync_ldb;
 struct net_functable;
index e998675fcbf2b8d0203db5079775756b41fd331b..fe68a8ef59719e4b30a07dc34dfe7f81effe1466 100644 (file)
@@ -17,6 +17,7 @@ ADD_OBJ_FILES = \
                libnet_join.o \
                libnet_vampire.o \
                libnet_samdump.o \
+               libnet_samdump_keytab.o \
                libnet_samsync_ldb.o \
                libnet_user.o \
                libnet_share.o \
diff --git a/source/libnet/libnet_samdump_keytab.c b/source/libnet/libnet_samdump_keytab.c
new file mode 100644 (file)
index 0000000..deaa282
--- /dev/null
@@ -0,0 +1,144 @@
+/* 
+   Unix SMB/CIFS implementation.
+   
+   Extract kerberos keys from a remote SamSync server
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+   
+   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 2 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, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include "includes.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+
+static NTSTATUS samdump_keytab_handle_user(TALLOC_CTX *mem_ctx,
+                                           const char *keytab_name,
+                                           struct creds_CredentialState *creds,
+                                           struct netr_DELTA_ENUM *delta) 
+{
+       struct netr_DELTA_USER *user = delta->delta_union.user;
+       const char *username = user->account_name.string;
+       struct cli_credentials *credentials;
+       int ret;
+
+       if (!user->nt_password_present) {
+               /* We can't do anything here */
+               return NT_STATUS_OK;
+       }
+
+       credentials = cli_credentials_init(mem_ctx);
+       if (!credentials) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       cli_credentials_set_conf(credentials);
+       cli_credentials_set_username(credentials, username, CRED_SPECIFIED);
+
+       /* We really should consult ldap in the main SamSync code, and
+        * pass a value in here */
+       cli_credentials_set_kvno(credentials, 0);
+       cli_credentials_set_nt_hash(credentials, &user->ntpassword, CRED_SPECIFIED);
+       ret = cli_credentials_set_keytab_name(credentials, keytab_name, CRED_SPECIFIED);
+       if (ret) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       ret = cli_credentials_update_keytab(credentials);
+       if (ret) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS libnet_samdump_keytab_fn(TALLOC_CTX *mem_ctx,          
+                                        void *private,                         
+                                        struct creds_CredentialState *creds,
+                                        enum netr_SamDatabaseID database,
+                                        struct netr_DELTA_ENUM *delta,
+                                        char **error_string)
+{
+       NTSTATUS nt_status = NT_STATUS_OK;
+       const char *keytab_name = private;
+
+       *error_string = NULL;
+       switch (delta->delta_type) {
+       case NETR_DELTA_USER:
+       {
+               /* not interested in builtin users */
+               if (database == SAM_DATABASE_DOMAIN) {
+                       nt_status = samdump_keytab_handle_user(mem_ctx, 
+                                                              keytab_name,
+                                                              creds,
+                                                              delta);
+                       break;
+               }
+       }
+       default:
+               /* Can't dump them all right now */
+               break;
+       }
+       return nt_status;
+}
+
+static NTSTATUS libnet_SamDump_keytab_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamDump_keytab *r)
+{
+       NTSTATUS nt_status;
+       struct libnet_SamSync r2;
+
+       r2.error_string = NULL;
+       r2.delta_fn = libnet_samdump_keytab_fn;
+       r2.fn_ctx = r->keytab_name;
+       r2.machine_account = NULL; /* TODO:  Create a machine account, fill this in, and the delete it */
+       nt_status = libnet_SamSync_netlogon(ctx, mem_ctx, &r2);
+       r->error_string = r2.error_string;
+
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return nt_status;
+       }
+
+       return nt_status;
+}
+
+
+
+static NTSTATUS libnet_SamDump_keytab_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamDump_keytab *r)
+{
+       NTSTATUS nt_status;
+       struct libnet_SamDump_keytab r2;
+       r2.level = LIBNET_SAMDUMP_NETLOGON;
+       r2.error_string = NULL;
+       r2.keytab_name = r->keytab_name;
+       nt_status = libnet_SamDump_keytab(ctx, mem_ctx, &r2);
+       r->error_string = r2.error_string;
+       
+       return nt_status;
+}
+
+NTSTATUS libnet_SamDump_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamDump_keytab *r)
+{
+       switch (r->level) {
+       case LIBNET_SAMDUMP_GENERIC:
+               return libnet_SamDump_keytab_generic(ctx, mem_ctx, r);
+       case LIBNET_SAMDUMP_NETLOGON:
+               return libnet_SamDump_keytab_netlogon(ctx, mem_ctx, r);
+       }
+
+       return NT_STATUS_INVALID_LEVEL;
+}
index 8a588de48cf0bffb1371d89165250e6da245be09..c8d569a97e3d24b57fa88959c033de4619e375c2 100644 (file)
@@ -43,6 +43,12 @@ struct libnet_SamDump {
        char *error_string;
 };
 
+struct libnet_SamDump_keytab {
+       enum libnet_SamDump_level level;
+       char *keytab_name;
+       char *error_string;
+};
+
 enum libnet_samsync_ldb_level {
        LIBNET_SAMSYNC_LDB_GENERIC,
        LIBNET_SAMSYNC_LDB_NETLOGON,
index e898352cfced24675f180ab83b4cd7f881c6faeb..75ad175c6641ac832fe99b3e9e35595781769ed5 100644 (file)
 #include "libnet/libnet.h"
 #include "librpc/gen_ndr/ndr_samr.h"
 
+static int net_samdump_keytab_usage(struct net_context *ctx, int argc, const char **argv)
+{
+       d_printf("net samdump keytab <keytab>\n");
+       return 0;       
+}
+
+static int net_samdump_keytab_help(struct net_context *ctx, int argc, const char **argv)
+{
+       d_printf("Dumps kerberos keys of a domain into a keytab.\n");
+       return 0;       
+}
+
+static int net_samdump_keytab(struct net_context *ctx, int argc, const char **argv) 
+{
+       NTSTATUS status;
+       struct libnet_context *libnetctx;
+       struct libnet_SamDump_keytab r;
+
+       switch (argc) {
+       case 0:
+               return net_samdump_keytab_usage(ctx, argc, argv);
+               break;
+       case 1:
+               r.keytab_name = argv[0];
+               break;
+       }
+
+       libnetctx = libnet_context_init(NULL);
+       if (!libnetctx) {
+               return -1;      
+       }
+       libnetctx->cred = ctx->credentials;
+
+       r.level        = LIBNET_SAMDUMP_GENERIC;
+       r.error_string = NULL;
+
+       status = libnet_SamDump_keytab(libnetctx, ctx->mem_ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("libnet_SamDump returned %s: %s\n",
+                        nt_errstr(status),
+                        r.error_string));
+               return -1;
+       }
+
+       talloc_free(libnetctx);
+
+       return 0;
+}
+
+/* main function table */
+static const struct net_functable net_samdump_functable[] = {
+       {"keytab", "dump keys into a keytab\n", net_samdump_keytab, net_samdump_keytab_usage},
+       {NULL, NULL, NULL, NULL}
+};
+
 int net_samdump(struct net_context *ctx, int argc, const char **argv) 
 {
        NTSTATUS status;
        struct libnet_context *libnetctx;
        struct libnet_SamDump r;
+       int rc;
+
+       switch (argc) {
+       case 0:
+               break;
+       case 1:
+       default:
+               rc = net_run_function(ctx, argc, argv, net_samdump_functable, 
+                                     net_samdump_usage);
+               return rc;
+       }
 
        libnetctx = libnet_context_init(NULL);
        if (!libnetctx) {
@@ -56,6 +122,7 @@ int net_samdump(struct net_context *ctx, int argc, const char **argv)
 int net_samdump_usage(struct net_context *ctx, int argc, const char **argv)
 {
        d_printf("net samdump\n");
+       d_printf("net samdump keytab <keytab>\n");
        return 0;       
 }