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 /* We make this keytab up based on a password. Therefore
721 * match-by-key is acceptable, we can't match on the wrong
723 ktc
->password_based
= true;
725 talloc_steal(cred
, ktc
);
727 *_ktc
= cred
->keytab
;
728 talloc_free(mem_ctx
);
732 /* Given the name of a keytab (presumably in the format
733 * FILE:/etc/krb5.keytab), open it and attach it */
735 _PUBLIC_
int cli_credentials_set_keytab_name(struct cli_credentials
*cred
,
736 struct loadparm_context
*lp_ctx
,
737 const char *keytab_name
,
738 enum credentials_obtained obtained
)
741 struct keytab_container
*ktc
;
742 struct smb_krb5_context
*smb_krb5_context
;
745 if (cred
->keytab_obtained
>= obtained
) {
749 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
, &smb_krb5_context
);
754 mem_ctx
= talloc_new(cred
);
759 ret
= smb_krb5_get_keytab_container(mem_ctx
, smb_krb5_context
,
760 NULL
, keytab_name
, &ktc
);
765 cred
->keytab_obtained
= obtained
;
767 talloc_steal(cred
, ktc
);
769 talloc_free(mem_ctx
);
774 /* Get server gss credentials (in gsskrb5, this means the keytab) */
776 _PUBLIC_
int cli_credentials_get_server_gss_creds(struct cli_credentials
*cred
,
777 struct loadparm_context
*lp_ctx
,
778 struct gssapi_creds_container
**_gcc
)
781 OM_uint32 maj_stat
, min_stat
;
782 struct gssapi_creds_container
*gcc
;
783 struct keytab_container
*ktc
;
784 struct smb_krb5_context
*smb_krb5_context
;
786 krb5_principal princ
;
787 const char *error_string
;
788 enum credentials_obtained obtained
;
790 mem_ctx
= talloc_new(cred
);
795 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
, &smb_krb5_context
);
800 ret
= principal_from_credentials(mem_ctx
, cred
, smb_krb5_context
, &princ
, &obtained
, &error_string
);
802 DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n",
804 talloc_free(mem_ctx
);
808 if (cred
->server_gss_creds_obtained
>= (MAX(cred
->keytab_obtained
, obtained
))) {
809 talloc_free(mem_ctx
);
810 *_gcc
= cred
->server_gss_creds
;
814 ret
= cli_credentials_get_keytab(cred
, lp_ctx
, &ktc
);
816 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret
)));
820 gcc
= talloc(cred
, struct gssapi_creds_container
);
822 talloc_free(mem_ctx
);
826 if (ktc
->password_based
|| obtained
< CRED_SPECIFIED
) {
827 /* This creates a GSSAPI cred_id_t for match-by-key with only the keytab set */
828 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, NULL
, ktc
->keytab
,
831 /* This creates a GSSAPI cred_id_t with the principal and keytab set, matching by name */
832 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, princ
, ktc
->keytab
,
843 cred
->server_gss_creds_obtained
= cred
->keytab_obtained
;
844 talloc_set_destructor(gcc
, free_gssapi_creds
);
845 cred
->server_gss_creds
= gcc
;
848 talloc_free(mem_ctx
);
856 _PUBLIC_
void cli_credentials_set_kvno(struct cli_credentials
*cred
,
863 * Return Kerberos KVNO
866 _PUBLIC_
int cli_credentials_get_kvno(struct cli_credentials
*cred
)
872 const char *cli_credentials_get_salt_principal(struct cli_credentials
*cred
)
874 return cred
->salt_principal
;
877 _PUBLIC_
void cli_credentials_set_salt_principal(struct cli_credentials
*cred
, const char *principal
)
879 talloc_free(cred
->salt_principal
);
880 cred
->salt_principal
= talloc_strdup(cred
, principal
);
883 /* The 'impersonate_principal' is used to allow one Kerberos principal
884 * (and it's associated keytab etc) to impersonate another. The
885 * ability to do this is controlled by the KDC, but it is generally
886 * permitted to impersonate anyone to yourself. This allows any
887 * member of the domain to get the groups of a user. This is also
888 * known as S4U2Self */
890 _PUBLIC_
const char *cli_credentials_get_impersonate_principal(struct cli_credentials
*cred
)
892 return cred
->impersonate_principal
;
896 * The 'self_service' is the service principal that
897 * represents the same object (by its objectSid)
898 * as the client principal (typically our machine account).
899 * When trying to impersonate 'impersonate_principal' with
902 _PUBLIC_
const char *cli_credentials_get_self_service(struct cli_credentials
*cred
)
904 return cred
->self_service
;
907 _PUBLIC_
void cli_credentials_set_impersonate_principal(struct cli_credentials
*cred
,
908 const char *principal
,
909 const char *self_service
)
911 talloc_free(cred
->impersonate_principal
);
912 cred
->impersonate_principal
= talloc_strdup(cred
, principal
);
913 talloc_free(cred
->self_service
);
914 cred
->self_service
= talloc_strdup(cred
, self_service
);
915 cli_credentials_set_kerberos_state(cred
, CRED_MUST_USE_KERBEROS
);
919 * when impersonating for S4U2proxy we need to set the target principal.
920 * Similarly, we may only be authorized to do general impersonation to
921 * some particular services.
923 * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
925 * NULL means that tickets will be obtained for the krbtgt service.
928 const char *cli_credentials_get_target_service(struct cli_credentials
*cred
)
930 return cred
->target_service
;
933 _PUBLIC_
void cli_credentials_set_target_service(struct cli_credentials
*cred
, const char *target_service
)
935 talloc_free(cred
->target_service
);
936 cred
->target_service
= talloc_strdup(cred
, target_service
);