samldb: Allow automatic generation of mAPIIDs
[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_kt_open_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         if (copy_one_principal) {
60                 krb5_principal k5_princ;
61
62                 code = smb_krb5_parse_name(context, principal, &k5_princ);
63                 if (code != 0) {
64                         *error_string = smb_get_krb5_error_message(context,
65                                                                    code,
66                                                                    mem_ctx);
67                         status = NT_STATUS_UNSUCCESSFUL;
68                         goto done;
69                 }
70
71                 code = samba_kdc_fetch(context, db_ctx, k5_princ,
72                                        SDB_F_GET_ANY, 0, &sentry);
73
74                 krb5_free_principal(context, k5_princ);
75         } else {
76                 code = samba_kdc_firstkey(context, db_ctx, &sentry);
77         }
78
79         for (; code == 0; code = samba_kdc_nextkey(context, db_ctx, &sentry)) {
80                 int i;
81
82                 code = krb5_unparse_name(context,
83                                          sentry.entry.principal,
84                                          &entry_principal);
85                 if (code != 0) {
86                         *error_string = smb_get_krb5_error_message(context,
87                                                                    code,
88                                                                    mem_ctx);
89                         status = NT_STATUS_UNSUCCESSFUL;
90                         goto done;
91                 }
92
93                 if (sentry.entry.keys.len == 0) {
94                         SAFE_FREE(entry_principal);
95                         sdb_free_entry(&sentry);
96                         sentry = (struct sdb_entry_ex) {
97                                 .free_entry = NULL,
98                         };
99
100                         continue;
101                 }
102
103                 for (i = 0; i < sentry.entry.keys.len; i++) {
104                         struct sdb_key *s = &(sentry.entry.keys.val[i]);
105                         krb5_enctype enctype;
106
107                         enctype = KRB5_KEY_TYPE(&(s->key));
108                         password.length = KRB5_KEY_LENGTH(&s->key);
109                         password.data = (char *)KRB5_KEY_DATA(&s->key);
110
111                         DBG_INFO("smb_krb5_kt_add_entry for enctype=0x%04x\n",
112                                   (int)enctype);
113                         code = smb_krb5_kt_add_entry(context,
114                                                      keytab,
115                                                      sentry.entry.kvno,
116                                                      entry_principal,
117                                                      NULL,
118                                                      enctype,
119                                                      &password,
120                                                      true,    /* no_salt */
121                                                      false);  /* keeyp_old_entries */
122                         if (code != 0) {
123                                 status = NT_STATUS_UNSUCCESSFUL;
124                                 *error_string = smb_get_krb5_error_message(context,
125                                                                            code,
126                                                                            mem_ctx);
127                                 DEBUG(0, ("smb_krb5_kt_add_entry failed code=%d, error = %s\n",
128                                           code, *error_string));
129                                 goto done;
130                         }
131                 }
132
133                 if (copy_one_principal) {
134                         break;
135                 }
136
137                 SAFE_FREE(entry_principal);
138                 sdb_free_entry(&sentry);
139                 sentry = (struct sdb_entry_ex) {
140                         .free_entry = NULL,
141                 };
142         }
143
144         if (code != 0 && code != SDB_ERR_NOENTRY) {
145                 *error_string = smb_get_krb5_error_message(context,
146                                                            code,
147                                                            mem_ctx);
148                 status = NT_STATUS_NO_SUCH_USER;
149                 goto done;
150         }
151
152         status = NT_STATUS_OK;
153 done:
154         SAFE_FREE(entry_principal);
155         sdb_free_entry(&sentry);
156
157         return status;
158 }
159
160 NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r)
161 {
162         krb5_error_code ret;
163         struct smb_krb5_context *smb_krb5_context;
164         struct samba_kdc_base_context *base_ctx;
165         struct samba_kdc_db_context *db_ctx = NULL;
166         const char *error_string = NULL;
167         NTSTATUS status;
168
169         ret = smb_krb5_init_context(ctx, ctx->lp_ctx, &smb_krb5_context);
170         if (ret) {
171                 return NT_STATUS_NO_MEMORY; 
172         }
173
174         base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context);
175         if (base_ctx == NULL) {
176                 return NT_STATUS_NO_MEMORY;
177         }
178
179         base_ctx->ev_ctx = ctx->event_ctx;
180         base_ctx->lp_ctx = ctx->lp_ctx;
181
182         status = samba_kdc_setup_db_ctx(mem_ctx, base_ctx, &db_ctx);
183         if (!NT_STATUS_IS_OK(status)) {
184                 return status;
185         }
186
187         if (r->in.principal != NULL) {
188                 DEBUG(0, ("Export one principal to %s\n", r->in.keytab_name));
189                 status = sdb_kt_copy(mem_ctx,
190                                      smb_krb5_context->krb5_context,
191                                      db_ctx,
192                                      r->in.keytab_name,
193                                      r->in.principal,
194                                      &error_string);
195         } else {
196                 unlink(r->in.keytab_name);
197                 DEBUG(0, ("Export complete keytab to %s\n", r->in.keytab_name));
198                 status = sdb_kt_copy(mem_ctx,
199                                      smb_krb5_context->krb5_context,
200                                      db_ctx,
201                                      r->in.keytab_name,
202                                      NULL,
203                                      &error_string);
204         }
205
206         talloc_free(db_ctx);
207         talloc_free(base_ctx);
208
209         if (!NT_STATUS_IS_OK(status)) {
210                 r->out.error_string = error_string;
211         }
212
213         return status;
214 }