Line data Source code
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 332 : static void keytab_principals_free(krb5_context context,
38 : uint32_t num_principals,
39 : krb5_principal *set)
40 : {
41 26 : uint32_t i;
42 :
43 1146 : for (i = 0; i < num_principals; i++) {
44 814 : krb5_free_principal(context, set[i]);
45 : }
46 306 : }
47 :
48 329 : 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 26 : unsigned int i, p;
60 26 : krb5_error_code ret;
61 26 : krb5_data password;
62 26 : char *unparsed;
63 :
64 329 : password.data = discard_const_p(char, password_s);
65 329 : password.length = strlen(password_s);
66 :
67 1316 : for (i = 0; enctypes[i]; i++) {
68 78 : krb5_keytab_entry entry;
69 :
70 987 : ZERO_STRUCT(entry);
71 :
72 987 : ret = smb_krb5_create_key_from_string(context,
73 : salt_princ,
74 : NULL,
75 : &password,
76 909 : enctypes[i],
77 : KRB5_KT_KEY(&entry));
78 987 : if (ret != 0) {
79 0 : *error_string = talloc_strdup(parent_ctx,
80 : "Failed to create key from string");
81 0 : return ret;
82 : }
83 :
84 987 : entry.vno = kvno;
85 :
86 3411 : for (p = 0; p < num_principals; p++) {
87 2424 : unparsed = NULL;
88 2424 : entry.principal = principals[p];
89 2424 : ret = krb5_kt_add_entry(context, keytab, &entry);
90 2424 : if (ret != 0) {
91 0 : char *k5_error_string =
92 0 : smb_get_krb5_error_message(context,
93 : ret, NULL);
94 0 : krb5_unparse_name(context,
95 0 : principals[p], &unparsed);
96 0 : *error_string = talloc_asprintf(parent_ctx,
97 : "Failed to add enctype %d entry for "
98 : "%s(kvno %d) to keytab: %s\n",
99 0 : (int)enctypes[i], unparsed,
100 : kvno, k5_error_string);
101 :
102 0 : free(unparsed);
103 0 : talloc_free(k5_error_string);
104 0 : krb5_free_keyblock_contents(context,
105 : KRB5_KT_KEY(&entry));
106 0 : return ret;
107 : }
108 :
109 2424 : DEBUG(5, ("Added key (kvno %d) to keytab (enctype %d)\n",
110 : kvno, (int)enctypes[i]));
111 : }
112 987 : krb5_free_keyblock_contents(context, KRB5_KT_KEY(&entry));
113 : }
114 303 : return 0;
115 : }
116 :
117 330 : 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)
131 : {
132 26 : krb5_error_code ret;
133 330 : krb5_principal salt_princ = NULL;
134 26 : krb5_enctype *enctypes;
135 26 : TALLOC_CTX *mem_ctx;
136 330 : const char *error_string = NULL;
137 :
138 330 : if (!new_secret) {
139 : /* There is no password here, so nothing to do */
140 1 : return 0;
141 : }
142 :
143 329 : mem_ctx = talloc_new(parent_ctx);
144 329 : if (!mem_ctx) {
145 0 : *perror_string = talloc_strdup(parent_ctx,
146 : "unable to allocate tmp_ctx for create_keytab");
147 0 : return ENOMEM;
148 : }
149 :
150 : /* The salt used to generate these entries may be different however,
151 : * fetch that */
152 329 : ret = krb5_parse_name(context, saltPrincipal, &salt_princ);
153 329 : if (ret) {
154 0 : *perror_string = smb_get_krb5_error_message(context,
155 : ret,
156 : parent_ctx);
157 0 : talloc_free(mem_ctx);
158 0 : return ret;
159 : }
160 :
161 329 : ret = ms_suptypes_to_ietf_enctypes(mem_ctx, supp_enctypes, &enctypes);
162 329 : if (ret) {
163 0 : *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 0 : goto done;
169 : }
170 :
171 329 : ret = keytab_add_keys(mem_ctx,
172 : num_principals,
173 : principals,
174 : salt_princ, kvno, new_secret,
175 : context, enctypes, keytab, &error_string);
176 329 : if (ret) {
177 0 : *perror_string = talloc_steal(parent_ctx, error_string);
178 0 : goto done;
179 : }
180 :
181 329 : if (old_secret && add_old && kvno != 0) {
182 0 : 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 0 : if (ret) {
188 0 : *perror_string = talloc_steal(parent_ctx, error_string);
189 : }
190 : }
191 :
192 329 : done:
193 329 : krb5_free_principal(context, salt_princ);
194 329 : talloc_free(mem_ctx);
195 329 : return ret;
196 : }
197 :
198 : /**
199 : * @brief Update a Kerberos keytab and removes any obsolete keytab entries.
200 : *
201 : * If the keytab does not exist, this function will create one.
202 : *
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
220 : *
221 : * @return 0 on success, errno on failure
222 : */
223 332 : 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)
238 : {
239 332 : krb5_keytab keytab = NULL;
240 26 : krb5_error_code ret;
241 332 : bool found_previous = false;
242 332 : TALLOC_CTX *tmp_ctx = NULL;
243 332 : krb5_principal *principals = NULL;
244 332 : uint32_t num_principals = 0;
245 26 : char *upper_realm;
246 332 : const char *error_string = NULL;
247 :
248 332 : if (keytab_name == NULL) {
249 0 : return ENOENT;
250 : }
251 :
252 332 : ret = krb5_kt_resolve(context, keytab_name, &keytab);
253 332 : if (ret) {
254 0 : *perror_string = smb_get_krb5_error_message(context,
255 : ret, parent_ctx);
256 0 : return ret;
257 : }
258 :
259 332 : DEBUG(5, ("Opened keytab %s\n", keytab_name));
260 :
261 332 : tmp_ctx = talloc_new(parent_ctx);
262 332 : if (!tmp_ctx) {
263 0 : *perror_string = talloc_strdup(parent_ctx,
264 : "Failed to allocate memory context");
265 0 : ret = ENOMEM;
266 0 : goto done;
267 : }
268 :
269 332 : upper_realm = strupper_talloc(tmp_ctx, realm);
270 332 : if (upper_realm == NULL) {
271 0 : *perror_string = talloc_strdup(parent_ctx,
272 : "Cannot allocate memory to upper case realm");
273 0 : ret = ENOMEM;
274 0 : goto done;
275 : }
276 :
277 332 : ret = smb_krb5_create_principals_array(tmp_ctx,
278 : context,
279 : samAccountName,
280 : upper_realm,
281 : num_SPNs,
282 : SPNs,
283 : &num_principals,
284 : &principals,
285 : &error_string);
286 332 : if (ret != 0) {
287 0 : *perror_string = talloc_asprintf(parent_ctx,
288 : "Failed to load principals from ldb message: %s\n",
289 : error_string);
290 0 : goto done;
291 : }
292 :
293 332 : ret = smb_krb5_remove_obsolete_keytab_entries(tmp_ctx,
294 : context,
295 : keytab,
296 : num_principals,
297 : principals,
298 : kvno,
299 : &found_previous,
300 : &error_string);
301 332 : if (ret != 0) {
302 0 : *perror_string = talloc_asprintf(parent_ctx,
303 : "Failed to remove old principals from keytab: %s\n",
304 : error_string);
305 0 : goto done;
306 : }
307 :
308 332 : if (!delete_all_kvno) {
309 : /* Create a new keytab. If during the cleanout we found
310 : * entries for kvno -1, then don't try and duplicate them.
311 : * Otherwise, add kvno, and kvno -1 */
312 330 : if (saltPrincipal == NULL) {
313 0 : *perror_string = talloc_strdup(parent_ctx,
314 : "No saltPrincipal provided");
315 0 : ret = EINVAL;
316 0 : goto done;
317 : }
318 :
319 356 : ret = create_keytab(tmp_ctx,
320 : samAccountName, upper_realm, saltPrincipal,
321 : kvno, new_secret, old_secret,
322 : supp_enctypes,
323 : num_principals,
324 : principals,
325 : context, keytab,
326 330 : found_previous ? false : true,
327 : &error_string);
328 330 : if (ret) {
329 0 : *perror_string = talloc_steal(parent_ctx, error_string);
330 : }
331 : }
332 :
333 332 : if (ret == 0 && _keytab != NULL) {
334 : /* caller wants the keytab handle back */
335 81 : *_keytab = keytab;
336 : }
337 :
338 251 : done:
339 332 : keytab_principals_free(context, num_principals, principals);
340 332 : if (ret != 0 || _keytab == NULL) {
341 251 : krb5_kt_close(context, keytab);
342 : }
343 332 : talloc_free(tmp_ctx);
344 332 : return ret;
345 : }
346 :
347 : /**
348 : * @brief Wrapper around smb_krb5_update_keytab() for creating an in-memory keytab
349 : *
350 : * @param[in] parent_ctx Talloc memory context
351 : * @param[in] context Kerberos context
352 : * @param[in] new_secret New password
353 : * @param[in] samAccountName User account to update
354 : * @param[in] realm Kerberos realm
355 : * @param[in] salt_principal Salt used for AES encryption.
356 : * Required, unless delete_all_kvno is set.
357 : * @param[in] kvno Current key version number
358 : * @param[out] keytab If supplied, returns the keytab
359 : * @param[out] keytab_name Returns the created keytab name
360 : *
361 : * @return 0 on success, errno on failure
362 : */
363 81 : krb5_error_code smb_krb5_create_memory_keytab(TALLOC_CTX *parent_ctx,
364 : krb5_context context,
365 : const char *new_secret,
366 : const char *samAccountName,
367 : const char *realm,
368 : const char *salt_principal,
369 : int kvno,
370 : krb5_keytab *keytab,
371 : const char **keytab_name)
372 : {
373 0 : krb5_error_code ret;
374 81 : TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
375 0 : const char *rand_string;
376 81 : const char *error_string = NULL;
377 81 : if (!mem_ctx) {
378 0 : return ENOMEM;
379 : }
380 :
381 81 : rand_string = generate_random_str(mem_ctx, 16);
382 81 : if (!rand_string) {
383 0 : talloc_free(mem_ctx);
384 0 : return ENOMEM;
385 : }
386 :
387 81 : *keytab_name = talloc_asprintf(mem_ctx, "MEMORY:%s", rand_string);
388 81 : if (*keytab_name == NULL) {
389 0 : talloc_free(mem_ctx);
390 0 : return ENOMEM;
391 : }
392 :
393 81 : ret = smb_krb5_update_keytab(mem_ctx, context,
394 : *keytab_name, samAccountName, realm,
395 : NULL, 0, salt_principal, new_secret, NULL,
396 : kvno, ENC_ALL_TYPES,
397 : false, keytab, &error_string);
398 81 : if (ret == 0) {
399 81 : talloc_steal(parent_ctx, *keytab_name);
400 : } else {
401 0 : DEBUG(0, ("Failed to create in-memory keytab: %s\n",
402 : error_string));
403 0 : *keytab_name = NULL;
404 : }
405 81 : talloc_free(mem_ctx);
406 81 : return ret;
407 : }
|