2 Unix SMB/CIFS implementation.
4 Handle user credentials (as regards krb5)
6 Copyright (C) Jelmer Vernooij 2005
7 Copyright (C) Tim Potter 2001
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
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.
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.
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/>.
25 #include "system/kerberos.h"
26 #include "system/gssapi.h"
27 #include "auth/kerberos/kerberos.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/credentials/credentials_proto.h"
30 #include "auth/credentials/credentials_krb5.h"
31 #include "auth/kerberos/kerberos_credentials.h"
32 #include "auth/kerberos/kerberos_srv_keytab.h"
33 #include "auth/kerberos/kerberos_util.h"
34 #include "auth/kerberos/pac_utils.h"
35 #include "param/param.h"
37 static void cli_credentials_invalidate_client_gss_creds(
38 struct cli_credentials
*cred
,
39 enum credentials_obtained obtained
);
41 _PUBLIC_
int cli_credentials_get_krb5_context(struct cli_credentials
*cred
,
42 struct loadparm_context
*lp_ctx
,
43 struct smb_krb5_context
**smb_krb5_context
)
46 if (cred
->smb_krb5_context
) {
47 *smb_krb5_context
= cred
->smb_krb5_context
;
51 ret
= smb_krb5_init_context(cred
, NULL
, lp_ctx
,
52 &cred
->smb_krb5_context
);
54 cred
->smb_krb5_context
= NULL
;
57 *smb_krb5_context
= cred
->smb_krb5_context
;
61 /* For most predictable behaviour, this needs to be called directly after the cli_credentials_init(),
62 * otherwise we may still have references to the old smb_krb5_context in a credential cache etc
64 _PUBLIC_ NTSTATUS
cli_credentials_set_krb5_context(struct cli_credentials
*cred
,
65 struct smb_krb5_context
*smb_krb5_context
)
67 if (smb_krb5_context
== NULL
) {
68 talloc_unlink(cred
, cred
->smb_krb5_context
);
69 cred
->smb_krb5_context
= NULL
;
73 if (!talloc_reference(cred
, smb_krb5_context
)) {
74 return NT_STATUS_NO_MEMORY
;
76 cred
->smb_krb5_context
= smb_krb5_context
;
80 static int cli_credentials_set_from_ccache(struct cli_credentials
*cred
,
81 struct ccache_container
*ccache
,
82 enum credentials_obtained obtained
,
83 const char **error_string
)
90 if (cred
->ccache_obtained
> obtained
) {
94 ret
= krb5_cc_get_principal(ccache
->smb_krb5_context
->krb5_context
,
95 ccache
->ccache
, &princ
);
98 (*error_string
) = talloc_asprintf(cred
, "failed to get principal from ccache: %s\n",
99 smb_get_krb5_error_message(ccache
->smb_krb5_context
->krb5_context
,
104 ret
= krb5_unparse_name(ccache
->smb_krb5_context
->krb5_context
, princ
, &name
);
106 (*error_string
) = talloc_asprintf(cred
, "failed to unparse principal from ccache: %s\n",
107 smb_get_krb5_error_message(ccache
->smb_krb5_context
->krb5_context
,
112 cli_credentials_set_principal(cred
, name
, obtained
);
116 krb5_free_principal(ccache
->smb_krb5_context
->krb5_context
, princ
);
118 /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */
119 cred
->ccache_obtained
= obtained
;
124 /* Free a memory ccache */
125 static int free_mccache(struct ccache_container
*ccc
)
127 krb5_cc_destroy(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
);
132 /* Free a disk-based ccache */
133 static int free_dccache(struct ccache_container
*ccc
) {
134 krb5_cc_close(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
);
139 _PUBLIC_
int cli_credentials_set_ccache(struct cli_credentials
*cred
,
140 struct loadparm_context
*lp_ctx
,
142 enum credentials_obtained obtained
,
143 const char **error_string
)
146 krb5_principal princ
;
147 struct ccache_container
*ccc
;
148 if (cred
->ccache_obtained
> obtained
) {
152 ccc
= talloc(cred
, struct ccache_container
);
154 (*error_string
) = error_message(ENOMEM
);
158 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
,
159 &ccc
->smb_krb5_context
);
161 (*error_string
) = error_message(ret
);
165 if (!talloc_reference(ccc
, ccc
->smb_krb5_context
)) {
167 (*error_string
) = error_message(ENOMEM
);
172 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, name
, &ccc
->ccache
);
174 (*error_string
) = talloc_asprintf(cred
, "failed to read krb5 ccache: %s: %s\n",
176 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
182 ret
= krb5_cc_default(ccc
->smb_krb5_context
->krb5_context
, &ccc
->ccache
);
184 (*error_string
) = talloc_asprintf(cred
, "failed to read default krb5 ccache: %s\n",
185 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
192 talloc_set_destructor(ccc
, free_dccache
);
194 ret
= krb5_cc_get_principal(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
, &princ
);
197 krb5_free_principal(ccc
->smb_krb5_context
->krb5_context
, princ
);
198 ret
= cli_credentials_set_from_ccache(cred
, ccc
, obtained
, error_string
);
201 (*error_string
) = error_message(ret
);
206 cred
->ccache_obtained
= obtained
;
207 talloc_steal(cred
, ccc
);
209 cli_credentials_invalidate_client_gss_creds(cred
, cred
->ccache_obtained
);
216 static int cli_credentials_new_ccache(struct cli_credentials
*cred
,
217 struct loadparm_context
*lp_ctx
,
219 struct ccache_container
**_ccc
,
220 const char **error_string
)
222 bool must_free_cc_name
= false;
224 struct ccache_container
*ccc
= talloc(cred
, struct ccache_container
);
229 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
,
230 &ccc
->smb_krb5_context
);
233 (*error_string
) = talloc_asprintf(cred
, "Failed to get krb5_context: %s",
237 if (!talloc_reference(ccc
, ccc
->smb_krb5_context
)) {
239 (*error_string
) = strerror(ENOMEM
);
244 must_free_cc_name
= true;
246 if (lpcfg_parm_bool(lp_ctx
, NULL
, "credentials", "krb5_cc_file", false)) {
247 ccache_name
= talloc_asprintf(ccc
, "FILE:/tmp/krb5_cc_samba_%u_%p",
248 (unsigned int)getpid(), ccc
);
250 ccache_name
= talloc_asprintf(ccc
, "MEMORY:%p",
256 (*error_string
) = strerror(ENOMEM
);
261 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, ccache_name
,
264 (*error_string
) = talloc_asprintf(cred
, "failed to resolve a krb5 ccache (%s): %s\n",
266 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
268 talloc_free(ccache_name
);
273 if (strncasecmp(ccache_name
, "MEMORY:", 7) == 0) {
274 talloc_set_destructor(ccc
, free_mccache
);
276 talloc_set_destructor(ccc
, free_dccache
);
279 if (must_free_cc_name
) {
280 talloc_free(ccache_name
);
288 _PUBLIC_
int cli_credentials_get_named_ccache(struct cli_credentials
*cred
,
289 struct tevent_context
*event_ctx
,
290 struct loadparm_context
*lp_ctx
,
292 struct ccache_container
**ccc
,
293 const char **error_string
)
296 enum credentials_obtained obtained
;
298 if (cred
->machine_account_pending
) {
299 cli_credentials_set_machine_account(cred
, lp_ctx
);
302 if (cred
->ccache_obtained
>= cred
->ccache_threshold
&&
303 cred
->ccache_obtained
> CRED_UNINITIALISED
) {
305 bool expired
= false;
306 ret
= smb_krb5_cc_get_lifetime(cred
->ccache
->smb_krb5_context
->krb5_context
,
307 cred
->ccache
->ccache
, &lifetime
);
308 if (ret
== KRB5_CC_END
) {
309 /* If we have a particular ccache set, without
310 * an initial ticket, then assume there is a
312 } else if (ret
== 0) {
314 DEBUG(3, ("Ticket in credentials cache for %s expired, will refresh\n",
315 cli_credentials_get_principal(cred
, cred
)));
317 } else if (lifetime
< 300) {
318 DEBUG(3, ("Ticket in credentials cache for %s will shortly expire (%u secs), will refresh\n",
319 cli_credentials_get_principal(cred
, cred
), (unsigned int)lifetime
));
323 (*error_string
) = talloc_asprintf(cred
, "failed to get ccache lifetime: %s\n",
324 smb_get_krb5_error_message(cred
->ccache
->smb_krb5_context
->krb5_context
,
329 DEBUG(5, ("Ticket in credentials cache for %s will expire in %u secs\n",
330 cli_credentials_get_principal(cred
, cred
), (unsigned int)lifetime
));
337 if (cli_credentials_is_anonymous(cred
)) {
338 (*error_string
) = "Cannot get anonymous kerberos credentials";
342 ret
= cli_credentials_new_ccache(cred
, lp_ctx
, ccache_name
, ccc
, error_string
);
347 ret
= kinit_to_ccache(cred
, cred
, (*ccc
)->smb_krb5_context
, event_ctx
, (*ccc
)->ccache
, &obtained
, error_string
);
352 ret
= cli_credentials_set_from_ccache(cred
, *ccc
,
353 obtained
, error_string
);
356 cred
->ccache_obtained
= cred
->principal_obtained
;
360 cli_credentials_invalidate_client_gss_creds(cred
, cred
->ccache_obtained
);
364 _PUBLIC_
int cli_credentials_get_ccache(struct cli_credentials
*cred
,
365 struct tevent_context
*event_ctx
,
366 struct loadparm_context
*lp_ctx
,
367 struct ccache_container
**ccc
,
368 const char **error_string
)
370 return cli_credentials_get_named_ccache(cred
, event_ctx
, lp_ctx
, NULL
, ccc
, error_string
);
373 /* We have good reason to think the ccache in these credentials is invalid - blow it away */
374 static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials
*cred
)
376 if (cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
377 talloc_unlink(cred
, cred
->client_gss_creds
);
378 cred
->client_gss_creds
= NULL
;
380 cred
->client_gss_creds_obtained
= CRED_UNINITIALISED
;
383 void cli_credentials_invalidate_client_gss_creds(struct cli_credentials
*cred
,
384 enum credentials_obtained obtained
)
386 /* If the caller just changed the username/password etc, then
387 * any cached credentials are now invalid */
388 if (obtained
>= cred
->client_gss_creds_obtained
) {
389 if (cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
390 talloc_unlink(cred
, cred
->client_gss_creds
);
391 cred
->client_gss_creds
= NULL
;
393 cred
->client_gss_creds_obtained
= CRED_UNINITIALISED
;
395 /* Now that we know that the data is 'this specified', then
396 * don't allow something less 'known' to be returned as a
397 * ccache. Ie, if the username is on the command line, we
398 * don't want to later guess to use a file-based ccache */
399 if (obtained
> cred
->client_gss_creds_threshold
) {
400 cred
->client_gss_creds_threshold
= obtained
;
404 /* We have good reason to think this CCACHE is invalid. Blow it away */
405 static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials
*cred
)
407 if (cred
->ccache_obtained
> CRED_UNINITIALISED
) {
408 talloc_unlink(cred
, cred
->ccache
);
411 cred
->ccache_obtained
= CRED_UNINITIALISED
;
413 cli_credentials_unconditionally_invalidate_client_gss_creds(cred
);
416 _PUBLIC_
void cli_credentials_invalidate_ccache(struct cli_credentials
*cred
,
417 enum credentials_obtained obtained
)
419 /* If the caller just changed the username/password etc, then
420 * any cached credentials are now invalid */
421 if (obtained
>= cred
->ccache_obtained
) {
422 if (cred
->ccache_obtained
> CRED_UNINITIALISED
) {
423 talloc_unlink(cred
, cred
->ccache
);
426 cred
->ccache_obtained
= CRED_UNINITIALISED
;
428 /* Now that we know that the data is 'this specified', then
429 * don't allow something less 'known' to be returned as a
430 * ccache. i.e, if the username is on the command line, we
431 * don't want to later guess to use a file-based ccache */
432 if (obtained
> cred
->ccache_threshold
) {
433 cred
->ccache_threshold
= obtained
;
436 cli_credentials_invalidate_client_gss_creds(cred
,
440 static int free_gssapi_creds(struct gssapi_creds_container
*gcc
)
443 (void)gss_release_cred(&min_stat
, &gcc
->creds
);
447 _PUBLIC_
int cli_credentials_get_client_gss_creds(struct cli_credentials
*cred
,
448 struct tevent_context
*event_ctx
,
449 struct loadparm_context
*lp_ctx
,
450 struct gssapi_creds_container
**_gcc
,
451 const char **error_string
)
454 OM_uint32 maj_stat
, min_stat
;
455 struct gssapi_creds_container
*gcc
;
456 struct ccache_container
*ccache
;
457 gss_buffer_desc empty_buffer
= GSS_C_EMPTY_BUFFER
;
458 krb5_enctype
*etypes
= NULL
;
460 if (cred
->client_gss_creds_obtained
>= cred
->client_gss_creds_threshold
&&
461 cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
462 bool expired
= false;
463 OM_uint32 lifetime
= 0;
464 gss_cred_usage_t usage
= 0;
465 maj_stat
= gss_inquire_cred(&min_stat
, cred
->client_gss_creds
->creds
,
466 NULL
, &lifetime
, &usage
, NULL
);
467 if (maj_stat
== GSS_S_CREDENTIALS_EXPIRED
) {
468 DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred
, cred
)));
470 } else if (maj_stat
== GSS_S_COMPLETE
&& lifetime
< 300) {
471 DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred
, cred
), lifetime
));
473 } else if (maj_stat
!= GSS_S_COMPLETE
) {
474 *error_string
= talloc_asprintf(cred
, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
475 gssapi_error_string(cred
, maj_stat
, min_stat
, NULL
));
479 cli_credentials_unconditionally_invalidate_client_gss_creds(cred
);
481 DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n",
482 cli_credentials_get_principal(cred
, cred
), (unsigned int)lifetime
));
484 *_gcc
= cred
->client_gss_creds
;
489 ret
= cli_credentials_get_ccache(cred
, event_ctx
, lp_ctx
,
490 &ccache
, error_string
);
492 if (cli_credentials_get_kerberos_state(cred
) == CRED_MUST_USE_KERBEROS
) {
493 DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string
));
495 DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string
));
500 gcc
= talloc(cred
, struct gssapi_creds_container
);
502 (*error_string
) = error_message(ENOMEM
);
506 maj_stat
= gss_krb5_import_cred(&min_stat
, ccache
->ccache
, NULL
, NULL
,
508 if ((maj_stat
== GSS_S_FAILURE
) && (min_stat
== (OM_uint32
)KRB5_CC_END
|| min_stat
== (OM_uint32
) KRB5_CC_NOTFOUND
)) {
509 /* This CCACHE is no good. Ensure we don't use it again */
510 cli_credentials_unconditionally_invalidate_ccache(cred
);
512 /* Now try again to get a ccache */
513 ret
= cli_credentials_get_ccache(cred
, event_ctx
, lp_ctx
,
514 &ccache
, error_string
);
516 DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret
)));
520 maj_stat
= gss_krb5_import_cred(&min_stat
, ccache
->ccache
, NULL
, NULL
,
532 (*error_string
) = talloc_asprintf(cred
, "gss_krb5_import_cred failed: %s", error_message(ret
));
536 #ifdef SAMBA4_USES_HEIMDAL /* MIT lacks krb5_get_default_in_tkt_etypes */
538 * transfer the enctypes from the smb_krb5_context to the gssapi layer
540 * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
541 * to configure the enctypes via the krb5.conf.
543 * And the gss_init_sec_context() creates it's own krb5_context and
544 * the TGS-REQ had all enctypes in it and only the ones configured
545 * and used for the AS-REQ, so it wasn't possible to disable the usage
548 min_stat
= krb5_get_default_in_tkt_etypes(ccache
->smb_krb5_context
->krb5_context
,
552 OM_uint32 num_ktypes
;
554 for (num_ktypes
= 0; etypes
[num_ktypes
]; num_ktypes
++);
556 maj_stat
= gss_krb5_set_allowable_enctypes(&min_stat
, gcc
->creds
,
567 (*error_string
) = talloc_asprintf(cred
, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret
));
572 #ifdef SAMBA4_USES_HEIMDAL /* MIT lacks GSS_KRB5_CRED_NO_CI_FLAGS_X */
574 /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
575 maj_stat
= gss_set_cred_option(&min_stat
, &gcc
->creds
,
576 GSS_KRB5_CRED_NO_CI_FLAGS_X
,
585 (*error_string
) = talloc_asprintf(cred
, "gss_set_cred_option failed: %s", error_message(ret
));
589 cred
->client_gss_creds_obtained
= cred
->ccache_obtained
;
590 talloc_set_destructor(gcc
, free_gssapi_creds
);
591 cred
->client_gss_creds
= gcc
;
597 Set a gssapi cred_id_t into the credentials system. (Client case)
599 This grabs the credentials both 'intact' and getting the krb5
600 ccache out of it. This routine can be generalised in future for
601 the case where we deal with GSSAPI mechs other than krb5.
603 On sucess, the caller must not free gssapi_cred, as it now belongs
604 to the credentials system.
607 int cli_credentials_set_client_gss_creds(struct cli_credentials
*cred
,
608 struct loadparm_context
*lp_ctx
,
609 gss_cred_id_t gssapi_cred
,
610 enum credentials_obtained obtained
,
611 const char **error_string
)
614 OM_uint32 maj_stat
, min_stat
;
615 struct ccache_container
*ccc
;
616 struct gssapi_creds_container
*gcc
;
617 if (cred
->client_gss_creds_obtained
> obtained
) {
621 gcc
= talloc(cred
, struct gssapi_creds_container
);
623 (*error_string
) = error_message(ENOMEM
);
627 ret
= cli_credentials_new_ccache(cred
, lp_ctx
, NULL
, &ccc
, error_string
);
632 maj_stat
= gss_krb5_copy_ccache(&min_stat
,
633 gssapi_cred
, ccc
->ccache
);
641 (*error_string
) = error_message(ENOMEM
);
646 ret
= cli_credentials_set_from_ccache(cred
, ccc
, obtained
, error_string
);
649 cred
->ccache_obtained
= obtained
;
651 gcc
->creds
= gssapi_cred
;
652 talloc_set_destructor(gcc
, free_gssapi_creds
);
654 /* set the clinet_gss_creds_obtained here, as it just
655 got set to UNINITIALISED by the calls above */
656 cred
->client_gss_creds_obtained
= obtained
;
657 cred
->client_gss_creds
= gcc
;
662 /* Get the keytab (actually, a container containing the krb5_keytab)
663 * attached to this context. If this hasn't been done or set before,
664 * it will be generated from the password.
666 _PUBLIC_
int cli_credentials_get_keytab(struct cli_credentials
*cred
,
667 struct loadparm_context
*lp_ctx
,
668 struct keytab_container
**_ktc
)
671 struct keytab_container
*ktc
;
672 struct smb_krb5_context
*smb_krb5_context
;
673 const char *keytab_name
;
677 if (cred
->keytab_obtained
>= (MAX(cred
->principal_obtained
,
678 cred
->username_obtained
))) {
679 *_ktc
= cred
->keytab
;
683 if (cli_credentials_is_anonymous(cred
)) {
687 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
,
693 mem_ctx
= talloc_new(cred
);
698 ret
= smb_krb5_create_memory_keytab(mem_ctx
,
699 smb_krb5_context
->krb5_context
,
700 cli_credentials_get_password(cred
),
701 cli_credentials_get_username(cred
),
702 cli_credentials_get_realm(cred
),
703 cli_credentials_get_kvno(cred
),
704 &keytab
, &keytab_name
);
706 talloc_free(mem_ctx
);
710 ret
= smb_krb5_get_keytab_container(mem_ctx
, smb_krb5_context
,
711 keytab
, keytab_name
, &ktc
);
713 talloc_free(mem_ctx
);
717 cred
->keytab_obtained
= (MAX(cred
->principal_obtained
,
718 cred
->username_obtained
));
720 talloc_steal(cred
, ktc
);
722 *_ktc
= cred
->keytab
;
723 talloc_free(mem_ctx
);
727 /* Given the name of a keytab (presumably in the format
728 * FILE:/etc/krb5.keytab), open it and attach it */
730 _PUBLIC_
int cli_credentials_set_keytab_name(struct cli_credentials
*cred
,
731 struct loadparm_context
*lp_ctx
,
732 const char *keytab_name
,
733 enum credentials_obtained obtained
)
736 struct keytab_container
*ktc
;
737 struct smb_krb5_context
*smb_krb5_context
;
740 if (cred
->keytab_obtained
>= obtained
) {
744 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
, &smb_krb5_context
);
749 mem_ctx
= talloc_new(cred
);
754 ret
= smb_krb5_get_keytab_container(mem_ctx
, smb_krb5_context
,
755 NULL
, keytab_name
, &ktc
);
760 cred
->keytab_obtained
= obtained
;
762 talloc_steal(cred
, ktc
);
764 talloc_free(mem_ctx
);
769 /* Get server gss credentials (in gsskrb5, this means the keytab) */
771 _PUBLIC_
int cli_credentials_get_server_gss_creds(struct cli_credentials
*cred
,
772 struct loadparm_context
*lp_ctx
,
773 struct gssapi_creds_container
**_gcc
)
776 OM_uint32 maj_stat
, min_stat
;
777 struct gssapi_creds_container
*gcc
;
778 struct keytab_container
*ktc
;
779 struct smb_krb5_context
*smb_krb5_context
;
781 krb5_principal princ
;
782 const char *error_string
;
783 enum credentials_obtained obtained
;
785 mem_ctx
= talloc_new(cred
);
790 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
, &smb_krb5_context
);
795 ret
= principal_from_credentials(mem_ctx
, cred
, smb_krb5_context
, &princ
, &obtained
, &error_string
);
797 DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n",
799 talloc_free(mem_ctx
);
803 if (cred
->server_gss_creds_obtained
>= (MAX(cred
->keytab_obtained
, obtained
))) {
804 talloc_free(mem_ctx
);
805 *_gcc
= cred
->server_gss_creds
;
809 ret
= cli_credentials_get_keytab(cred
, lp_ctx
, &ktc
);
811 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret
)));
815 gcc
= talloc(cred
, struct gssapi_creds_container
);
817 talloc_free(mem_ctx
);
821 if (obtained
< CRED_SPECIFIED
) {
822 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
823 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, NULL
, ktc
->keytab
,
826 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
827 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, princ
, ktc
->keytab
,
838 cred
->server_gss_creds_obtained
= cred
->keytab_obtained
;
839 talloc_set_destructor(gcc
, free_gssapi_creds
);
840 cred
->server_gss_creds
= gcc
;
843 talloc_free(mem_ctx
);
851 _PUBLIC_
void cli_credentials_set_kvno(struct cli_credentials
*cred
,
858 * Return Kerberos KVNO
861 _PUBLIC_
int cli_credentials_get_kvno(struct cli_credentials
*cred
)
867 const char *cli_credentials_get_salt_principal(struct cli_credentials
*cred
)
869 return cred
->salt_principal
;
872 _PUBLIC_
void cli_credentials_set_salt_principal(struct cli_credentials
*cred
, const char *principal
)
874 talloc_free(cred
->salt_principal
);
875 cred
->salt_principal
= talloc_strdup(cred
, principal
);
878 /* The 'impersonate_principal' is used to allow one Kerberos principal
879 * (and it's associated keytab etc) to impersonate another. The
880 * ability to do this is controlled by the KDC, but it is generally
881 * permitted to impersonate anyone to yourself. This allows any
882 * member of the domain to get the groups of a user. This is also
883 * known as S4U2Self */
885 _PUBLIC_
const char *cli_credentials_get_impersonate_principal(struct cli_credentials
*cred
)
887 return cred
->impersonate_principal
;
891 * The 'self_service' is the service principal that
892 * represents the same object (by its objectSid)
893 * as the client principal (typically our machine account).
894 * When trying to impersonate 'impersonate_principal' with
897 _PUBLIC_
const char *cli_credentials_get_self_service(struct cli_credentials
*cred
)
899 return cred
->self_service
;
902 _PUBLIC_
void cli_credentials_set_impersonate_principal(struct cli_credentials
*cred
,
903 const char *principal
,
904 const char *self_service
)
906 talloc_free(cred
->impersonate_principal
);
907 cred
->impersonate_principal
= talloc_strdup(cred
, principal
);
908 talloc_free(cred
->self_service
);
909 cred
->self_service
= talloc_strdup(cred
, self_service
);
910 cli_credentials_set_kerberos_state(cred
, CRED_MUST_USE_KERBEROS
);
914 * when impersonating for S4U2proxy we need to set the target principal.
915 * Similarly, we may only be authorized to do general impersonation to
916 * some particular services.
918 * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
920 * NULL means that tickets will be obtained for the krbtgt service.
923 const char *cli_credentials_get_target_service(struct cli_credentials
*cred
)
925 return cred
->target_service
;
928 _PUBLIC_
void cli_credentials_set_target_service(struct cli_credentials
*cred
, const char *target_service
)
930 talloc_free(cred
->target_service
);
931 cred
->target_service
= talloc_strdup(cred
, target_service
);