s4-libnet: Link dckeytab.so correctly when is AD DC enabled
[sfrench/samba-autobuild/.git] / source4 / libnet / libnet_export_keytab.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
5    Copyright (C) Andreas Schneider <asn@samba.org> 2016
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/kerberos.h"
23 #include "auth/kerberos/kerberos.h"
24 #include "kdc/samba_kdc.h"
25 #include "libnet/libnet_export_keytab.h"
26
27 #include "kdc/db-glue.h"
28 #include "kdc/sdb.h"
29
30 static NTSTATUS sdb_kt_copy(TALLOC_CTX *mem_ctx,
31                             krb5_context context,
32                             struct samba_kdc_db_context *db_ctx,
33                             const char *keytab_name,
34                             const char *principal,
35                             const char **error_string)
36 {
37         struct sdb_entry_ex sentry = {
38                 .free_entry = NULL,
39         };
40         krb5_keytab keytab;
41         krb5_error_code code = 0;
42         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
43         char *entry_principal = NULL;
44         bool copy_one_principal = (principal != NULL);
45         krb5_data password;
46
47         code = smb_krb5_open_keytab_relative(context,
48                                              keytab_name,
49                                              true, /* write_access */
50                                              &keytab);
51         if (code != 0) {
52                 *error_string = talloc_asprintf(mem_ctx,
53                                                 "Failed to open keytab: %s",
54                                                 keytab_name);
55                 status = NT_STATUS_NO_SUCH_FILE;
56                 goto done;
57         }
58
59         for (code = samba_kdc_firstkey(context, db_ctx, &sentry);
60              code == 0;
61              code = samba_kdc_nextkey(context, db_ctx, &sentry)) {
62                 bool principal_found = false;
63                 int i;
64
65                 code = krb5_unparse_name(context,
66                                          sentry.entry.principal,
67                                          &entry_principal);
68                 if (code != 0) {
69                         *error_string = smb_get_krb5_error_message(context,
70                                                                    code,
71                                                                    mem_ctx);
72                         status = NT_STATUS_UNSUCCESSFUL;
73                         goto done;
74                 }
75
76                 if (principal != NULL) {
77                         int cmp;
78
79                         cmp = strcmp(principal, entry_principal);
80                         if (cmp == 0) {
81                                 principal_found = true;
82                         }
83                 }
84
85                 if (sentry.entry.keys.len == 0 ||
86                     (copy_one_principal && !principal_found)) {
87                         SAFE_FREE(entry_principal);
88                         sdb_free_entry(&sentry);
89                         sentry = (struct sdb_entry_ex) {
90                                 .free_entry = NULL,
91                         };
92
93                         continue;
94                 }
95
96                 for (i = 0; i < sentry.entry.keys.len; i++) {
97                         struct sdb_key *s = &(sentry.entry.keys.val[i]);
98                         krb5_enctype enctype;
99
100                         enctype = KRB5_KEY_TYPE(&(s->key));
101                         password.length = KRB5_KEY_LENGTH(&s->key);
102                         password.data = (char *)KRB5_KEY_DATA(&s->key);
103
104                         DBG_INFO("smb_krb5_kt_add_entry for enctype=0x%04x\n",
105                                   (int)enctype);
106                         code = smb_krb5_kt_add_entry(context,
107                                                      keytab,
108                                                      sentry.entry.kvno,
109                                                      entry_principal,
110                                                      NULL,
111                                                      enctype,
112                                                      &password,
113                                                      true,    /* no_salt */
114                                                      false);  /* keeyp_old_entries */
115                         if (code != 0) {
116                                 status = NT_STATUS_UNSUCCESSFUL;
117                                 *error_string = smb_get_krb5_error_message(context,
118                                                                            code,
119                                                                            mem_ctx);
120                                 DEBUG(0, ("smb_krb5_kt_add_entry failed code=%d, error = %s\n",
121                                           code, *error_string));
122                                 goto done;
123                         }
124                 }
125
126                 if (principal_found) {
127                         break;
128                 }
129
130                 SAFE_FREE(entry_principal);
131                 sdb_free_entry(&sentry);
132                 sentry = (struct sdb_entry_ex) {
133                         .free_entry = NULL,
134                 };
135         }
136
137         if (code != 0 && code != SDB_ERR_NOENTRY) {
138                 *error_string = smb_get_krb5_error_message(context,
139                                                            code,
140                                                            mem_ctx);
141                 status = NT_STATUS_NO_SUCH_USER;
142                 goto done;
143         }
144
145         status = NT_STATUS_OK;
146 done:
147         SAFE_FREE(entry_principal);
148         sdb_free_entry(&sentry);
149
150         return status;
151 }
152
153 NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r)
154 {
155         krb5_error_code ret;
156         struct smb_krb5_context *smb_krb5_context;
157         struct samba_kdc_base_context *base_ctx;
158         struct samba_kdc_db_context *db_ctx = NULL;
159         const char *error_string = NULL;
160         NTSTATUS status;
161
162         ret = smb_krb5_init_context(ctx, ctx->lp_ctx, &smb_krb5_context);
163         if (ret) {
164                 return NT_STATUS_NO_MEMORY; 
165         }
166
167         base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context);
168         if (base_ctx == NULL) {
169                 return NT_STATUS_NO_MEMORY;
170         }
171
172         base_ctx->ev_ctx = ctx->event_ctx;
173         base_ctx->lp_ctx = ctx->lp_ctx;
174
175         status = samba_kdc_setup_db_ctx(mem_ctx, base_ctx, &db_ctx);
176         if (!NT_STATUS_IS_OK(status)) {
177                 return status;
178         }
179
180         if (r->in.principal != NULL) {
181                 DEBUG(0, ("Export one principal to %s\n", r->in.keytab_name));
182                 status = sdb_kt_copy(mem_ctx,
183                                      smb_krb5_context->krb5_context,
184                                      db_ctx,
185                                      r->in.keytab_name,
186                                      r->in.principal,
187                                      &error_string);
188         } else {
189                 unlink(r->in.keytab_name);
190                 DEBUG(0, ("Export complete keytab to %s\n", r->in.keytab_name));
191                 status = sdb_kt_copy(mem_ctx,
192                                      smb_krb5_context->krb5_context,
193                                      db_ctx,
194                                      r->in.keytab_name,
195                                      NULL,
196                                      &error_string);
197         }
198
199         talloc_free(db_ctx);
200         talloc_free(base_ctx);
201
202         if (!NT_STATUS_IS_OK(status)) {
203                 r->out.error_string = error_string;
204         }
205
206         return status;
207 }