s3:modules: call rpcgen only if vfs_nfs4acl_xattr is enabled
[Samba.git] / source4 / auth / kerberos / srv_keytab.c
blob52e1e2286694998be3395c68e20819edebfffe16
1 /*
2 Unix SMB/CIFS implementation.
4 Kerberos utility functions
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
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.
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.
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/>.
23 /**
24 * @file srv_keytab.c
26 * @brief Kerberos keytab utility functions
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"
37 static void keytab_principals_free(krb5_context context,
38 uint32_t num_principals,
39 krb5_principal *set)
41 uint32_t i;
43 for (i = 0; i < num_principals; i++) {
44 krb5_free_principal(context, set[i]);
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)
59 unsigned int i, p;
60 krb5_error_code ret;
61 krb5_data password;
62 char *unparsed;
64 password.data = discard_const_p(char, password_s);
65 password.length = strlen(password_s);
67 for (i = 0; enctypes[i]; i++) {
68 krb5_keytab_entry entry;
70 ZERO_STRUCT(entry);
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;
84 entry.vno = kvno;
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);
102 free(unparsed);
103 talloc_free(k5_error_string);
104 krb5_free_keyblock_contents(context,
105 KRB5_KT_KEY(&entry));
106 return ret;
109 DEBUG(5, ("Added key (kvno %d) to keytab (enctype %d)\n",
110 kvno, (int)enctypes[i]));
112 krb5_free_keyblock_contents(context, KRB5_KT_KEY(&entry));
114 return 0;
117 static krb5_error_code create_keytab(TALLOC_CTX *parent_ctx,
118 const char *samAccountName,
119 const char *realm,
120 const char *saltPrincipal,
121 int kvno,
122 const char *new_secret,
123 const char *old_secret,
124 uint32_t supp_enctypes,
125 uint32_t num_principals,
126 krb5_principal *principals,
127 krb5_context context,
128 krb5_keytab keytab,
129 bool add_old,
130 const char **perror_string)
132 krb5_error_code ret;
133 krb5_principal salt_princ = NULL;
134 krb5_enctype *enctypes;
135 TALLOC_CTX *mem_ctx;
136 const char *error_string = NULL;
138 if (!new_secret) {
139 /* There is no password here, so nothing to do */
140 return 0;
143 mem_ctx = talloc_new(parent_ctx);
144 if (!mem_ctx) {
145 *perror_string = talloc_strdup(parent_ctx,
146 "unable to allocate tmp_ctx for create_keytab");
147 return ENOMEM;
150 /* The salt used to generate these entries may be different however,
151 * fetch that */
152 ret = krb5_parse_name(context, saltPrincipal, &salt_princ);
153 if (ret) {
154 *perror_string = smb_get_krb5_error_message(context,
155 ret,
156 parent_ctx);
157 talloc_free(mem_ctx);
158 return ret;
161 ret = ms_suptypes_to_ietf_enctypes(mem_ctx, supp_enctypes, &enctypes);
162 if (ret) {
163 *perror_string = talloc_asprintf(parent_ctx,
164 "create_keytab: generating list of "
165 "encryption types failed (%s)\n",
166 smb_get_krb5_error_message(context,
167 ret, mem_ctx));
168 goto done;
171 ret = keytab_add_keys(mem_ctx,
172 num_principals,
173 principals,
174 salt_princ, kvno, new_secret,
175 context, enctypes, keytab, &error_string);
176 if (ret) {
177 *perror_string = talloc_steal(parent_ctx, error_string);
178 goto done;
181 if (old_secret && add_old && kvno != 0) {
182 ret = keytab_add_keys(mem_ctx,
183 num_principals,
184 principals,
185 salt_princ, kvno - 1, old_secret,
186 context, enctypes, keytab, &error_string);
187 if (ret) {
188 *perror_string = talloc_steal(parent_ctx, error_string);
192 done:
193 krb5_free_principal(context, salt_princ);
194 talloc_free(mem_ctx);
195 return ret;
199 * @brief Update a Kerberos keytab and removes any obsolete keytab entries.
201 * If the keytab does not exist, this function will create one.
203 * @param[in] parent_ctx Talloc memory context
204 * @param[in] context Kerberos context
205 * @param[in] keytab_name Keytab to open
206 * @param[in] samAccountName User account to update
207 * @param[in] realm Kerberos realm
208 * @param[in] SPNs Service principal names to update
209 * @param[in] num_SPNs Length of SPNs
210 * @param[in] saltPrincipal Salt used for AES encryption.
211 * Required, unless delete_all_kvno is set.
212 * @param[in] old_secret Old password
213 * @param[in] new_secret New password
214 * @param[in] kvno Current key version number
215 * @param[in] supp_enctypes msDS-SupportedEncryptionTypes bit-field
216 * @param[in] delete_all_kvno Removes all obsolete entries, without
217 * recreating the keytab.
218 * @param[out] _keytab If supplied, returns the keytab
219 * @param[out] perror_string Error string on failure
221 * @return 0 on success, errno on failure
223 krb5_error_code smb_krb5_update_keytab(TALLOC_CTX *parent_ctx,
224 krb5_context context,
225 const char *keytab_name,
226 const char *samAccountName,
227 const char *realm,
228 const char **SPNs,
229 int num_SPNs,
230 const char *saltPrincipal,
231 const char *new_secret,
232 const char *old_secret,
233 int kvno,
234 uint32_t supp_enctypes,
235 bool delete_all_kvno,
236 krb5_keytab *_keytab,
237 const char **perror_string)
239 krb5_keytab keytab;
240 krb5_error_code ret;
241 bool found_previous = false;
242 TALLOC_CTX *tmp_ctx;
243 krb5_principal *principals = NULL;
244 uint32_t num_principals = 0;
245 char *upper_realm;
246 const char *error_string = NULL;
248 if (keytab_name == NULL) {
249 return ENOENT;
252 ret = krb5_kt_resolve(context, keytab_name, &keytab);
253 if (ret) {
254 *perror_string = smb_get_krb5_error_message(context,
255 ret, parent_ctx);
256 return ret;
259 DEBUG(5, ("Opened keytab %s\n", keytab_name));
261 tmp_ctx = talloc_new(parent_ctx);
262 if (!tmp_ctx) {
263 *perror_string = talloc_strdup(parent_ctx,
264 "Failed to allocate memory context");
265 return ENOMEM;
268 upper_realm = strupper_talloc(tmp_ctx, realm);
269 if (upper_realm == NULL) {
270 *perror_string = talloc_strdup(parent_ctx,
271 "Cannot allocate memory to upper case realm");
272 talloc_free(tmp_ctx);
273 return ENOMEM;
276 ret = smb_krb5_create_principals_array(tmp_ctx,
277 context,
278 samAccountName,
279 upper_realm,
280 num_SPNs,
281 SPNs,
282 &num_principals,
283 &principals,
284 &error_string);
285 if (ret != 0) {
286 *perror_string = talloc_asprintf(parent_ctx,
287 "Failed to load principals from ldb message: %s\n",
288 error_string);
289 goto done;
292 ret = smb_krb5_remove_obsolete_keytab_entries(tmp_ctx,
293 context,
294 keytab,
295 num_principals,
296 principals,
297 kvno,
298 &found_previous,
299 &error_string);
300 if (ret != 0) {
301 *perror_string = talloc_asprintf(parent_ctx,
302 "Failed to remove old principals from keytab: %s\n",
303 error_string);
304 goto done;
307 if (!delete_all_kvno) {
308 /* Create a new keytab. If during the cleanout we found
309 * entries for kvno -1, then don't try and duplicate them.
310 * Otherwise, add kvno, and kvno -1 */
311 if (saltPrincipal == NULL) {
312 *perror_string = talloc_strdup(parent_ctx,
313 "No saltPrincipal provided");
314 ret = EINVAL;
315 goto done;
318 ret = create_keytab(tmp_ctx,
319 samAccountName, upper_realm, saltPrincipal,
320 kvno, new_secret, old_secret,
321 supp_enctypes,
322 num_principals,
323 principals,
324 context, keytab,
325 found_previous ? false : true,
326 &error_string);
327 if (ret) {
328 *perror_string = talloc_steal(parent_ctx, error_string);
332 if (ret == 0 && _keytab != NULL) {
333 /* caller wants the keytab handle back */
334 *_keytab = keytab;
337 done:
338 keytab_principals_free(context, num_principals, principals);
339 if (ret != 0 || _keytab == NULL) {
340 krb5_kt_close(context, keytab);
342 talloc_free(tmp_ctx);
343 return ret;
347 * @brief Wrapper around smb_krb5_update_keytab() for creating an in-memory keytab
349 * @param[in] parent_ctx Talloc memory context
350 * @param[in] context Kerberos context
351 * @param[in] new_secret New password
352 * @param[in] samAccountName User account to update
353 * @param[in] realm Kerberos realm
354 * @param[in] salt_principal Salt used for AES encryption.
355 * Required, unless delete_all_kvno is set.
356 * @param[in] kvno Current key version number
357 * @param[out] keytab If supplied, returns the keytab
358 * @param[out] keytab_name Returns the created keytab name
360 * @return 0 on success, errno on failure
362 krb5_error_code smb_krb5_create_memory_keytab(TALLOC_CTX *parent_ctx,
363 krb5_context context,
364 const char *new_secret,
365 const char *samAccountName,
366 const char *realm,
367 const char *salt_principal,
368 int kvno,
369 krb5_keytab *keytab,
370 const char **keytab_name)
372 krb5_error_code ret;
373 TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
374 const char *rand_string;
375 const char *error_string = NULL;
376 if (!mem_ctx) {
377 return ENOMEM;
380 rand_string = generate_random_str(mem_ctx, 16);
381 if (!rand_string) {
382 talloc_free(mem_ctx);
383 return ENOMEM;
386 *keytab_name = talloc_asprintf(mem_ctx, "MEMORY:%s", rand_string);
387 if (*keytab_name == NULL) {
388 talloc_free(mem_ctx);
389 return ENOMEM;
392 ret = smb_krb5_update_keytab(mem_ctx, context,
393 *keytab_name, samAccountName, realm,
394 NULL, 0, salt_principal, new_secret, NULL,
395 kvno, ENC_ALL_TYPES,
396 false, keytab, &error_string);
397 if (ret == 0) {
398 talloc_steal(parent_ctx, *keytab_name);
399 } else {
400 DEBUG(0, ("Failed to create in-memory keytab: %s\n",
401 error_string));
402 *keytab_name = NULL;
404 talloc_free(mem_ctx);
405 return ret;