s4:kerberos Add 'net export keytab' command for wireshark decryption
authorAndrew Bartlett <abartlet@samba.org>
Mon, 27 Jul 2009 12:04:26 +0000 (22:04 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 27 Jul 2009 22:52:43 +0000 (08:52 +1000)
It is much easier to do decryption with wireshark when the keytab is
available for every host in the domain.  Running 'net export keytab
<keytab name>' will export the current (as pointed to by the supplied
smb.conf) local Samba4 doamin.

(This uses Heimdal's 'hdb' keytab and then the existing hdb-samba4,
and so has a good chance of keeping working in the long term).

Andrew Bartlett

16 files changed:
.gitignore
source4/auth/kerberos/config.mk
source4/auth/kerberos/keytab_copy.c [new file with mode: 0644]
source4/kdc/config.mk
source4/kdc/hdb-samba4.h
source4/kdc/kdc.c
source4/kdc/kdc.h
source4/kdc/pac-glue.c
source4/kdc/pac-glue.h [new file with mode: 0644]
source4/libnet/config.mk
source4/libnet/libnet.h
source4/libnet/libnet_export_keytab.c [new file with mode: 0644]
source4/libnet/libnet_export_keytab.h [new file with mode: 0644]
source4/utils/net/config.mk
source4/utils/net/net.c
source4/utils/net/net_export_keytab.c [new file with mode: 0644]

