From 221c1512a8b4de9a568c0a0cdafa97ab5c53368c Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 21 Dec 2005 22:02:52 +0000 Subject: r12411: Add 'net samdump keytab '. 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 (This used to be commit 272013438f53bb168f74e09eb70fc96112b84772) --- source4/auth/credentials/credentials_files.c | 4 +- source4/auth/credentials/credentials_krb5.c | 27 ++--- source4/auth/kerberos/kerberos_util.c | 58 +++++++---- source4/include/structs.h | 1 + source4/libnet/config.mk | 1 + source4/libnet/libnet_samdump_keytab.c | 144 +++++++++++++++++++++++++++ source4/libnet/libnet_vampire.h | 6 ++ source4/utils/net/net_vampire.c | 67 +++++++++++++ 8 files changed, 264 insertions(+), 44 deletions(-) create mode 100644 source4/libnet/libnet_samdump_keytab.c (limited to 'source4') diff --git a/source4/auth/credentials/credentials_files.c b/source4/auth/credentials/credentials_files.c index 1f7a7cf435..8d84e8cdb5 100644 --- a/source4/auth/credentials/credentials_files.c +++ b/source4/auth/credentials/credentials_files.c @@ -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); } } } diff --git a/source4/auth/credentials/credentials_krb5.c b/source4/auth/credentials/credentials_krb5.c index 173739e9b8..5f40ca1046 100644 --- a/source4/auth/credentials/credentials_krb5.c +++ b/source4/auth/credentials/credentials_krb5.c @@ -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; diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c index a9ea6f9db3..d8c650b098 100644 --- a/source4/auth/kerberos/kerberos_util.c +++ b/source4/auth/kerberos/kerberos_util.c @@ -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 { diff --git a/source4/include/structs.h b/source4/include/structs.h index b6ccd0ce19..b652579edd 100644 --- a/source4/include/structs.h +++ b/source4/include/structs.h @@ -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; diff --git a/source4/libnet/config.mk b/source4/libnet/config.mk index e998675fcb..fe68a8ef59 100644 --- a/source4/libnet/config.mk +++ b/source4/libnet/config.mk @@ -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/source4/libnet/libnet_samdump_keytab.c b/source4/libnet/libnet_samdump_keytab.c new file mode 100644 index 0000000000..deaa282801 --- /dev/null +++ b/source4/libnet/libnet_samdump_keytab.c @@ -0,0 +1,144 @@ +/* + Unix SMB/CIFS implementation. + + Extract kerberos keys from a remote SamSync server + + Copyright (C) Andrew Bartlett 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; +} diff --git a/source4/libnet/libnet_vampire.h b/source4/libnet/libnet_vampire.h index 8a588de48c..c8d569a97e 100644 --- a/source4/libnet/libnet_vampire.h +++ b/source4/libnet/libnet_vampire.h @@ -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, diff --git a/source4/utils/net/net_vampire.c b/source4/utils/net/net_vampire.c index e898352cfc..75ad175c66 100644 --- a/source4/utils/net/net_vampire.c +++ b/source4/utils/net/net_vampire.c @@ -25,11 +25,77 @@ #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 \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 \n"); return 0; } -- cgit