mit-kdb: Add ks_create_principal().
[samba.git] / source4 / kdc / mit-kdb / kdb_samba_principals.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Samba KDB plugin for MIT Kerberos
5
6    Copyright (c) 2010      Simo Sorce <idra@samba.org>.
7    Copyright (c) 2014      Andreas Schneider <asn@samba.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24
25 #include "system/kerberos.h"
26
27 #include <profile.h>
28 #include <kdb.h>
29
30 #include "kdc/mit_samba.h"
31 #include "kdb_samba.h"
32
33 static krb5_error_code ks_get_principal(krb5_context context,
34                                         krb5_const_principal principal,
35                                         unsigned int kflags,
36                                         krb5_db_entry **kentry)
37 {
38         struct mit_samba_context *mit_ctx;
39         krb5_error_code code;
40
41         mit_ctx = ks_get_context(context);
42         if (mit_ctx == NULL) {
43                 return KRB5_KDB_DBNOTINITED;
44         }
45
46         code = mit_samba_get_principal(mit_ctx,
47                                        principal,
48                                        kflags,
49                                        kentry);
50         if (code != 0) {
51                 goto cleanup;
52         }
53
54 cleanup:
55
56         return code;
57 }
58
59 static krb5_boolean ks_is_master_key_principal(krb5_context context,
60                                                krb5_const_principal princ)
61 {
62         return krb5_princ_size(context, princ) == 2 &&
63                ks_data_eq_string(princ->data[0], "K") &&
64                ks_data_eq_string(princ->data[1], "M");
65 }
66
67 static krb5_error_code ks_get_master_key_principal(krb5_context context,
68                                                    krb5_const_principal princ,
69                                                    krb5_db_entry **kentry_ptr)
70 {
71         krb5_error_code code;
72         krb5_key_data *key_data;
73         krb5_timestamp now;
74         krb5_db_entry *kentry;
75
76         *kentry_ptr = NULL;
77
78         kentry = malloc(sizeof(krb5_db_entry));
79         if (kentry == NULL) {
80                 return ENOMEM;
81         }
82
83         ZERO_STRUCTP(kentry);
84
85         kentry->magic = KRB5_KDB_MAGIC_NUMBER;
86         kentry->len = KRB5_KDB_V1_BASE_LENGTH;
87         kentry->attributes = KRB5_KDB_DISALLOW_ALL_TIX;
88
89         if (princ == NULL) {
90                 code = krb5_parse_name(context, KRB5_KDB_M_NAME, &kentry->princ);
91         } else {
92                 code = krb5_copy_principal(context, princ, &kentry->princ);
93         }
94         if (code != 0) {
95                 ks_free_krb5_db_entry(context, kentry);
96                 return code;
97         }
98
99         now = time(NULL);
100
101         code = krb5_dbe_update_mod_princ_data(context, kentry, now, kentry->princ);
102         if (code != 0) {
103                 ks_free_krb5_db_entry(context, kentry);
104                 return code;
105         }
106
107         /* Return a dummy key */
108         kentry->n_key_data = 1;
109         kentry->key_data = malloc(sizeof(krb5_key_data));
110         if (code != 0) {
111                 ks_free_krb5_db_entry(context, kentry);
112                 return code;
113         }
114
115         key_data = &kentry->key_data[0];
116
117         key_data->key_data_ver          = KRB5_KDB_V1_KEY_DATA_ARRAY;
118         key_data->key_data_kvno         = 1;
119         key_data->key_data_type[0]      = ENCTYPE_UNKNOWN;
120         if (code != 0) {
121                 ks_free_krb5_db_entry(context, kentry);
122                 return code;
123         }
124
125         *kentry_ptr = kentry;
126
127         return 0;
128 }
129
130 static krb5_error_code ks_create_principal(krb5_context context,
131                                            krb5_const_principal princ,
132                                            int attributes,
133                                            int max_life,
134                                            const char *password,
135                                            krb5_db_entry **kentry_ptr)
136 {
137         krb5_error_code code;
138         krb5_key_data *key_data;
139         krb5_timestamp now;
140         krb5_db_entry *kentry;
141         krb5_keyblock key;
142         krb5_data salt;
143         krb5_data pwd;
144         int enctype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
145         int sts = KRB5_KDB_SALTTYPE_SPECIAL;
146
147         if (princ == NULL) {
148                 return KRB5_KDB_NOENTRY;
149         }
150
151         *kentry_ptr = NULL;
152
153         kentry = calloc(1, sizeof(krb5_db_entry));
154         if (kentry == NULL) {
155                 return ENOMEM;
156         }
157
158         ZERO_STRUCTP(kentry);
159
160         kentry->magic = KRB5_KDB_MAGIC_NUMBER;
161         kentry->len = KRB5_KDB_V1_BASE_LENGTH;
162
163         if (attributes > 0) {
164                 kentry->attributes = attributes;
165         }
166
167         if (max_life > 0) {
168                 kentry->max_life = max_life;
169         }
170
171         code = krb5_copy_principal(context, princ, &kentry->princ);
172         if (code != 0) {
173                 ks_free_krb5_db_entry(context, kentry);
174                 return code;
175         }
176
177         now = time(NULL);
178
179         code = krb5_dbe_update_mod_princ_data(context, kentry, now, kentry->princ);
180         if (code != 0) {
181                 ks_free_krb5_db_entry(context, kentry);
182                 return code;
183         }
184
185         code = mit_samba_generate_salt(&salt);
186         if (code != 0) {
187                 ks_free_krb5_db_entry(context, kentry);
188                 return code;
189         }
190
191         if (password != NULL) {
192                 pwd.data = strdup(password);
193                 pwd.length = strlen(password);
194         } else {
195                 /* create a random password */
196                 code = mit_samba_generate_random_password(&pwd);
197                 if (code != 0) {
198                         ks_free_krb5_db_entry(context, kentry);
199                         return code;
200                 }
201         }
202
203         code = krb5_c_string_to_key(context, enctype, &pwd, &salt, &key);
204         SAFE_FREE(pwd.data);
205         if (code != 0) {
206                 ks_free_krb5_db_entry(context, kentry);
207                 return code;
208         }
209
210         kentry->n_key_data = 1;
211         kentry->key_data = calloc(1, sizeof(krb5_key_data));
212         if (code != 0) {
213                 ks_free_krb5_db_entry(context, kentry);
214                 return code;
215         }
216
217         key_data = &kentry->key_data[0];
218
219         key_data->key_data_ver          = KRB5_KDB_V1_KEY_DATA_ARRAY;
220         key_data->key_data_kvno         = 1;
221         key_data->key_data_type[0]      = key.enctype;
222         key_data->key_data_length[0]    = key.length;
223         key_data->key_data_contents[0]  = key.contents;
224         key_data->key_data_type[1]      = sts;
225         key_data->key_data_length[1]    = salt.length;
226         key_data->key_data_contents[1]  = (krb5_octet*)salt.data;
227
228         *kentry_ptr = kentry;
229
230         return 0;
231 }
232
233 krb5_error_code kdb_samba_db_get_principal(krb5_context context,
234                                            krb5_const_principal princ,
235                                            unsigned int kflags,
236                                            krb5_db_entry **kentry)
237 {
238         struct mit_samba_context *mit_ctx;
239         krb5_error_code code;
240
241         mit_ctx = ks_get_context(context);
242         if (mit_ctx == NULL) {
243                 return KRB5_KDB_DBNOTINITED;
244         }
245
246         if (ks_is_master_key_principal(context, princ)) {
247                 return ks_get_master_key_principal(context, princ, kentry);
248         }
249
250         /* FIXME: temporarily fake up kadmin history to let kadmin.local work */
251         if (ks_is_kadmin_history(context, princ)) {
252                 return ks_get_dummy_principal(context, princ, kentry);
253         }
254
255         code = ks_get_principal(context, princ, kflags, kentry);
256
257         return code;
258 }
259
260 void kdb_samba_db_free_principal(krb5_context context,
261                                  krb5_db_entry *entry)
262 {
263         struct mit_samba_context *mit_ctx;
264
265         mit_ctx = ks_get_context(context);
266         if (mit_ctx == NULL) {
267                 return;
268         }
269
270         ks_free_krb5_db_entry(context, entry);
271 }
272
273 krb5_error_code kdb_samba_db_put_principal(krb5_context context,
274                                            krb5_db_entry *entry,
275                                            char **db_args)
276 {
277
278         /* NOTE: deferred, samba does not allow the KDC to store
279          * principals for now */
280         return KRB5_KDB_DB_INUSE;
281 }
282
283 krb5_error_code kdb_samba_db_delete_principal(krb5_context context,
284                                               krb5_const_principal princ)
285 {
286
287         /* NOTE: deferred, samba does not allow the KDC to delete
288          * principals for now */
289         return KRB5_KDB_DB_INUSE;
290 }
291
292 krb5_error_code kdb_samba_db_iterate(krb5_context context,
293                                      char *match_entry,
294                                      int (*func)(krb5_pointer, krb5_db_entry *),
295                                      krb5_pointer func_arg)
296 {
297         struct mit_samba_context *mit_ctx;
298         krb5_db_entry *kentry = NULL;
299         krb5_error_code code;
300
301
302         mit_ctx = ks_get_context(context);
303         if (mit_ctx == NULL) {
304                 return KRB5_KDB_DBNOTINITED;
305         }
306
307         code = mit_samba_get_firstkey(mit_ctx, &kentry);
308         while (code == 0) {
309                 code = (*func)(func_arg, kentry);
310                 if (code != 0) {
311                         break;
312                 }
313
314                 code = mit_samba_get_nextkey(mit_ctx, &kentry);
315         }
316
317         if (code == KRB5_KDB_NOENTRY) {
318                 code = 0;
319         }
320
321         return code;
322 }