index 1ace6e73a4a8c77047a591d80655d9b068b20fc9..0d54fb09ddcd7bca1ddb5b1cfd6f64cc7cc5c9fe 100644 (file)
@@ -177,7 +177,7 @@ source4/heimdal/lib/wind/*_table.?
 source4/include/build.h
 source4/include/config_tmp.h
 source4/include/config_tmp.h.in
-source4/kdc/pac_glue.h
+source4/kdc/pac-glue_proto.h
 source4/ldap_server/proto.h
 source4/lib/charset/charset_proto.h
 source4/libcli/composite/proto.h
index 822bf398a76d463525698103fab0747c0f6e614b..609b036b64dc37c892aea58aecd6c153c65be11d 100644 (file)
@@ -12,7 +12,8 @@ KERBEROS_OBJ_FILES = $(addprefix $(authsrcdir)/kerberos/, \
        kerberos_heimdal.o \
        kerberos_pac.o \
        gssapi_parse.o \
-       krb5_init_context.o)
+       krb5_init_context.o \
+       keytab_copy.o)
 
 $(eval $(call proto_header_template,$(authsrcdir)/kerberos/proto.h,$(KERBEROS_OBJ_FILES:.o=.c)))
 
diff --git a/source4/auth/kerberos/keytab_copy.c b/source4/auth/kerberos/keytab_copy.c
new file mode 100644 (file)
index 0000000..ba4ea2b
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+
+static const krb5_boolean verbose_flag = FALSE;
+
+static krb5_boolean
+compare_keyblock(const krb5_keyblock *a, const krb5_keyblock *b)
+{
+    if(a->keytype != b->keytype ||
+       a->keyvalue.length != b->keyvalue.length ||
+       memcmp(a->keyvalue.data, b->keyvalue.data, a->keyvalue.length) != 0)
+       return FALSE;
+    return TRUE;
+}
+
+krb5_error_code kt_copy (krb5_context context, const char *from, const char *to)
+{
+    krb5_error_code ret;
+    krb5_keytab src_keytab, dst_keytab;
+    krb5_kt_cursor cursor;
+    krb5_keytab_entry entry, dummy;
+
+    ret = krb5_kt_resolve (context, from, &src_keytab);
+    if (ret) {
+       krb5_warn (context, ret, "resolving src keytab `%s'", from);
+       return 1;
+    }
+
+    ret = krb5_kt_resolve (context, to, &dst_keytab);
+    if (ret) {
+       krb5_kt_close (context, src_keytab);
+       krb5_warn (context, ret, "resolving dst keytab `%s'", to);
+       return 1;
+    }
+
+    ret = krb5_kt_start_seq_get (context, src_keytab, &cursor);
+    if (ret) {
+       krb5_warn (context, ret, "krb5_kt_start_seq_get %s", from);
+       goto out;
+    }
+
+    if (verbose_flag)
+       fprintf(stderr, "copying %s to %s\n", from, to);
+
+    while((ret = krb5_kt_next_entry(context, src_keytab,
+                                   &entry, &cursor)) == 0) {
+       char *name_str;
+       char *etype_str;
+       ret = krb5_unparse_name (context, entry.principal, &name_str);
+       if(ret) {
+           krb5_warn(context, ret, "krb5_unparse_name");
+           name_str = NULL; /* XXX */
+       }
+       ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &etype_str);
+       if(ret) {
+           krb5_warn(context, ret, "krb5_enctype_to_string");
+           etype_str = NULL; /* XXX */
+       }
+       ret = krb5_kt_get_entry(context, dst_keytab,
+                               entry.principal,
+                               entry.vno,
+                               entry.keyblock.keytype,
+                               &dummy);
+       if(ret == 0) {
+           /* this entry is already in the new keytab, so no need to
+               copy it; if the keyblocks are not the same, something
+               is weird, so complain about that */
+           if(!compare_keyblock(&entry.keyblock, &dummy.keyblock)) {
+               krb5_warnx(context, "entry with different keyvalue "
+                          "already exists for %s, keytype %s, kvno %d",
+                          name_str, etype_str, entry.vno);
+           }
+           krb5_kt_free_entry(context, &dummy);
+           krb5_kt_free_entry (context, &entry);
+           free(name_str);
+           free(etype_str);
+           continue;
+       } else if(ret != KRB5_KT_NOTFOUND) {
+           krb5_warn (context, ret, "%s: fetching %s/%s/%u",
+                      to, name_str, etype_str, entry.vno);
+           krb5_kt_free_entry (context, &entry);
+           free(name_str);
+           free(etype_str);
+           break;
+       } 
+       if (verbose_flag)
+           fprintf (stderr, "copying %s, keytype %s, kvno %d\n", name_str,
+                    etype_str, entry.vno);
+       ret = krb5_kt_add_entry (context, dst_keytab, &entry);
+       krb5_kt_free_entry (context, &entry);
+       if (ret) {
+           krb5_warn (context, ret, "%s: adding %s/%s/%u",
+                      to, name_str, etype_str, entry.vno);
+           free(name_str);
+           free(etype_str);
+           break;
+       }
+       free(name_str);
+       free(etype_str);
+    }
+    krb5_kt_end_seq_get (context, src_keytab, &cursor);
+
+  out:
+    krb5_kt_close (context, src_keytab);
+    krb5_kt_close (context, dst_keytab);
+    if (ret == KRB5_KT_END) {
+       return 0;
+    } else if (ret == 0) {
+       return EINVAL;
+    }
+    return ret;
+}
index 03fa2db295c77f92c903668173c49fdea2187613..7a998572483d1801c711263de15ec5c3ba1cc911 100644 (file)
@@ -6,7 +6,7 @@
 INIT_FUNCTION = server_service_kdc_init
 SUBSYSTEM = service
 PRIVATE_DEPENDENCIES = \
-               HEIMDAL_KDC HDB_SAMBA4 LIBSAMBA-HOSTCONFIG
+               HEIMDAL_KDC HDB_SAMBA4 PAC_GLUE LIBSAMBA-HOSTCONFIG
 # End SUBSYSTEM KDC
 #######################
 
@@ -22,5 +22,17 @@ PRIVATE_DEPENDENCIES = \
 # End SUBSYSTEM KDC
 #######################
 
