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_internal.h"
30 #include "auth/credentials/credentials_proto.h"
31 #include "auth/credentials/credentials_krb5.h"
32 #include "auth/kerberos/kerberos_credentials.h"
33 #include "auth/kerberos/kerberos_srv_keytab.h"
34 #include "auth/kerberos/kerberos_util.h"
35 #include "auth/kerberos/pac_utils.h"
36 #include "param/param.h"
38 static void cli_credentials_invalidate_client_gss_creds(
39 struct cli_credentials
*cred
,
40 enum credentials_obtained obtained
);
42 _PUBLIC_
int cli_credentials_get_krb5_context(struct cli_credentials
*cred
,
43 struct loadparm_context
*lp_ctx
,
44 struct smb_krb5_context
**smb_krb5_context
)
47 if (cred
->smb_krb5_context
) {
48 *smb_krb5_context
= cred
->smb_krb5_context
;
52 ret
= smb_krb5_init_context(cred
, lp_ctx
,
53 &cred
->smb_krb5_context
);
55 cred
->smb_krb5_context
= NULL
;
58 *smb_krb5_context
= cred
->smb_krb5_context
;
62 /* For most predictable behaviour, this needs to be called directly after the cli_credentials_init(),
63 * otherwise we may still have references to the old smb_krb5_context in a credential cache etc
65 _PUBLIC_ NTSTATUS
cli_credentials_set_krb5_context(struct cli_credentials
*cred
,
66 struct smb_krb5_context
*smb_krb5_context
)
68 if (smb_krb5_context
== NULL
) {
69 talloc_unlink(cred
, cred
->smb_krb5_context
);
70 cred
->smb_krb5_context
= NULL
;
74 if (!talloc_reference(cred
, smb_krb5_context
)) {
75 return NT_STATUS_NO_MEMORY
;
77 cred
->smb_krb5_context
= smb_krb5_context
;
81 static int cli_credentials_set_from_ccache(struct cli_credentials
*cred
,
82 struct ccache_container
*ccache
,
83 enum credentials_obtained obtained
,
84 const char **error_string
)
91 if (cred
->ccache_obtained
> obtained
) {
95 ret
= krb5_cc_get_principal(ccache
->smb_krb5_context
->krb5_context
,
96 ccache
->ccache
, &princ
);
99 (*error_string
) = talloc_asprintf(cred
, "failed to get principal from ccache: %s\n",
100 smb_get_krb5_error_message(ccache
->smb_krb5_context
->krb5_context
,
105 ret
= krb5_unparse_name(ccache
->smb_krb5_context
->krb5_context
, princ
, &name
);
107 (*error_string
) = talloc_asprintf(cred
, "failed to unparse principal from ccache: %s\n",
108 smb_get_krb5_error_message(ccache
->smb_krb5_context
->krb5_context
,
113 cli_credentials_set_principal(cred
, name
, obtained
);
117 krb5_free_principal(ccache
->smb_krb5_context
->krb5_context
, princ
);
119 /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */
120 cred
->ccache_obtained
= obtained
;
125 /* Free a memory ccache */
126 static int free_mccache(struct ccache_container
*ccc
)
128 krb5_cc_destroy(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
);
133 /* Free a disk-based ccache */
134 static int free_dccache(struct ccache_container
*ccc
) {
135 krb5_cc_close(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
);
140 _PUBLIC_
int cli_credentials_set_ccache(struct cli_credentials
*cred
,
141 struct loadparm_context
*lp_ctx
,
143 enum credentials_obtained obtained
,
144 const char **error_string
)
147 krb5_principal princ
;
148 struct ccache_container
*ccc
;
149 if (cred
->ccache_obtained
> obtained
) {
153 ccc
= talloc(cred
, struct ccache_container
);
155 (*error_string
) = error_message(ENOMEM
);
159 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
,
160 &ccc
->smb_krb5_context
);
162 (*error_string
) = error_message(ret
);
166 if (!talloc_reference(ccc
, ccc
->smb_krb5_context
)) {
168 (*error_string
) = error_message(ENOMEM
);
173 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, name
, &ccc
->ccache
);
175 (*error_string
) = talloc_asprintf(cred
, "failed to read krb5 ccache: %s: %s\n",
177 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
183 ret
= krb5_cc_default(ccc
->smb_krb5_context
->krb5_context
, &ccc
->ccache
);
185 (*error_string
) = talloc_asprintf(cred
, "failed to read default krb5 ccache: %s\n",
186 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
193 talloc_set_destructor(ccc
, free_dccache
);
195 ret
= krb5_cc_get_principal(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
, &princ
);
198 krb5_free_principal(ccc
->smb_krb5_context
->krb5_context
, princ
);
199 ret
= cli_credentials_set_from_ccache(cred
, ccc
, obtained
, error_string
);
202 (*error_string
) = error_message(ret
);
207 cred
->ccache_obtained
= obtained
;
208 talloc_steal(cred
, ccc
);
210 cli_credentials_invalidate_client_gss_creds(cred
, cred
->ccache_obtained
);
217 * Indicate the we failed to log in to this service/host with these
218 * credentials. The caller passes an unsigned int which they
219 * initialise to the number of times they would like to retry.
221 * This method is used to support re-trying with freshly fetched
222 * credentials in case a server is rebuilt while clients have
223 * non-expired tickets. When the client code gets a logon failure they
224 * throw away the existing credentials for the server and retry.
226 _PUBLIC_
bool cli_credentials_failed_kerberos_login(struct cli_credentials
*cred
,
227 const char *principal
,
230 struct ccache_container
*ccc
;
231 krb5_creds creds
, creds2
;
234 if (principal
== NULL
) {
235 /* no way to delete if we don't know the principal */
241 /* not a kerberos connection */
246 /* We have already tried discarding the credentials */
252 ret
= krb5_parse_name(ccc
->smb_krb5_context
->krb5_context
, principal
, &creds
.server
);
257 ret
= krb5_cc_retrieve_cred(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
, KRB5_TC_MATCH_SRV_NAMEONLY
, &creds
, &creds2
);
259 /* don't retry - we didn't find these credentials to remove */
263 ret
= krb5_cc_remove_cred(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
, KRB5_TC_MATCH_SRV_NAMEONLY
, &creds
);
264 krb5_free_cred_contents(ccc
->smb_krb5_context
->krb5_context
, &creds2
);
266 /* don't retry - we didn't find these credentials to
267 * remove. Note that with the current backend this
268 * never happens, as it always returns 0 even if the
269 * creds don't exist, which is why we do a separate
270 * krb5_cc_retrieve_cred() above.
278 static int cli_credentials_new_ccache(struct cli_credentials
*cred
,
279 struct loadparm_context
*lp_ctx
,
281 struct ccache_container
**_ccc
,
282 const char **error_string
)
284 bool must_free_cc_name
= false;
286 struct ccache_container
*ccc
= talloc(cred
, struct ccache_container
);
291 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
,
292 &ccc
->smb_krb5_context
);
295 (*error_string
) = talloc_asprintf(cred
, "Failed to get krb5_context: %s",
299 if (!talloc_reference(ccc
, ccc
->smb_krb5_context
)) {
301 (*error_string
) = strerror(ENOMEM
);
306 must_free_cc_name
= true;
308 if (lpcfg_parm_bool(lp_ctx
, NULL
, "credentials", "krb5_cc_file", false)) {
309 ccache_name
= talloc_asprintf(ccc
, "FILE:/tmp/krb5_cc_samba_%u_%p",
310 (unsigned int)getpid(), ccc
);
312 ccache_name
= talloc_asprintf(ccc
, "MEMORY:%p",
318 (*error_string
) = strerror(ENOMEM
);
323 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, ccache_name
,
326 (*error_string
) = talloc_asprintf(cred
, "failed to resolve a krb5 ccache (%s): %s\n",
328 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
330 talloc_free(ccache_name
);
335 if (strncasecmp(ccache_name
, "MEMORY:", 7) == 0) {
336 talloc_set_destructor(ccc
, free_mccache
);
338 talloc_set_destructor(ccc
, free_dccache
);
341 if (must_free_cc_name
) {
342 talloc_free(ccache_name
);
350 _PUBLIC_
int cli_credentials_get_named_ccache(struct cli_credentials
*cred
,
351 struct tevent_context
*event_ctx
,
352 struct loadparm_context
*lp_ctx
,
354 struct ccache_container
**ccc
,
355 const char **error_string
)
358 enum credentials_obtained obtained
;
360 if (cred
->machine_account_pending
) {
361 cli_credentials_set_machine_account(cred
, lp_ctx
);
364 if (cred
->ccache_obtained
>= cred
->ccache_threshold
&&
365 cred
->ccache_obtained
> CRED_UNINITIALISED
) {
367 bool expired
= false;
368 ret
= smb_krb5_cc_get_lifetime(cred
->ccache
->smb_krb5_context
->krb5_context
,
369 cred
->ccache
->ccache
, &lifetime
);
370 if (ret
== KRB5_CC_END
) {
371 /* If we have a particular ccache set, without
372 * an initial ticket, then assume there is a
374 } else if (ret
== 0) {
376 DEBUG(3, ("Ticket in credentials cache for %s expired, will refresh\n",
377 cli_credentials_get_principal(cred
, cred
)));
379 } else if (lifetime
< 300) {
380 DEBUG(3, ("Ticket in credentials cache for %s will shortly expire (%u secs), will refresh\n",
381 cli_credentials_get_principal(cred
, cred
), (unsigned int)lifetime
));
385 (*error_string
) = talloc_asprintf(cred
, "failed to get ccache lifetime: %s\n",
386 smb_get_krb5_error_message(cred
->ccache
->smb_krb5_context
->krb5_context
,
391 DEBUG(5, ("Ticket in credentials cache for %s will expire in %u secs\n",
392 cli_credentials_get_principal(cred
, cred
), (unsigned int)lifetime
));
399 if (cli_credentials_is_anonymous(cred
)) {
400 (*error_string
) = "Cannot get anonymous kerberos credentials";
404 ret
= cli_credentials_new_ccache(cred
, lp_ctx
, ccache_name
, ccc
, error_string
);
409 ret
= kinit_to_ccache(cred
, cred
, (*ccc
)->smb_krb5_context
, event_ctx
, (*ccc
)->ccache
, &obtained
, error_string
);
414 ret
= cli_credentials_set_from_ccache(cred
, *ccc
,
415 obtained
, error_string
);
418 cred
->ccache_obtained
= cred
->principal_obtained
;
422 cli_credentials_invalidate_client_gss_creds(cred
, cred
->ccache_obtained
);
426 _PUBLIC_
int cli_credentials_get_ccache(struct cli_credentials
*cred
,
427 struct tevent_context
*event_ctx
,
428 struct loadparm_context
*lp_ctx
,
429 struct ccache_container
**ccc
,
430 const char **error_string
)
432 return cli_credentials_get_named_ccache(cred
, event_ctx
, lp_ctx
, NULL
, ccc
, error_string
);
435 /* We have good reason to think the ccache in these credentials is invalid - blow it away */
436 static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials
*cred
)
438 if (cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
439 talloc_unlink(cred
, cred
->client_gss_creds
);
440 cred
->client_gss_creds
= NULL
;
442 cred
->client_gss_creds_obtained
= CRED_UNINITIALISED
;
445 void cli_credentials_invalidate_client_gss_creds(struct cli_credentials
*cred
,
446 enum credentials_obtained obtained
)
448 /* If the caller just changed the username/password etc, then
449 * any cached credentials are now invalid */
450 if (obtained
>= cred
->client_gss_creds_obtained
) {
451 if (cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
452 talloc_unlink(cred
, cred
->client_gss_creds
);
453 cred
->client_gss_creds
= NULL
;
455 cred
->client_gss_creds_obtained
= CRED_UNINITIALISED
;
457 /* Now that we know that the data is 'this specified', then
458 * don't allow something less 'known' to be returned as a
459 * ccache. Ie, if the username is on the command line, we
460 * don't want to later guess to use a file-based ccache */
461 if (obtained
> cred
->client_gss_creds_threshold
) {
462 cred
->client_gss_creds_threshold
= obtained
;
466 /* We have good reason to think this CCACHE is invalid. Blow it away */
467 static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials
*cred
)
469 if (cred
->ccache_obtained
> CRED_UNINITIALISED
) {
470 talloc_unlink(cred
, cred
->ccache
);
473 cred
->ccache_obtained
= CRED_UNINITIALISED
;
475 cli_credentials_unconditionally_invalidate_client_gss_creds(cred
);
478 _PUBLIC_
void cli_credentials_invalidate_ccache(struct cli_credentials
*cred
,
479 enum credentials_obtained obtained
)
481 /* If the caller just changed the username/password etc, then
482 * any cached credentials are now invalid */
483 if (obtained
>= cred
->ccache_obtained
) {
484 if (cred
->ccache_obtained
> CRED_UNINITIALISED
) {
485 talloc_unlink(cred
, cred
->ccache
);
488 cred
->ccache_obtained
= CRED_UNINITIALISED
;
490 /* Now that we know that the data is 'this specified', then
491 * don't allow something less 'known' to be returned as a
492 * ccache. i.e, if the username is on the command line, we
493 * don't want to later guess to use a file-based ccache */
494 if (obtained
> cred
->ccache_threshold
) {
495 cred
->ccache_threshold
= obtained
;
498 cli_credentials_invalidate_client_gss_creds(cred
,
502 static int free_gssapi_creds(struct gssapi_creds_container
*gcc
)
505 (void)gss_release_cred(&min_stat
, &gcc
->creds
);
509 _PUBLIC_
int cli_credentials_get_client_gss_creds(struct cli_credentials
*cred
,
510 struct tevent_context
*event_ctx
,
511 struct loadparm_context
*lp_ctx
,
512 struct gssapi_creds_container
**_gcc
,
513 const char **error_string
)
516 OM_uint32 maj_stat
, min_stat
;
517 struct gssapi_creds_container
*gcc
;
518 struct ccache_container
*ccache
;
519 #ifdef SAMBA4_USES_HEIMDAL
520 gss_buffer_desc empty_buffer
= GSS_C_EMPTY_BUFFER
;
522 krb5_enctype
*etypes
= NULL
;
524 if (cred
->client_gss_creds_obtained
>= cred
->client_gss_creds_threshold
&&
525 cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
526 bool expired
= false;
527 OM_uint32 lifetime
= 0;
528 gss_cred_usage_t usage
= 0;
529 maj_stat
= gss_inquire_cred(&min_stat
, cred
->client_gss_creds
->creds
,
530 NULL
, &lifetime
, &usage
, NULL
);
531 if (maj_stat
== GSS_S_CREDENTIALS_EXPIRED
) {
532 DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred
, cred
)));
534 } else if (maj_stat
== GSS_S_COMPLETE
&& lifetime
< 300) {
535 DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred
, cred
), lifetime
));
537 } else if (maj_stat
!= GSS_S_COMPLETE
) {
538 *error_string
= talloc_asprintf(cred
, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
539 gssapi_error_string(cred
, maj_stat
, min_stat
, NULL
));
543 cli_credentials_unconditionally_invalidate_client_gss_creds(cred
);
545 DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n",
546 cli_credentials_get_principal(cred
, cred
), (unsigned int)lifetime
));
548 *_gcc
= cred
->client_gss_creds
;
553 ret
= cli_credentials_get_ccache(cred
, event_ctx
, lp_ctx
,
554 &ccache
, error_string
);
556 if (cli_credentials_get_kerberos_state(cred
) == CRED_MUST_USE_KERBEROS
) {
557 DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string
));
559 DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string
));
564 gcc
= talloc(cred
, struct gssapi_creds_container
);
566 (*error_string
) = error_message(ENOMEM
);
570 maj_stat
= gss_krb5_import_cred(&min_stat
, ccache
->ccache
, NULL
, NULL
,
572 if ((maj_stat
== GSS_S_FAILURE
) && (min_stat
== (OM_uint32
)KRB5_CC_END
|| min_stat
== (OM_uint32
) KRB5_CC_NOTFOUND
)) {
573 /* This CCACHE is no good. Ensure we don't use it again */
574 cli_credentials_unconditionally_invalidate_ccache(cred
);
576 /* Now try again to get a ccache */
577 ret
= cli_credentials_get_ccache(cred
, event_ctx
, lp_ctx
,
578 &ccache
, error_string
);
580 DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret
)));
584 maj_stat
= gss_krb5_import_cred(&min_stat
, ccache
->ccache
, NULL
, NULL
,
596 (*error_string
) = talloc_asprintf(cred
, "gss_krb5_import_cred failed: %s", error_message(ret
));
602 * transfer the enctypes from the smb_krb5_context to the gssapi layer
604 * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
605 * to configure the enctypes via the krb5.conf.
607 * And the gss_init_sec_context() creates it's own krb5_context and
608 * the TGS-REQ had all enctypes in it and only the ones configured
609 * and used for the AS-REQ, so it wasn't possible to disable the usage
612 min_stat
= get_kerberos_allowed_etypes(ccache
->smb_krb5_context
->krb5_context
,
615 OM_uint32 num_ktypes
;
617 for (num_ktypes
= 0; etypes
[num_ktypes
]; num_ktypes
++);
619 maj_stat
= gss_krb5_set_allowable_enctypes(&min_stat
, gcc
->creds
,
630 (*error_string
) = talloc_asprintf(cred
, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret
));
635 #ifdef SAMBA4_USES_HEIMDAL /* MIT lacks GSS_KRB5_CRED_NO_CI_FLAGS_X */
637 /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
638 maj_stat
= gss_set_cred_option(&min_stat
, &gcc
->creds
,
639 GSS_KRB5_CRED_NO_CI_FLAGS_X
,
648 (*error_string
) = talloc_asprintf(cred
, "gss_set_cred_option failed: %s", error_message(ret
));
652 cred
->client_gss_creds_obtained
= cred
->ccache_obtained
;
653 talloc_set_destructor(gcc
, free_gssapi_creds
);
654 cred
->client_gss_creds
= gcc
;
660 Set a gssapi cred_id_t into the credentials system. (Client case)
662 This grabs the credentials both 'intact' and getting the krb5
663 ccache out of it. This routine can be generalised in future for
664 the case where we deal with GSSAPI mechs other than krb5.
666 On sucess, the caller must not free gssapi_cred, as it now belongs
667 to the credentials system.
670 int cli_credentials_set_client_gss_creds(struct cli_credentials
*cred
,
671 struct loadparm_context
*lp_ctx
,
672 gss_cred_id_t gssapi_cred
,
673 enum credentials_obtained obtained
,
674 const char **error_string
)
677 OM_uint32 maj_stat
, min_stat
;
678 struct ccache_container
*ccc
;
679 struct gssapi_creds_container
*gcc
;
680 if (cred
->client_gss_creds_obtained
> obtained
) {
684 gcc
= talloc(cred
, struct gssapi_creds_container
);
686 (*error_string
) = error_message(ENOMEM
);
690 ret
= cli_credentials_new_ccache(cred
, lp_ctx
, NULL
, &ccc
, error_string
);
695 maj_stat
= gss_krb5_copy_ccache(&min_stat
,
696 gssapi_cred
, ccc
->ccache
);
704 (*error_string
) = error_message(ENOMEM
);
709 ret
= cli_credentials_set_from_ccache(cred
, ccc
, obtained
, error_string
);
712 cred
->ccache_obtained
= obtained
;
714 gcc
->creds
= gssapi_cred
;
715 talloc_set_destructor(gcc
, free_gssapi_creds
);
717 /* set the clinet_gss_creds_obtained here, as it just
718 got set to UNINITIALISED by the calls above */
719 cred
->client_gss_creds_obtained
= obtained
;
720 cred
->client_gss_creds
= gcc
;
725 /* Get the keytab (actually, a container containing the krb5_keytab)
726 * attached to this context. If this hasn't been done or set before,
727 * it will be generated from the password.
729 _PUBLIC_
int cli_credentials_get_keytab(struct cli_credentials
*cred
,
730 struct loadparm_context
*lp_ctx
,
731 struct keytab_container
**_ktc
)
734 struct keytab_container
*ktc
;
735 struct smb_krb5_context
*smb_krb5_context
;
736 const char *keytab_name
;
740 if (cred
->keytab_obtained
>= (MAX(cred
->principal_obtained
,
741 cred
->username_obtained
))) {
742 *_ktc
= cred
->keytab
;
746 if (cli_credentials_is_anonymous(cred
)) {
750 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
,
756 mem_ctx
= talloc_new(cred
);
761 ret
= smb_krb5_create_memory_keytab(mem_ctx
,
762 smb_krb5_context
->krb5_context
,
763 cli_credentials_get_password(cred
),
764 cli_credentials_get_username(cred
),
765 cli_credentials_get_realm(cred
),
766 cli_credentials_get_kvno(cred
),
767 &keytab
, &keytab_name
);
769 talloc_free(mem_ctx
);
773 ret
= smb_krb5_get_keytab_container(mem_ctx
, smb_krb5_context
,
774 keytab
, keytab_name
, &ktc
);
776 talloc_free(mem_ctx
);
780 cred
->keytab_obtained
= (MAX(cred
->principal_obtained
,
781 cred
->username_obtained
));
783 /* We make this keytab up based on a password. Therefore
784 * match-by-key is acceptable, we can't match on the wrong
786 ktc
->password_based
= true;
788 talloc_steal(cred
, ktc
);
790 *_ktc
= cred
->keytab
;
791 talloc_free(mem_ctx
);
795 /* Given the name of a keytab (presumably in the format
796 * FILE:/etc/krb5.keytab), open it and attach it */
798 _PUBLIC_
int cli_credentials_set_keytab_name(struct cli_credentials
*cred
,
799 struct loadparm_context
*lp_ctx
,
800 const char *keytab_name
,
801 enum credentials_obtained obtained
)
804 struct keytab_container
*ktc
;
805 struct smb_krb5_context
*smb_krb5_context
;
808 if (cred
->keytab_obtained
>= obtained
) {
812 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
, &smb_krb5_context
);
817 mem_ctx
= talloc_new(cred
);
822 ret
= smb_krb5_get_keytab_container(mem_ctx
, smb_krb5_context
,
823 NULL
, keytab_name
, &ktc
);
828 cred
->keytab_obtained
= obtained
;
830 talloc_steal(cred
, ktc
);
832 talloc_free(mem_ctx
);
837 /* Get server gss credentials (in gsskrb5, this means the keytab) */
839 _PUBLIC_
int cli_credentials_get_server_gss_creds(struct cli_credentials
*cred
,
840 struct loadparm_context
*lp_ctx
,
841 struct gssapi_creds_container
**_gcc
)
844 OM_uint32 maj_stat
, min_stat
;
845 struct gssapi_creds_container
*gcc
;
846 struct keytab_container
*ktc
;
847 struct smb_krb5_context
*smb_krb5_context
;
849 krb5_principal princ
;
850 const char *error_string
;
851 enum credentials_obtained obtained
;
853 mem_ctx
= talloc_new(cred
);
858 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
, &smb_krb5_context
);
863 ret
= principal_from_credentials(mem_ctx
, cred
, smb_krb5_context
, &princ
, &obtained
, &error_string
);
865 DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n",
867 talloc_free(mem_ctx
);
871 if (cred
->server_gss_creds_obtained
>= (MAX(cred
->keytab_obtained
, obtained
))) {
872 talloc_free(mem_ctx
);
873 *_gcc
= cred
->server_gss_creds
;
877 ret
= cli_credentials_get_keytab(cred
, lp_ctx
, &ktc
);
879 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret
)));
883 gcc
= talloc(cred
, struct gssapi_creds_container
);
885 talloc_free(mem_ctx
);
889 if (ktc
->password_based
|| obtained
< CRED_SPECIFIED
) {
890 /* This creates a GSSAPI cred_id_t for match-by-key with only the keytab set */
891 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, NULL
, ktc
->keytab
,
894 /* This creates a GSSAPI cred_id_t with the principal and keytab set, matching by name */
895 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, princ
, ktc
->keytab
,
906 cred
->server_gss_creds_obtained
= cred
->keytab_obtained
;
907 talloc_set_destructor(gcc
, free_gssapi_creds
);
908 cred
->server_gss_creds
= gcc
;
911 talloc_free(mem_ctx
);
919 _PUBLIC_
void cli_credentials_set_kvno(struct cli_credentials
*cred
,
926 * Return Kerberos KVNO
929 _PUBLIC_
int cli_credentials_get_kvno(struct cli_credentials
*cred
)
935 const char *cli_credentials_get_salt_principal(struct cli_credentials
*cred
)
937 return cred
->salt_principal
;
940 _PUBLIC_
void cli_credentials_set_salt_principal(struct cli_credentials
*cred
, const char *principal
)
942 talloc_free(cred
->salt_principal
);
943 cred
->salt_principal
= talloc_strdup(cred
, principal
);
946 /* The 'impersonate_principal' is used to allow one Kerberos principal
947 * (and it's associated keytab etc) to impersonate another. The
948 * ability to do this is controlled by the KDC, but it is generally
949 * permitted to impersonate anyone to yourself. This allows any
950 * member of the domain to get the groups of a user. This is also
951 * known as S4U2Self */
953 _PUBLIC_
const char *cli_credentials_get_impersonate_principal(struct cli_credentials
*cred
)
955 return cred
->impersonate_principal
;
959 * The 'self_service' is the service principal that
960 * represents the same object (by its objectSid)
961 * as the client principal (typically our machine account).
962 * When trying to impersonate 'impersonate_principal' with
965 _PUBLIC_
const char *cli_credentials_get_self_service(struct cli_credentials
*cred
)
967 return cred
->self_service
;
970 _PUBLIC_
void cli_credentials_set_impersonate_principal(struct cli_credentials
*cred
,
971 const char *principal
,
972 const char *self_service
)
974 talloc_free(cred
->impersonate_principal
);
975 cred
->impersonate_principal
= talloc_strdup(cred
, principal
);
976 talloc_free(cred
->self_service
);
977 cred
->self_service
= talloc_strdup(cred
, self_service
);
978 cli_credentials_set_kerberos_state(cred
, CRED_MUST_USE_KERBEROS
);
982 * when impersonating for S4U2proxy we need to set the target principal.
983 * Similarly, we may only be authorized to do general impersonation to
984 * some particular services.
986 * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
988 * NULL means that tickets will be obtained for the krbtgt service.
991 const char *cli_credentials_get_target_service(struct cli_credentials
*cred
)
993 return cred
->target_service
;
996 _PUBLIC_
void cli_credentials_set_target_service(struct cli_credentials
*cred
, const char *target_service
)
998 talloc_free(cred
->target_service
);
999 cred
->target_service
= talloc_strdup(cred
, target_service
);