source: trunk/server/source4/auth/credentials/credentials_krb5.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 23.1 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Handle user credentials (as regards krb5)
5
6 Copyright (C) Jelmer Vernooij 2005
7 Copyright (C) Tim Potter 2001
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#include "includes.h"
25#include "system/kerberos.h"
26#include "auth/kerberos/kerberos.h"
27#include "auth/credentials/credentials.h"
28#include "auth/credentials/credentials_proto.h"
29#include "auth/credentials/credentials_krb5.h"
30#include "auth/kerberos/kerberos_credentials.h"
31#include "auth/kerberos/kerberos_util.h"
32#include "param/param.h"
33
34_PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred,
35 struct loadparm_context *lp_ctx,
36 struct smb_krb5_context **smb_krb5_context)
37{
38 int ret;
39 if (cred->smb_krb5_context) {
40 *smb_krb5_context = cred->smb_krb5_context;
41 return 0;
42 }
43
44 ret = smb_krb5_init_context(cred, NULL, lp_ctx,
45 &cred->smb_krb5_context);
46 if (ret) {
47 cred->smb_krb5_context = NULL;
48 return ret;
49 }
50 *smb_krb5_context = cred->smb_krb5_context;
51 return 0;
52}
53
54/* For most predictable behaviour, this needs to be called directly after the cli_credentials_init(),
55 * otherwise we may still have references to the old smb_krb5_context in a credential cache etc
56 */
57_PUBLIC_ NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred,
58 struct smb_krb5_context *smb_krb5_context)
59{
60 if (smb_krb5_context == NULL) {
61 talloc_unlink(cred, cred->smb_krb5_context);
62 cred->smb_krb5_context = NULL;
63 return NT_STATUS_OK;
64 }
65
66 if (!talloc_reference(cred, smb_krb5_context)) {
67 return NT_STATUS_NO_MEMORY;
68 }
69 cred->smb_krb5_context = smb_krb5_context;
70 return NT_STATUS_OK;
71}
72
73static int cli_credentials_set_from_ccache(struct cli_credentials *cred,
74 struct ccache_container *ccache,
75 enum credentials_obtained obtained,
76 const char **error_string)
77{
78
79 krb5_principal princ;
80 krb5_error_code ret;
81 char *name;
82
83 if (cred->ccache_obtained > obtained) {
84 return 0;
85 }
86
87 ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context,
88 ccache->ccache, &princ);
89
90 if (ret) {
91 (*error_string) = talloc_asprintf(cred, "failed to get principal from ccache: %s\n",
92 smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context,
93 ret, cred));
94 return ret;
95 }
96
97 ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name);
98 if (ret) {
99 (*error_string) = talloc_asprintf(cred, "failed to unparse principal from ccache: %s\n",
100 smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context,
101 ret, cred));
102 return ret;
103 }
104
105 cli_credentials_set_principal(cred, name, obtained);
106
107 free(name);
108
109 krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ);
110
111 /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */
112 cred->ccache_obtained = obtained;
113
114 return 0;
115}
116
117/* Free a memory ccache */
118static int free_mccache(struct ccache_container *ccc)
119{
120 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache);
121
122 return 0;
123}
124
125/* Free a disk-based ccache */
126static int free_dccache(struct ccache_container *ccc) {
127 krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache);
128
129 return 0;
130}
131
132_PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred,
133 struct loadparm_context *lp_ctx,
134 const char *name,
135 enum credentials_obtained obtained,
136 const char **error_string)
137{
138 krb5_error_code ret;
139 krb5_principal princ;
140 struct ccache_container *ccc;
141 if (cred->ccache_obtained > obtained) {
142 return 0;
143 }
144
145 ccc = talloc(cred, struct ccache_container);
146 if (!ccc) {
147 (*error_string) = error_message(ENOMEM);
148 return ENOMEM;
149 }
150
151 ret = cli_credentials_get_krb5_context(cred, lp_ctx,
152 &ccc->smb_krb5_context);
153 if (ret) {
154 (*error_string) = error_message(ret);
155 talloc_free(ccc);
156 return ret;
157 }
158 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
159 talloc_free(ccc);
160 (*error_string) = error_message(ENOMEM);
161 return ENOMEM;
162 }
163
164 if (name) {
165 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
166 if (ret) {
167 (*error_string) = talloc_asprintf(cred, "failed to read krb5 ccache: %s: %s\n",
168 name,
169 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
170 ret, ccc));
171 talloc_free(ccc);
172 return ret;
173 }
174 } else {
175 ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
176 if (ret) {
177 (*error_string) = talloc_asprintf(cred, "failed to read default krb5 ccache: %s\n",
178 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
179 ret, ccc));
180 talloc_free(ccc);
181 return ret;
182 }
183 }
184
185 talloc_set_destructor(ccc, free_dccache);
186
187 ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
188
189 if (ret == 0) {
190 krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ);
191 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
192
193 if (ret) {
194 (*error_string) = error_message(ret);
195 return ret;
196 }
197
198 cred->ccache = ccc;
199 cred->ccache_obtained = obtained;
200 talloc_steal(cred, ccc);
201
202 cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
203 return 0;
204 }
205 return 0;
206}
207
208
209static int cli_credentials_new_ccache(struct cli_credentials *cred,
210 struct loadparm_context *lp_ctx,
211 char *ccache_name,
212 struct ccache_container **_ccc,
213 const char **error_string)
214{
215 bool must_free_cc_name = false;
216 krb5_error_code ret;
217 struct ccache_container *ccc = talloc(cred, struct ccache_container);
218 if (!ccc) {
219 return ENOMEM;
220 }
221
222 ret = cli_credentials_get_krb5_context(cred, lp_ctx,
223 &ccc->smb_krb5_context);
224 if (ret) {
225 talloc_free(ccc);
226 (*error_string) = talloc_asprintf(cred, "Failed to get krb5_context: %s",
227 error_message(ret));
228 return ret;
229 }
230 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
231 talloc_free(ccc);
232 (*error_string) = strerror(ENOMEM);
233 return ENOMEM;
234 }
235
236 if (!ccache_name) {
237 must_free_cc_name = true;
238 ccache_name = talloc_asprintf(ccc, "MEMORY:%p",
239 ccc);
240
241 if (!ccache_name) {
242 talloc_free(ccc);
243 (*error_string) = strerror(ENOMEM);
244 return ENOMEM;
245 }
246 }
247
248 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name,
249 &ccc->ccache);
250 if (ret) {
251 (*error_string) = talloc_asprintf(cred, "failed to resolve a krb5 ccache (%s): %s\n",
252 ccache_name,
253 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
254 ret, ccc));
255 talloc_free(ccache_name);
256 talloc_free(ccc);
257 return ret;
258 }
259
260 if (strncasecmp(ccache_name, "MEMORY:", 7) == 0) {
261 talloc_set_destructor(ccc, free_mccache);
262 } else {
263 talloc_set_destructor(ccc, free_dccache);
264 }
265
266 if (must_free_cc_name) {
267 talloc_free(ccache_name);
268 }
269
270 *_ccc = ccc;
271
272 return 0;
273}
274
275_PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
276 struct tevent_context *event_ctx,
277 struct loadparm_context *lp_ctx,
278 char *ccache_name,
279 struct ccache_container **ccc,
280 const char **error_string)
281{
282 krb5_error_code ret;
283 enum credentials_obtained obtained;
284
285 if (cred->machine_account_pending) {
286 cli_credentials_set_machine_account(cred, lp_ctx);
287 }
288
289 if (cred->ccache_obtained >= cred->ccache_threshold &&
290 cred->ccache_obtained > CRED_UNINITIALISED) {
291 *ccc = cred->ccache;
292 return 0;
293 }
294 if (cli_credentials_is_anonymous(cred)) {
295 (*error_string) = "Cannot get anonymous kerberos credentials";
296 return EINVAL;
297 }
298
299 ret = cli_credentials_new_ccache(cred, lp_ctx, ccache_name, ccc, error_string);
300 if (ret) {
301 return ret;
302 }
303
304 ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, event_ctx, (*ccc)->ccache, &obtained, error_string);
305 if (ret) {
306 return ret;
307 }
308
309 ret = cli_credentials_set_from_ccache(cred, *ccc,
310 obtained, error_string);
311
312 cred->ccache = *ccc;
313 cred->ccache_obtained = cred->principal_obtained;
314 if (ret) {
315 return ret;
316 }
317 cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
318 return 0;
319}
320
321_PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred,
322 struct tevent_context *event_ctx,
323 struct loadparm_context *lp_ctx,
324 struct ccache_container **ccc,
325 const char **error_string)
326{
327 return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string);
328}
329
330/* We have good reason to think the ccache in these credentials is invalid - blow it away */
331static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials *cred)
332{
333 if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
334 talloc_unlink(cred, cred->client_gss_creds);
335 cred->client_gss_creds = NULL;
336 }
337 cred->client_gss_creds_obtained = CRED_UNINITIALISED;
338}
339
340void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred,
341 enum credentials_obtained obtained)
342{
343 /* If the caller just changed the username/password etc, then
344 * any cached credentials are now invalid */
345 if (obtained >= cred->client_gss_creds_obtained) {
346 if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
347 talloc_unlink(cred, cred->client_gss_creds);
348 cred->client_gss_creds = NULL;
349 }
350 cred->client_gss_creds_obtained = CRED_UNINITIALISED;
351 }
352 /* Now that we know that the data is 'this specified', then
353 * don't allow something less 'known' to be returned as a
354 * ccache. Ie, if the username is on the commmand line, we
355 * don't want to later guess to use a file-based ccache */
356 if (obtained > cred->client_gss_creds_threshold) {
357 cred->client_gss_creds_threshold = obtained;
358 }
359}
360
361/* We have good reason to think this CCACHE is invalid. Blow it away */
362static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred)
363{
364 if (cred->ccache_obtained > CRED_UNINITIALISED) {
365 talloc_unlink(cred, cred->ccache);
366 cred->ccache = NULL;
367 }
368 cred->ccache_obtained = CRED_UNINITIALISED;
369
370 cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
371}
372
373_PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred,
374 enum credentials_obtained obtained)
375{
376 /* If the caller just changed the username/password etc, then
377 * any cached credentials are now invalid */
378 if (obtained >= cred->ccache_obtained) {
379 if (cred->ccache_obtained > CRED_UNINITIALISED) {
380 talloc_unlink(cred, cred->ccache);
381 cred->ccache = NULL;
382 }
383 cred->ccache_obtained = CRED_UNINITIALISED;
384 }
385 /* Now that we know that the data is 'this specified', then
386 * don't allow something less 'known' to be returned as a
387 * ccache. Ie, if the username is on the commmand line, we
388 * don't want to later guess to use a file-based ccache */
389 if (obtained > cred->ccache_threshold) {
390 cred->ccache_threshold = obtained;
391 }
392
393 cli_credentials_invalidate_client_gss_creds(cred,
394 obtained);
395}
396
397static int free_gssapi_creds(struct gssapi_creds_container *gcc)
398{
399 OM_uint32 min_stat, maj_stat;
400 maj_stat = gss_release_cred(&min_stat, &gcc->creds);
401 return 0;
402}
403
404_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
405 struct tevent_context *event_ctx,
406 struct loadparm_context *lp_ctx,
407 struct gssapi_creds_container **_gcc,
408 const char **error_string)
409{
410 int ret = 0;
411 OM_uint32 maj_stat, min_stat;
412 struct gssapi_creds_container *gcc;
413 struct ccache_container *ccache;
414 gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
415 krb5_enctype *etypes = NULL;
416
417 if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold &&
418 cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
419 *_gcc = cred->client_gss_creds;
420 return 0;
421 }
422
423 ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
424 &ccache, error_string);
425 if (ret) {
426 DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret)));
427 return ret;
428 }
429
430 gcc = talloc(cred, struct gssapi_creds_container);
431 if (!gcc) {
432 (*error_string) = error_message(ENOMEM);
433 return ENOMEM;
434 }
435
436 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
437 &gcc->creds);
438 if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) {
439 /* This CCACHE is no good. Ensure we don't use it again */
440 cli_credentials_unconditionally_invalidate_ccache(cred);
441
442 /* Now try again to get a ccache */
443 ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
444 &ccache, error_string);
445 if (ret) {
446 DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret)));
447 return ret;
448 }
449
450 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
451 &gcc->creds);
452
453 }
454
455 if (maj_stat) {
456 talloc_free(gcc);
457 if (min_stat) {
458 ret = min_stat;
459 } else {
460 ret = EINVAL;
461 }
462 (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret));
463 return ret;
464 }
465
466 /*
467 * transfer the enctypes from the smb_krb5_context to the gssapi layer
468 *
469 * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
470 * to configure the enctypes via the krb5.conf.
471 *
472 * And the gss_init_sec_context() creates it's own krb5_context and
473 * the TGS-REQ had all enctypes in it and only the ones configured
474 * and used for the AS-REQ, so it wasn't possible to disable the usage
475 * of AES keys.
476 */
477 min_stat = krb5_get_default_in_tkt_etypes(ccache->smb_krb5_context->krb5_context,
478 &etypes);
479 if (min_stat == 0) {
480 OM_uint32 num_ktypes;
481
482 for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++);
483
484 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds,
485 num_ktypes,
486 (int32_t *) etypes);
487 krb5_xfree (etypes);
488 if (maj_stat) {
489 talloc_free(gcc);
490 if (min_stat) {
491 ret = min_stat;
492 } else {
493 ret = EINVAL;
494 }
495 (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret));
496 return ret;
497 }
498 }
499
500 /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
501 maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
502 GSS_KRB5_CRED_NO_CI_FLAGS_X,
503 &empty_buffer);
504 if (maj_stat) {
505 talloc_free(gcc);
506 if (min_stat) {
507 ret = min_stat;
508 } else {
509 ret = EINVAL;
510 }
511 (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret));
512 return ret;
513 }
514
515 cred->client_gss_creds_obtained = cred->ccache_obtained;
516 talloc_set_destructor(gcc, free_gssapi_creds);
517 cred->client_gss_creds = gcc;
518 *_gcc = gcc;
519 return 0;
520}
521
522/**
523 Set a gssapi cred_id_t into the credentials system. (Client case)
524
525 This grabs the credentials both 'intact' and getting the krb5
526 ccache out of it. This routine can be generalised in future for
527 the case where we deal with GSSAPI mechs other than krb5.
528
529 On sucess, the caller must not free gssapi_cred, as it now belongs
530 to the credentials system.
531*/
532
533 int cli_credentials_set_client_gss_creds(struct cli_credentials *cred,
534 struct loadparm_context *lp_ctx,
535 gss_cred_id_t gssapi_cred,
536 enum credentials_obtained obtained,
537 const char **error_string)
538{
539 int ret;
540 OM_uint32 maj_stat, min_stat;
541 struct ccache_container *ccc;
542 struct gssapi_creds_container *gcc;
543 if (cred->client_gss_creds_obtained > obtained) {
544 return 0;
545 }
546
547 gcc = talloc(cred, struct gssapi_creds_container);
548 if (!gcc) {
549 (*error_string) = error_message(ENOMEM);
550 return ENOMEM;
551 }
552
553 ret = cli_credentials_new_ccache(cred, lp_ctx, NULL, &ccc, error_string);
554 if (ret != 0) {
555 return ret;
556 }
557
558 maj_stat = gss_krb5_copy_ccache(&min_stat,
559 gssapi_cred, ccc->ccache);
560 if (maj_stat) {
561 if (min_stat) {
562 ret = min_stat;
563 } else {
564 ret = EINVAL;
565 }
566 if (ret) {
567 (*error_string) = error_message(ENOMEM);
568 }
569 }
570
571 if (ret == 0) {
572 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
573 }
574 cred->ccache = ccc;
575 cred->ccache_obtained = obtained;
576 if (ret == 0) {
577 gcc->creds = gssapi_cred;
578 talloc_set_destructor(gcc, free_gssapi_creds);
579
580 /* set the clinet_gss_creds_obtained here, as it just
581 got set to UNINITIALISED by the calls above */
582 cred->client_gss_creds_obtained = obtained;
583 cred->client_gss_creds = gcc;
584 }
585 return ret;
586}
587
588/* Get the keytab (actually, a container containing the krb5_keytab)
589 * attached to this context. If this hasn't been done or set before,
590 * it will be generated from the password.
591 */
592_PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred,
593 struct loadparm_context *lp_ctx,
594 struct keytab_container **_ktc)
595{
596 krb5_error_code ret;
597 struct keytab_container *ktc;
598 struct smb_krb5_context *smb_krb5_context;
599 TALLOC_CTX *mem_ctx;
600
601 if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
602 cred->username_obtained))) {
603 *_ktc = cred->keytab;
604 return 0;
605 }
606
607 if (cli_credentials_is_anonymous(cred)) {
608 return EINVAL;
609 }
610
611 ret = cli_credentials_get_krb5_context(cred, lp_ctx,
612 &smb_krb5_context);
613 if (ret) {
614 return ret;
615 }
616
617 mem_ctx = talloc_new(cred);
618 if (!mem_ctx) {
619 return ENOMEM;
620 }
621
622 ret = smb_krb5_create_memory_keytab(mem_ctx, cred,
623 smb_krb5_context, &ktc);
624 if (ret) {
625 talloc_free(mem_ctx);
626 return ret;
627 }
628
629 cred->keytab_obtained = (MAX(cred->principal_obtained,
630 cred->username_obtained));
631
632 talloc_steal(cred, ktc);
633 cred->keytab = ktc;
634 *_ktc = cred->keytab;
635 talloc_free(mem_ctx);
636 return ret;
637}
638
639/* Given the name of a keytab (presumably in the format
640 * FILE:/etc/krb5.keytab), open it and attach it */
641
642_PUBLIC_ int cli_credentials_set_keytab_name(struct cli_credentials *cred,
643 struct loadparm_context *lp_ctx,
644 const char *keytab_name,
645 enum credentials_obtained obtained)
646{
647 krb5_error_code ret;
648 struct keytab_container *ktc;
649 struct smb_krb5_context *smb_krb5_context;
650 TALLOC_CTX *mem_ctx;
651
652 if (cred->keytab_obtained >= obtained) {
653 return 0;
654 }
655
656 ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
657 if (ret) {
658 return ret;
659 }
660
661 mem_ctx = talloc_new(cred);
662 if (!mem_ctx) {
663 return ENOMEM;
664 }
665
666 ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context,
667 keytab_name, &ktc);
668 if (ret) {
669 return ret;
670 }
671
672 cred->keytab_obtained = obtained;
673
674 talloc_steal(cred, ktc);
675 cred->keytab = ktc;
676 talloc_free(mem_ctx);
677
678 return ret;
679}
680
681/* Get server gss credentials (in gsskrb5, this means the keytab) */
682
683_PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
684 struct loadparm_context *lp_ctx,
685 struct gssapi_creds_container **_gcc)
686{
687 int ret = 0;
688 OM_uint32 maj_stat, min_stat;
689 struct gssapi_creds_container *gcc;
690 struct keytab_container *ktc;
691 struct smb_krb5_context *smb_krb5_context;
692 TALLOC_CTX *mem_ctx;
693 krb5_principal princ;
694 const char *error_string;
695 enum credentials_obtained obtained;
696
697 mem_ctx = talloc_new(cred);
698 if (!mem_ctx) {
699 return ENOMEM;
700 }
701
702 ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
703 if (ret) {
704 return ret;
705 }
706
707 ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string);
708 if (ret) {
709 DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n",
710 error_string));
711 talloc_free(mem_ctx);
712 return ret;
713 }
714
715 if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) {
716 talloc_free(mem_ctx);
717 *_gcc = cred->server_gss_creds;
718 return 0;
719 }
720
721 ret = cli_credentials_get_keytab(cred, lp_ctx, &ktc);
722 if (ret) {
723 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
724 return ret;
725 }
726
727 gcc = talloc(cred, struct gssapi_creds_container);
728 if (!gcc) {
729 talloc_free(mem_ctx);
730 return ENOMEM;
731 }
732
733 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
734 maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab,
735 &gcc->creds);
736 if (maj_stat) {
737 if (min_stat) {
738 ret = min_stat;
739 } else {
740 ret = EINVAL;
741 }
742 }
743 if (ret == 0) {
744 cred->server_gss_creds_obtained = cred->keytab_obtained;
745 talloc_set_destructor(gcc, free_gssapi_creds);
746 cred->server_gss_creds = gcc;
747 *_gcc = gcc;
748 }
749 talloc_free(mem_ctx);
750 return ret;
751}
752
753/**
754 * Set Kerberos KVNO
755 */
756
757_PUBLIC_ void cli_credentials_set_kvno(struct cli_credentials *cred,
758 int kvno)
759{
760 cred->kvno = kvno;
761}
762
763/**
764 * Return Kerberos KVNO
765 */
766
767_PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred)
768{
769 return cred->kvno;
770}
771
772
773const char *cli_credentials_get_salt_principal(struct cli_credentials *cred)
774{
775 return cred->salt_principal;
776}
777
778_PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal)
779{
780 talloc_free(cred->salt_principal);
781 cred->salt_principal = talloc_strdup(cred, principal);
782}
783
784/* The 'impersonate_principal' is used to allow on Kerberos principal
785 * (and it's associated keytab etc) to impersonate another. The
786 * ability to do this is controlled by the KDC, but it is generally
787 * permitted to impersonate anyone to yourself. This allows any
788 * member of the domain to get the groups of a user. This is also
789 * known as S4U2Self */
790
791const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred)
792{
793 return cred->impersonate_principal;
794}
795
796_PUBLIC_ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred, const char *principal)
797{
798 talloc_free(cred->impersonate_principal);
799 cred->impersonate_principal = talloc_strdup(cred, principal);
800}
801
802/* when impersonating for S4U2Self we need to set the target principal
803 * to ourself, as otherwise we would need additional rights.
804 * Similarly, we may only be authorized to do general impersonation to
805 * some particular services.
806 *
807 * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
808 *
809 * NULL means that tickets will be obtained for the krbtgt service.
810*/
811
812const char *cli_credentials_get_target_service(struct cli_credentials *cred)
813{
814 return cred->target_service;
815}
816
817_PUBLIC_ void cli_credentials_set_target_service(struct cli_credentials *cred, const char *target_service)
818{
819 talloc_free(cred->target_service);
820 cred->target_service = talloc_strdup(cred, target_service);
821}
822
Note: See TracBrowser for help on using the repository browser.