-HDB_SAMBA4_OBJ_FILES = $(addprefix $(kdcsrcdir)/, hdb-samba4.o pac-glue.o)
-$(eval $(call proto_header_template,$(kdcsrcdir)/pac_glue.h,$(HDB_SAMBA4_OBJ_FILES:.o=.c)))
+HDB_SAMBA4_OBJ_FILES = $(addprefix $(kdcsrcdir)/, hdb-samba4.o)
+
+#######################
+# Start SUBSYSTEM KDC
+[SUBSYSTEM::PAC_GLUE]
+CFLAGS = -Iheimdal/kdc -Iheimdal/lib/hdb
+PRIVATE_DEPENDENCIES = \
+               LIBLDB auth_sam auth_sam_reply CREDENTIALS \
+               HEIMDAL_HDB LIBSAMBA-HOSTCONFIG
+# End SUBSYSTEM KDC
+#######################
+
+PAC_GLUE_OBJ_FILES = $(addprefix $(kdcsrcdir)/, pac-glue.o)
+$(eval $(call proto_header_template,$(kdcsrcdir)/pac-glue_proto.h,$(HDB_SAMBA4_OBJ_FILES:.o=.c)))
index 0b39fdfb10d93183802c1f4eb0fec08da414d994..fc2f9c131079f8faf023ecb676c352c3bdfcf314 100644 (file)
@@ -20,8 +20,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-extern TALLOC_CTX *hdb_samba4_mem_ctx;
-
 struct hdb_samba4_context {
        struct tevent_context *ev_ctx;
        struct loadparm_context *lp_ctx;
index 746781f02d3ff0ccb4d334a4847ce7b233dd70a0..c861f7ae3e2cd77d2803644a434d50155c0a68a8 100644 (file)
@@ -550,15 +550,6 @@ static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_c
        return NT_STATUS_OK;
 }
 
-static struct krb5plugin_windc_ftable windc_plugin_table = {
-       .minor_version = KRB5_WINDC_PLUGING_MINOR,
-       .init = samba_kdc_plugin_init,
-       .fini = samba_kdc_plugin_fini,
-       .pac_generate = samba_kdc_get_pac,
-       .pac_verify = samba_kdc_reget_pac,
-       .client_access = samba_kdc_check_client_access,
-};
-
 
 static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, 
                                 struct kdc_check_generic_kerberos *r)
index e8511d95eb0eaf35e45d7da5bb1cb4ba0ecc206c..fb70f953927d65fcc7f5fb3f731acf528f83fd0d 100644 (file)
@@ -25,7 +25,7 @@
 #include <hdb.h>
 #include <kdc.h>
 #include <krb5/windc_plugin.h>
-#include "kdc/pac_glue.h"
+#include "kdc/pac-glue.h"
 #include "kdc/hdb-samba4.h"
 
 struct kdc_server;
index 3dcdd4d439f997eef5526b17d9c383dbf0bf976c..3d542d9a942e1c28cff459556f90e6167cdd7409 100644 (file)
 struct krb5_dh_moduli;
 struct _krb5_krb_auth_data;
 
-krb5_error_code        samba_kdc_plugin_init(krb5_context context, void **ptr) 
+static krb5_error_code samba_kdc_plugin_init(krb5_context context, void **ptr) 
 {
        *ptr = NULL;
        return 0;
 }
 
-void   samba_kdc_plugin_fini(void *ptr) 
+static void    samba_kdc_plugin_fini(void *ptr) 
 {
        return;
 }
@@ -104,10 +104,10 @@ static krb5_error_code make_pac(krb5_context context,
 }
 
 /* Given the right private pointer from hdb_samba4, get a PAC from the attached ldb messages */
