s4-auth/kerberos: Remove unused paremters to create_keytab()
[samba.git] / source4 / auth / kerberos / srv_keytab.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Kerberos utility functions
5
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
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 /**
24  * @file srv_keytab.c
25  *
26  * @brief Kerberos keytab utility functions
27  *
28  */
29
30 #include "includes.h"
31 #include "system/kerberos.h"
32 #include "auth/credentials/credentials.h"
33 #include "auth/kerberos/kerberos.h"
34 #include "auth/kerberos/kerberos_util.h"
35 #include "auth/kerberos/kerberos_srv_keytab.h"
36
37 static void keytab_principals_free(krb5_context context,
38                                    uint32_t num_principals,
39                                    krb5_principal *set)
40 {
41         uint32_t i;
42
43         for (i = 0; i < num_principals; i++) {
44                 krb5_free_principal(context, set[i]);
45         }
46 }
47
48 static krb5_error_code keytab_add_keys(TALLOC_CTX *parent_ctx,
49                                        uint32_t num_principals,
50                                        krb5_principal *principals,
51                                        krb5_principal salt_princ,
52                                        int kvno,
53                                        const char *password_s,
54                                        krb5_context context,
55                                        krb5_enctype *enctypes,
56                                        krb5_keytab keytab,
57                                        const char **error_string)
58 {
59         unsigned int i, p;
60         krb5_error_code ret;
61         krb5_data password;
62         char *unparsed;
63
64         password.data = discard_const_p(char, password_s);
65         password.length = strlen(password_s);
66
67         for (i = 0; enctypes[i]; i++) {
68                 krb5_keytab_entry entry;
69
70                 ZERO_STRUCT(entry);
71
72                 ret = smb_krb5_create_key_from_string(context,
73                                                       salt_princ,
74                                                       NULL,
75                                                       &password,
76                                                       enctypes[i],
77                                                       KRB5_KT_KEY(&entry));
78                 if (ret != 0) {
79                         *error_string = talloc_strdup(parent_ctx,
80                                                       "Failed to create key from string");
81                         return ret;
82                 }
83
84                 entry.vno = kvno;
85
86                 for (p = 0; p < num_principals; p++) {
87                         unparsed = NULL;
88                         entry.principal = principals[p];
89                         ret = krb5_kt_add_entry(context, keytab, &entry);
90                         if (ret != 0) {
91                                 char *k5_error_string =
92                                         smb_get_krb5_error_message(context,
93                                                                    ret, NULL);
94                                 krb5_unparse_name(context,
95                                                 principals[p], &unparsed);
96                                 *error_string = talloc_asprintf(parent_ctx,
97                                         "Failed to add enctype %d entry for "
98                                         "%s(kvno %d) to keytab: %s\n",
99                                         (int)enctypes[i], unparsed,
100                                         kvno, k5_error_string);
101
102                                 free(unparsed);
103                                 talloc_free(k5_error_string);
104                                 krb5_free_keyblock_contents(context,
105                                                             KRB5_KT_KEY(&entry));
106                                 return ret;
107                         }
108
109                         DEBUG(5, ("Added key (kvno %d) to keytab (enctype %d)\n",
110                                   kvno, (int)enctypes[i]));
111                 }
112                 krb5_free_keyblock_contents(context, KRB5_KT_KEY(&entry));
113         }
114         return 0;
115 }
116
117 static krb5_error_code create_keytab(TALLOC_CTX *parent_ctx,
118                                      const char *saltPrincipal,
119                                      int kvno,
120                                      const char *new_secret,
121                                      const char *old_secret,
122                                      uint32_t supp_enctypes,
123                                      uint32_t num_principals,
124                                      krb5_principal *principals,
125                                      krb5_context context,
126                                      krb5_keytab keytab,
127                                      bool add_old,
128                                      const char **perror_string)
129 {
130         krb5_error_code ret;
131         krb5_principal salt_princ = NULL;
132         krb5_enctype *enctypes;
133         TALLOC_CTX *mem_ctx;
134         const char *error_string = NULL;
135
136         if (!new_secret) {
137                 /* There is no password here, so nothing to do */
138                 return 0;
139         }
140
141         mem_ctx = talloc_new(parent_ctx);
142         if (!mem_ctx) {
143                 *perror_string = talloc_strdup(parent_ctx,
144                         "unable to allocate tmp_ctx for create_keytab");
145                 return ENOMEM;
146         }
147
148         /* The salt used to generate these entries may be different however,
149          * fetch that */
150         ret = krb5_parse_name(context, saltPrincipal, &salt_princ);
151         if (ret) {
152                 *perror_string = smb_get_krb5_error_message(context,
153                                                            ret,
154                                                            parent_ctx);
155                 talloc_free(mem_ctx);
156                 return ret;
157         }
158
159         ret = ms_suptypes_to_ietf_enctypes(mem_ctx, supp_enctypes, &enctypes);
160         if (ret) {
161                 *perror_string = talloc_asprintf(parent_ctx,
162                                         "create_keytab: generating list of "
163                                         "encryption types failed (%s)\n",
164                                         smb_get_krb5_error_message(context,
165                                                                 ret, mem_ctx));
166                 goto done;
167         }
168
169         ret = keytab_add_keys(mem_ctx,
170                               num_principals,
171                               principals,
172                               salt_princ, kvno, new_secret,
173                               context, enctypes, keytab, &error_string);
174         if (ret) {
175                 *perror_string = talloc_steal(parent_ctx, error_string);
176                 goto done;
177         }
178
179         if (old_secret && add_old && kvno != 0) {
180                 ret = keytab_add_keys(mem_ctx,
181                                       num_principals,
182                                       principals,
183                                       salt_princ, kvno - 1, old_secret,
184                                       context, enctypes, keytab, &error_string);
185                 if (ret) {
186                         *perror_string = talloc_steal(parent_ctx, error_string);
187                 }
188         }
189
190 done:
191         krb5_free_principal(context, salt_princ);
192         talloc_free(mem_ctx);
193         return ret;
194 }
195
196 /**
197  * @brief Update a Kerberos keytab and removes any obsolete keytab entries.
198  *
199  * If the keytab does not exist, this function will create one.
200  *
201  * @param[in] parent_ctx        Talloc memory context
202  * @param[in] context           Kerberos context
203  * @param[in] keytab_name       Keytab to open
204  * @param[in] samAccountName    User account to update
205  * @param[in] realm             Kerberos realm
206  * @param[in] SPNs              Service principal names to update
207  * @param[in] num_SPNs          Length of SPNs
208  * @param[in] saltPrincipal     Salt used for AES encryption.
209  *                              Required, unless delete_all_kvno is set.
210  * @param[in] old_secret        Old password
211  * @param[in] new_secret        New password
212  * @param[in] kvno              Current key version number
213  * @param[in] supp_enctypes     msDS-SupportedEncryptionTypes bit-field
214  * @param[in] delete_all_kvno   Removes all obsolete entries, without
215  *                              recreating the keytab.
216  * @param[out] _keytab          If supplied, returns the keytab
217  * @param[out] perror_string    Error string on failure
218  *
219  * @return                      0 on success, errno on failure
220  */
221 krb5_error_code smb_krb5_update_keytab(TALLOC_CTX *parent_ctx,
222                                 krb5_context context,
223                                 const char *keytab_name,
224                                 const char *samAccountName,
225                                 const char *realm,
226                                 const char **SPNs,
227                                 int num_SPNs,
228                                 const char *saltPrincipal,
229                                 const char *new_secret,
230                                 const char *old_secret,
231                                 int kvno,
232                                 uint32_t supp_enctypes,
233                                 bool delete_all_kvno,
234                                 krb5_keytab *_keytab,
235                                 const char **perror_string)
236 {
237         krb5_keytab keytab = NULL;
238         krb5_error_code ret;
239         bool found_previous = false;
240         TALLOC_CTX *tmp_ctx = NULL;
241         krb5_principal *principals = NULL;
242         uint32_t num_principals = 0;
243         char *upper_realm;
244         const char *error_string = NULL;
245
246         if (keytab_name == NULL) {
247                 return ENOENT;
248         }
249
250         ret = krb5_kt_resolve(context, keytab_name, &keytab);
251         if (ret) {
252                 *perror_string = smb_get_krb5_error_message(context,
253                                                            ret, parent_ctx);
254                 return ret;
255         }
256
257         DEBUG(5, ("Opened keytab %s\n", keytab_name));
258
259         tmp_ctx = talloc_new(parent_ctx);
260         if (!tmp_ctx) {
261                 *perror_string = talloc_strdup(parent_ctx,
262                                               "Failed to allocate memory context");
263                 ret = ENOMEM;
264                 goto done;
265         }
266
267         upper_realm = strupper_talloc(tmp_ctx, realm);
268         if (upper_realm == NULL) {
269                 *perror_string = talloc_strdup(parent_ctx,
270                                               "Cannot allocate memory to upper case realm");
271                 ret = ENOMEM;
272                 goto done;
273         }
274
275         ret = smb_krb5_create_principals_array(tmp_ctx,
276                                                context,
277                                                samAccountName,
278                                                upper_realm,
279                                                num_SPNs,
280                                                SPNs,
281                                                &num_principals,
282                                                &principals,
283                                                &error_string);
284         if (ret != 0) {
285                 *perror_string = talloc_asprintf(parent_ctx,
286                         "Failed to load principals from ldb message: %s\n",
287                         error_string);
288                 goto done;
289         }
290
291         ret = smb_krb5_remove_obsolete_keytab_entries(tmp_ctx,
292                                                       context,
293                                                       keytab,
294                                                       num_principals,
295                                                       principals,
296                                                       kvno,
297                                                       &found_previous,
298                                                       &error_string);
299         if (ret != 0) {
300                 *perror_string = talloc_asprintf(parent_ctx,
301                         "Failed to remove old principals from keytab: %s\n",
302                         error_string);
303                 goto done;
304         }
305
306         if (!delete_all_kvno) {
307                 /* Create a new keytab.  If during the cleanout we found
308                  * entries for kvno -1, then don't try and duplicate them.
309                  * Otherwise, add kvno, and kvno -1 */
310                 if (saltPrincipal == NULL) {
311                         *perror_string = talloc_strdup(parent_ctx,
312                                                        "No saltPrincipal provided");
313                         ret = EINVAL;
314                         goto done;
315                 }
316
317                 ret = create_keytab(tmp_ctx,
318                                     saltPrincipal,
319                                     kvno, new_secret, old_secret,
320                                     supp_enctypes,
321                                     num_principals,
322                                     principals,
323                                     context, keytab,
324                                     found_previous ? false : true,
325                                     &error_string);
326                 if (ret) {
327                         *perror_string = talloc_steal(parent_ctx, error_string);
328                 }
329         }
330
331         if (ret == 0 && _keytab != NULL) {
332                 /* caller wants the keytab handle back */
333                 *_keytab = keytab;
334         }
335
336 done:
337         keytab_principals_free(context, num_principals, principals);
338         if (ret != 0 || _keytab == NULL) {
339                 krb5_kt_close(context, keytab);
340         }
341         talloc_free(tmp_ctx);
342         return ret;
343 }
344
345 /**
346  * @brief Wrapper around smb_krb5_update_keytab() for creating an in-memory keytab
347  *
348  * @param[in] parent_ctx        Talloc memory context
349  * @param[in] context           Kerberos context
350  * @param[in] new_secret        New password
351  * @param[in] samAccountName    User account to update
352  * @param[in] realm             Kerberos realm
353  * @param[in] salt_principal    Salt used for AES encryption.
354  *                              Required, unless delete_all_kvno is set.
355  * @param[in] kvno              Current key version number
356  * @param[out] keytab           If supplied, returns the keytab
357  * @param[out] keytab_name      Returns the created keytab name
358  *
359  * @return                      0 on success, errno on failure
360  */
361 krb5_error_code smb_krb5_create_memory_keytab(TALLOC_CTX *parent_ctx,
362                                 krb5_context context,
363                                 const char *new_secret,
364                                 const char *samAccountName,
365                                 const char *realm,
366                                 const char *salt_principal,
367                                 int kvno,
368                                 krb5_keytab *keytab,
369                                 const char **keytab_name)
370 {
371         krb5_error_code ret;
372         TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
373         const char *rand_string;
374         const char *error_string = NULL;
375         if (!mem_ctx) {
376                 return ENOMEM;
377         }
378
379         rand_string = generate_random_str(mem_ctx, 16);
380         if (!rand_string) {
381                 talloc_free(mem_ctx);
382                 return ENOMEM;
383         }
384
385         *keytab_name = talloc_asprintf(mem_ctx, "MEMORY:%s", rand_string);
386         if (*keytab_name == NULL) {
387                 talloc_free(mem_ctx);
388                 return ENOMEM;
389         }
390
391         ret = smb_krb5_update_keytab(mem_ctx, context,
392                                      *keytab_name, samAccountName, realm,
393                                      NULL, 0, salt_principal, new_secret, NULL,
394                                      kvno, ENC_ALL_TYPES,
395                                      false, keytab, &error_string);
396         if (ret == 0) {
397                 talloc_steal(parent_ctx, *keytab_name);
398         } else {
399                 DEBUG(0, ("Failed to create in-memory keytab: %s\n",
400                           error_string));
401                 *keytab_name = NULL;
402         }
403         talloc_free(mem_ctx);
404         return ret;
405 }