-krb5_error_code samba_kdc_get_pac(void *priv,
-                                 krb5_context context, 
-                                 struct hdb_entry_ex *client,
-                                 krb5_pac *pac)
+static krb5_error_code samba_kdc_get_pac(void *priv,
+                                        krb5_context context, 
+                                        struct hdb_entry_ex *client,
+                                        krb5_pac *pac)
 {
        krb5_error_code ret;
        NTSTATUS nt_status;
@@ -149,10 +149,10 @@ krb5_error_code samba_kdc_get_pac(void *priv,
 
 /* Resign (and reform, including possibly new groups) a PAC */
 
-krb5_error_code samba_kdc_reget_pac(void *priv, krb5_context context,
-                               const krb5_principal client_principal,
-                               struct hdb_entry_ex *client,  
-                               struct hdb_entry_ex *server, krb5_pac *pac)
+static krb5_error_code samba_kdc_reget_pac(void *priv, krb5_context context,
+                                          const krb5_principal client_principal,
+                                          struct hdb_entry_ex *client,  
+                                          struct hdb_entry_ex *server, krb5_pac *pac)
 {
        krb5_error_code ret;
 
@@ -230,13 +230,13 @@ static void samba_kdc_build_edata_reply(TALLOC_CTX *tmp_ctx, krb5_data *e_data,
  * the account_ok routine in auth/auth_sam.c for consistancy */
 
 
-krb5_error_code samba_kdc_check_client_access(void *priv, 
-                                             krb5_context context, 
-                                             krb5_kdc_configuration *config,
-                                             hdb_entry_ex *client_ex, const char *client_name,
-                                             hdb_entry_ex *server_ex, const char *server_name,
-                                             KDC_REQ *req,
-                                             krb5_data *e_data)
+static krb5_error_code samba_kdc_check_client_access(void *priv, 
+                                                    krb5_context context, 
+                                                    krb5_kdc_configuration *config,
+                                                    hdb_entry_ex *client_ex, const char *client_name,
+                                                    hdb_entry_ex *server_ex, const char *server_name,
+                                                    KDC_REQ *req,
+                                                    krb5_data *e_data)
 {
        krb5_error_code ret;
        NTSTATUS nt_status;
@@ -314,3 +314,12 @@ krb5_error_code samba_kdc_check_client_access(void *priv,
        return ret;
 }
 
+struct krb5plugin_windc_ftable windc_plugin_table = {
+       .minor_version = KRB5_WINDC_PLUGING_MINOR,
+       .init = samba_kdc_plugin_init,
+       .fini = samba_kdc_plugin_fini,
+       .pac_generate = samba_kdc_get_pac,
+       .pac_verify = samba_kdc_reget_pac,
+       .client_access = samba_kdc_check_client_access,
+};
+
diff --git a/source4/kdc/pac-glue.h b/source4/kdc/pac-glue.h
new file mode 100644 (file)
index 0000000..1c14f7f
--- /dev/null
@@ -0,0 +1,30 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   KDC Server startup
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
+
+   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/>.
+*/
+
+#ifndef __KDC_PAC_GLUE_H__
+#define __KDC_PAC_GLUE_H__
+
+#include "kdc/pac-glue_proto.h"
+
+extern struct krb5plugin_windc_ftable windc_plugin_table;
+
+#endif /* __KDC_PAC_GLUE_H__ */
+
index 07d5434ebfe32dbfb882cdeb52aaa2c648ed5aa9..eede8c871de080e1885315714de08617b1044976 100644 (file)
@@ -1,5 +1,5 @@
 [SUBSYSTEM::LIBSAMBA-NET]
-PUBLIC_DEPENDENCIES = CREDENTIALS dcerpc dcerpc_samr RPC_NDR_LSA RPC_NDR_SRVSVC RPC_NDR_DRSUAPI LIBCLI_COMPOSITE LIBCLI_RESOLVE LIBCLI_FINDDCS LIBCLI_CLDAP LIBCLI_FINDDCS gensec_schannel LIBCLI_AUTH LIBNDR SMBPASSWD PROVISION LIBCLI_SAMSYNC
+PUBLIC_DEPENDENCIES = CREDENTIALS dcerpc dcerpc_samr RPC_NDR_LSA RPC_NDR_SRVSVC RPC_NDR_DRSUAPI LIBCLI_COMPOSITE LIBCLI_RESOLVE LIBCLI_FINDDCS LIBCLI_CLDAP LIBCLI_FINDDCS gensec_schannel LIBCLI_AUTH LIBNDR SMBPASSWD PROVISION LIBCLI_SAMSYNC HDB_SAMBA4
 
 LIBSAMBA-NET_OBJ_FILES = $(addprefix $(libnetsrcdir)/, \
        libnet.o libnet_passwd.o libnet_time.o libnet_rpc.o \
@@ -7,7 +7,7 @@ LIBSAMBA-NET_OBJ_FILES = $(addprefix $(libnetsrcdir)/, \
        libnet_vampire.o libnet_samdump.o libnet_samdump_keytab.o \
        libnet_samsync_ldb.o libnet_user.o libnet_group.o libnet_share.o \
        libnet_lookup.o libnet_domain.o userinfo.o groupinfo.o userman.o \
-       groupman.o prereq_domain.o libnet_samsync.o)
+       groupman.o prereq_domain.o libnet_samsync.o libnet_export_keytab.o)
 
 $(eval $(call proto_header_template,$(libnetsrcdir)/libnet_proto.h,$(LIBSAMBA-NET_OBJ_FILES:.o=.c)))
 
index 543a131806b667a21b5dad8f6aec6adbe72a6e37..9964a3f526dd2a6ff6020054e610271016c1ccc7 100644 (file)
@@ -75,4 +75,5 @@ struct libnet_context {
 #include "libnet/libnet_share.h"
 #include "libnet/libnet_lookup.h"
 #include "libnet/libnet_domain.h"
+#include "libnet/libnet_export_keytab.h"
 #include "libnet/libnet_proto.h"
diff --git a/source4/libnet/libnet_export_keytab.c b/source4/libnet/libnet_export_keytab.c
new file mode 100644 (file)
index 0000000..a7006b4
--- /dev/null
@@ -0,0 +1,53 @@
+#include "includes.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+#include <hdb.h>
+#include "kdc/hdb-samba4.h"
+#include "libnet/libnet.h"
+
+NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r)
+{
+       krb5_error_code ret;
+       struct smb_krb5_context *smb_krb5_context;
+       const char *from_keytab;
+
+       /* Register hdb-samba4 hooks for use as a keytab */
+
+       struct hdb_samba4_context *hdb_samba4_context = talloc(mem_ctx, struct hdb_samba4_context);
+       if (!hdb_samba4_context) {
+               return NT_STATUS_NO_MEMORY; 
+       }
+
+       hdb_samba4_context->ev_ctx = ctx->event_ctx;
+       hdb_samba4_context->lp_ctx = ctx->lp_ctx;
+
+       from_keytab = talloc_asprintf(hdb_samba4_context, "HDB:samba4&%p", hdb_samba4_context);
+       if (!from_keytab) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ret = smb_krb5_init_context(ctx, ctx->event_ctx, ctx->lp_ctx, &smb_krb5_context);
+       if (ret) {
+               return NT_STATUS_NO_MEMORY; 
+       }
+
+       ret = krb5_plugin_register(smb_krb5_context->krb5_context, 
+                                  PLUGIN_TYPE_DATA, "hdb",
+                                  &hdb_samba4);
+       if(ret) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ret = krb5_kt_register(smb_krb5_context->krb5_context, &hdb_kt_ops);
+       if(ret) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ret = kt_copy(smb_krb5_context->krb5_context, from_keytab, r->in.keytab_name);
+       if(ret) {
+               r->out.error_string = smb_get_krb5_error_message(smb_krb5_context->krb5_context,
+                                                                ret, mem_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       return NT_STATUS_OK;
+}
diff --git a/source4/libnet/libnet_export_keytab.h b/source4/libnet/libnet_export_keytab.h
new file mode 100644 (file)
index 0000000..194f890
--- /dev/null
@@ -0,0 +1,28 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
+   
+   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/>.
+*/
+
+struct libnet_export_keytab {
+       struct {
+               const char *keytab_name;
+       } in;
+       struct {
+               const char *error_string;
+       } out;
+};
+
index b2f0fcf6b1fdff6e62f9716bb8ff59616182e0f9..ff8cb2c526944b27dbd44f064d22d0a6e4526845 100644 (file)
@@ -21,7 +21,8 @@ net_OBJ_FILES = $(addprefix $(utilssrcdir)/net/,  \
                net_time.o \
                net_join.o \
                net_vampire.o \
-               net_user.o)
+               net_user.o \
+               net_export_keytab.o)
 
 
 $(eval $(call proto_header_template,$(utilssrcdir)/net/net_proto.h,$(net_OBJ_FILES:.o=.c)))
index d934403ade2105e23ca5c82030f52c87f5203e15..a96c672dfdc2ad664451c77a2a8376a04bf9f97b 100644 (file)
@@ -104,11 +104,11 @@ static const struct net_functable net_functable[] = {
        {"time", "get remote server's time\n", net_time, net_time_usage},
        {"join", "join a domain\n", net_join, net_join_usage},
        {"samdump", "dump the sam of a domain\n", net_samdump, net_samdump_usage},
+       {"export", "dump the sam of this domain\n", net_export, net_export_usage},
        {"vampire", "join and syncronise an AD domain onto the local server\n", net_vampire, net_vampire_usage},
        {"samsync", "synchronise into the local ldb the sam of an NT4 domain\n", net_samsync_ldb, net_samsync_ldb_usage},
        {"user", "manage user accounts\n", net_user, net_user_usage},
-       {"machinepw", "Get a machine password out of our SAM\n", net_machinepw,
-        net_machinepw_usage},
+       {"machinepw", "Get a machine password out of our SAM\n", net_machinepw, net_machinepw_usage},
        {NULL, NULL, NULL, NULL}
 };
 
diff --git a/source4/utils/net/net_export_keytab.c b/source4/utils/net/net_export_keytab.c
new file mode 100644 (file)
index 0000000..7f13278
--- /dev/null
@@ -0,0 +1,110 @@
+/* 
+   Samba Unix/Linux SMB client library 
+   Distributed SMB/CIFS Server Management Utility 
+
+   Copyright (C) 2004 Stefan Metzmacher <metze@samba.org>
+   Copyright (C) 2005 Andrew Bartlett <abartlet@samba.org>
+
+   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/net.h"
+#include "libnet/libnet.h"
+#include "param/param.h"
+
+static int net_export_keytab_usage(struct net_context *ctx, int argc, const char **argv)
+{
+       d_printf("net export keytab <keytab>\n");
+       return 0;       
+}
+
+static int net_export_keytab_help(struct net_context *ctx, int argc, const char **argv)
+{
+       d_printf("Dumps kerberos keys of the domain into a keytab.\n");
+       return 0;       
+}
+
+static int net_export_keytab(struct net_context *ctx, int argc, const char **argv) 
+{
+       NTSTATUS status;
+       struct libnet_context *libnetctx;
+       struct libnet_export_keytab r;
+
+       switch (argc) {
+       case 0:
+               return net_export_keytab_usage(ctx, argc, argv);
+               break;
+       case 1:
+               r.in.keytab_name = argv[0];
+               break;
+       }
+
+       libnetctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx);
+       if (!libnetctx) {
+               return -1;      
+       }
+       libnetctx->cred = ctx->credentials;
+
+       r.out.error_string = NULL;
+
+       status = libnet_export_keytab(libnetctx, ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("libnet_export_keytab returned %s: %s\n",
+                        nt_errstr(status),
+                        r.out.error_string));
+               return -1;
+       }
+
+       talloc_free(libnetctx);
+
+       return 0;
+}
+
+/* main function table */
+static const struct net_functable net_export_functable[] = {
+       {"keytab", "dump keys into a keytab\n", net_export_keytab, net_export_keytab_usage},
+       {NULL, NULL, NULL, NULL}
+};
+
+int net_export(struct net_context *ctx, int argc, const char **argv) 
+{
+       int rc;
+
+       switch (argc) {
+       case 0:
+               rc = net_export_usage(ctx, argc, argv);
+               return rc;
+       case 1:
+       default:
+               rc = net_run_function(ctx, argc, argv, net_export_functable, 
+                                     net_export_usage);
+               return rc;
+       }
+
+       return 0;
+}
+
+int net_export_usage(struct net_context *ctx, int argc, const char **argv)
+{
+       d_printf("net export keytab <keytab>\n");
+       return 0;       
+}
+
+int net_export_help(struct net_context *ctx, int argc, const char **argv)
+{
+       d_printf("Dumps the sam of the domain we are joined to.\n");
+       return 0;       
+}
+