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 "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_srv_keytab.h"
32 #include "auth/kerberos/kerberos_util.h"
33 #include "auth/kerberos/pac_utils.h"
34 #include "param/param.h"
36 static void cli_credentials_invalidate_client_gss_creds(
37 struct cli_credentials
*cred
,
38 enum credentials_obtained obtained
);
40 _PUBLIC_
int cli_credentials_get_krb5_context(struct cli_credentials
*cred
,
41 struct loadparm_context
*lp_ctx
,
42 struct smb_krb5_context
**smb_krb5_context
)
45 if (cred
->smb_krb5_context
) {
46 *smb_krb5_context
= cred
->smb_krb5_context
;
50 ret
= smb_krb5_init_context(cred
, NULL
, lp_ctx
,
51 &cred
->smb_krb5_context
);
53 cred
->smb_krb5_context
= NULL
;
56 *smb_krb5_context
= cred
->smb_krb5_context
;
60 /* For most predictable behaviour, this needs to be called directly after the cli_credentials_init(),
61 * otherwise we may still have references to the old smb_krb5_context in a credential cache etc
63 _PUBLIC_ NTSTATUS
cli_credentials_set_krb5_context(struct cli_credentials
*cred
,
64 struct smb_krb5_context
*smb_krb5_context
)
66 if (smb_krb5_context
== NULL
) {
67 talloc_unlink(cred
, cred
->smb_krb5_context
);
68 cred
->smb_krb5_context
= NULL
;
72 if (!talloc_reference(cred
, smb_krb5_context
)) {
73 return NT_STATUS_NO_MEMORY
;
75 cred
->smb_krb5_context
= smb_krb5_context
;
79 static int cli_credentials_set_from_ccache(struct cli_credentials
*cred
,
80 struct ccache_container
*ccache
,
81 enum credentials_obtained obtained
,
82 const char **error_string
)
89 if (cred
->ccache_obtained
> obtained
) {
93 ret
= krb5_cc_get_principal(ccache
->smb_krb5_context
->krb5_context
,
94 ccache
->ccache
, &princ
);
97 (*error_string
) = talloc_asprintf(cred
, "failed to get principal from ccache: %s\n",
98 smb_get_krb5_error_message(ccache
->smb_krb5_context
->krb5_context
,
103 ret
= krb5_unparse_name(ccache
->smb_krb5_context
->krb5_context
, princ
, &name
);
105 (*error_string
) = talloc_asprintf(cred
, "failed to unparse principal from ccache: %s\n",
106 smb_get_krb5_error_message(ccache
->smb_krb5_context
->krb5_context
,
111 cli_credentials_set_principal(cred
, name
, obtained
);
115 krb5_free_principal(ccache
->smb_krb5_context
->krb5_context
, princ
);
117 /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */
118 cred
->ccache_obtained
= obtained
;
123 /* Free a memory ccache */
124 static int free_mccache(struct ccache_container
*ccc
)
126 krb5_cc_destroy(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
);
131 /* Free a disk-based ccache */
132 static int free_dccache(struct ccache_container
*ccc
) {
133 krb5_cc_close(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
);
138 _PUBLIC_
int cli_credentials_set_ccache(struct cli_credentials
*cred
,
139 struct loadparm_context
*lp_ctx
,
141 enum credentials_obtained obtained
,
142 const char **error_string
)
145 krb5_principal princ
;
146 struct ccache_container
*ccc
;
147 if (cred
->ccache_obtained
> obtained
) {
151 ccc
= talloc(cred
, struct ccache_container
);
153 (*error_string
) = error_message(ENOMEM
);
157 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
,
158 &ccc
->smb_krb5_context
);
160 (*error_string
) = error_message(ret
);
164 if (!talloc_reference(ccc
, ccc
->smb_krb5_context
)) {
166 (*error_string
) = error_message(ENOMEM
);
171 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, name
, &ccc
->ccache
);
173 (*error_string
) = talloc_asprintf(cred
, "failed to read krb5 ccache: %s: %s\n",
175 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
181 ret
= krb5_cc_default(ccc
->smb_krb5_context
->krb5_context
, &ccc
->ccache
);
183 (*error_string
) = talloc_asprintf(cred
, "failed to read default krb5 ccache: %s\n",
184 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
191 talloc_set_destructor(ccc
, free_dccache
);
193 ret
= krb5_cc_get_principal(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
, &princ
);
196 krb5_free_principal(ccc
->smb_krb5_context
->krb5_context
, princ
);
197 ret
= cli_credentials_set_from_ccache(cred
, ccc
, obtained
, error_string
);
200 (*error_string
) = error_message(ret
);
205 cred
->ccache_obtained
= obtained
;
206 talloc_steal(cred
, ccc
);
208 cli_credentials_invalidate_client_gss_creds(cred
, cred
->ccache_obtained
);
215 static int cli_credentials_new_ccache(struct cli_credentials
*cred
,
216 struct loadparm_context
*lp_ctx
,
218 struct ccache_container
**_ccc
,
219 const char **error_string
)
221 bool must_free_cc_name
= false;
223 struct ccache_container
*ccc
= talloc(cred
, struct ccache_container
);
228 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
,
229 &ccc
->smb_krb5_context
);
232 (*error_string
) = talloc_asprintf(cred
, "Failed to get krb5_context: %s",
236 if (!talloc_reference(ccc
, ccc
->smb_krb5_context
)) {
238 (*error_string
) = strerror(ENOMEM
);
243 must_free_cc_name
= true;
245 if (lpcfg_parm_bool(lp_ctx
, NULL
, "credentials", "krb5_cc_file", false)) {
246 ccache_name
= talloc_asprintf(ccc
, "FILE:/tmp/krb5_cc_samba_%u_%p",
247 (unsigned int)getpid(), ccc
);
249 ccache_name
= talloc_asprintf(ccc
, "MEMORY:%p",
255 (*error_string
) = strerror(ENOMEM
);
260 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, ccache_name
,
263 (*error_string
) = talloc_asprintf(cred
, "failed to resolve a krb5 ccache (%s): %s\n",
265 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
267 talloc_free(ccache_name
);
272 if (strncasecmp(ccache_name
, "MEMORY:", 7) == 0) {
273 talloc_set_destructor(ccc
, free_mccache
);
275 talloc_set_destructor(ccc
, free_dccache
);
278 if (must_free_cc_name
) {
279 talloc_free(ccache_name
);
287 _PUBLIC_
int cli_credentials_get_named_ccache(struct cli_credentials
*cred
,
288 struct tevent_context
*event_ctx
,
289 struct loadparm_context
*lp_ctx
,
291 struct ccache_container
**ccc
,
292 const char **error_string
)
295 enum credentials_obtained obtained
;
297 if (cred
->machine_account_pending
) {
298 cli_credentials_set_machine_account(cred
, lp_ctx
);
301 if (cred
->ccache_obtained
>= cred
->ccache_threshold
&&
302 cred
->ccache_obtained
> CRED_UNINITIALISED
) {
304 bool expired
= false;
305 ret
= krb5_cc_get_lifetime(cred
->ccache
->smb_krb5_context
->krb5_context
,
306 cred
->ccache
->ccache
, &lifetime
);
307 if (ret
== KRB5_CC_END
) {
308 /* If we have a particular ccache set, without
309 * an initial ticket, then assume there is a
311 } else if (ret
== 0) {
313 DEBUG(3, ("Ticket in credentials cache for %s expired, will refresh\n",
314 cli_credentials_get_principal(cred
, cred
)));
316 } else if (lifetime
< 300) {
317 DEBUG(3, ("Ticket in credentials cache for %s will shortly expire (%u secs), will refresh\n",
318 cli_credentials_get_principal(cred
, cred
), (unsigned int)lifetime
));
322 (*error_string
) = talloc_asprintf(cred
, "failed to get ccache lifetime: %s\n",
323 smb_get_krb5_error_message(cred
->ccache
->smb_krb5_context
->krb5_context
,
328 DEBUG(5, ("Ticket in credentials cache for %s will expire in %u secs\n",
329 cli_credentials_get_principal(cred
, cred
), (unsigned int)lifetime
));
336 if (cli_credentials_is_anonymous(cred
)) {
337 (*error_string
) = "Cannot get anonymous kerberos credentials";
341 ret
= cli_credentials_new_ccache(cred
, lp_ctx
, ccache_name
, ccc
, error_string
);
346 ret
= kinit_to_ccache(cred
, cred
, (*ccc
)->smb_krb5_context
, event_ctx
, (*ccc
)->ccache
, &obtained
, error_string
);
351 ret
= cli_credentials_set_from_ccache(cred
, *ccc
,
352 obtained
, error_string
);
355 cred
->ccache_obtained
= cred
->principal_obtained
;
359 cli_credentials_invalidate_client_gss_creds(cred
, cred
->ccache_obtained
);
363 _PUBLIC_
int cli_credentials_get_ccache(struct cli_credentials
*cred
,
364 struct tevent_context
*event_ctx
,
365 struct loadparm_context
*lp_ctx
,
366 struct ccache_container
**ccc
,
367 const char **error_string
)
369 return cli_credentials_get_named_ccache(cred
, event_ctx
, lp_ctx
, NULL
, ccc
, error_string
);
372 /* We have good reason to think the ccache in these credentials is invalid - blow it away */
373 static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials
*cred
)
375 if (cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
376 talloc_unlink(cred
, cred
->client_gss_creds
);
377 cred
->client_gss_creds
= NULL
;
379 cred
->client_gss_creds_obtained
= CRED_UNINITIALISED
;
382 void cli_credentials_invalidate_client_gss_creds(struct cli_credentials
*cred
,
383 enum credentials_obtained obtained
)
385 /* If the caller just changed the username/password etc, then
386 * any cached credentials are now invalid */
387 if (obtained
>= cred
->client_gss_creds_obtained
) {
388 if (cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
389 talloc_unlink(cred
, cred
->client_gss_creds
);
390 cred
->client_gss_creds
= NULL
;
392 cred
->client_gss_creds_obtained
= CRED_UNINITIALISED
;
394 /* Now that we know that the data is 'this specified', then
395 * don't allow something less 'known' to be returned as a
396 * ccache. Ie, if the username is on the command line, we
397 * don't want to later guess to use a file-based ccache */
398 if (obtained
> cred
->client_gss_creds_threshold
) {
399 cred
->client_gss_creds_threshold
= obtained
;
403 /* We have good reason to think this CCACHE is invalid. Blow it away */
404 static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials
*cred
)
406 if (cred
->ccache_obtained
> CRED_UNINITIALISED
) {
407 talloc_unlink(cred
, cred
->ccache
);
410 cred
->ccache_obtained
= CRED_UNINITIALISED
;
412 cli_credentials_unconditionally_invalidate_client_gss_creds(cred
);
415 _PUBLIC_
void cli_credentials_invalidate_ccache(struct cli_credentials
*cred
,
416 enum credentials_obtained obtained
)
418 /* If the caller just changed the username/password etc, then
419 * any cached credentials are now invalid */
420 if (obtained
>= cred
->ccache_obtained
) {
421 if (cred
->ccache_obtained
> CRED_UNINITIALISED
) {
422 talloc_unlink(cred
, cred
->ccache
);
425 cred
->ccache_obtained
= CRED_UNINITIALISED
;
427 /* Now that we know that the data is 'this specified', then
428 * don't allow something less 'known' to be returned as a
429 * ccache. i.e, if the username is on the command line, we
430 * don't want to later guess to use a file-based ccache */
431 if (obtained
> cred
->ccache_threshold
) {
432 cred
->ccache_threshold
= obtained
;
435 cli_credentials_invalidate_client_gss_creds(cred
,
439 static int free_gssapi_creds(struct gssapi_creds_container
*gcc
)
442 (void)gss_release_cred(&min_stat
, &gcc
->creds
);
446 _PUBLIC_
int cli_credentials_get_client_gss_creds(struct cli_credentials
*cred
,
447 struct tevent_context
*event_ctx
,
448 struct loadparm_context
*lp_ctx
,
449 struct gssapi_creds_container
**_gcc
,
450 const char **error_string
)
453 OM_uint32 maj_stat
, min_stat
;
454 struct gssapi_creds_container
*gcc
;
455 struct ccache_container
*ccache
;
456 gss_buffer_desc empty_buffer
= GSS_C_EMPTY_BUFFER
;
457 krb5_enctype
*etypes
= NULL
;
459 if (cred
->client_gss_creds_obtained
>= cred
->client_gss_creds_threshold
&&
460 cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
461 bool expired
= false;
462 OM_uint32 lifetime
= 0;
463 gss_cred_usage_t usage
= 0;
464 maj_stat
= gss_inquire_cred(&min_stat
, cred
->client_gss_creds
->creds
,
465 NULL
, &lifetime
, &usage
, NULL
);
466 if (maj_stat
== GSS_S_CREDENTIALS_EXPIRED
) {
467 DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred
, cred
)));
469 } else if (maj_stat
== GSS_S_COMPLETE
&& lifetime
< 300) {
470 DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred
, cred
), lifetime
));
472 } else if (maj_stat
!= GSS_S_COMPLETE
) {
473 *error_string
= talloc_asprintf(cred
, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
474 gssapi_error_string(cred
, maj_stat
, min_stat
, NULL
));
478 cli_credentials_unconditionally_invalidate_client_gss_creds(cred
);
480 DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n",
481 cli_credentials_get_principal(cred
, cred
), (unsigned int)lifetime
));
483 *_gcc
= cred
->client_gss_creds
;
488 ret
= cli_credentials_get_ccache(cred
, event_ctx
, lp_ctx
,
489 &ccache
, error_string
);
491 if (cli_credentials_get_kerberos_state(cred
) == CRED_MUST_USE_KERBEROS
) {
492 DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string
));
494 DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string
));
499 gcc
= talloc(cred
, struct gssapi_creds_container
);
501 (*error_string
) = error_message(ENOMEM
);
505 maj_stat
= gss_krb5_import_cred(&min_stat
, ccache
->ccache
, NULL
, NULL
,
507 if ((maj_stat
== GSS_S_FAILURE
) && (min_stat
== (OM_uint32
)KRB5_CC_END
|| min_stat
== (OM_uint32
) KRB5_CC_NOTFOUND
)) {
508 /* This CCACHE is no good. Ensure we don't use it again */
509 cli_credentials_unconditionally_invalidate_ccache(cred
);
511 /* Now try again to get a ccache */
512 ret
= cli_credentials_get_ccache(cred
, event_ctx
, lp_ctx
,
513 &ccache
, error_string
);
515 DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret
)));
519 maj_stat
= gss_krb5_import_cred(&min_stat
, ccache
->ccache
, NULL
, NULL
,
531 (*error_string
) = talloc_asprintf(cred
, "gss_krb5_import_cred failed: %s", error_message(ret
));
536 * transfer the enctypes from the smb_krb5_context to the gssapi layer
538 * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
539 * to configure the enctypes via the krb5.conf.
541 * And the gss_init_sec_context() creates it's own krb5_context and
542 * the TGS-REQ had all enctypes in it and only the ones configured
543 * and used for the AS-REQ, so it wasn't possible to disable the usage
546 min_stat
= krb5_get_default_in_tkt_etypes(ccache
->smb_krb5_context
->krb5_context
,
550 OM_uint32 num_ktypes
;
552 for (num_ktypes
= 0; etypes
[num_ktypes
]; num_ktypes
++);
554 maj_stat
= gss_krb5_set_allowable_enctypes(&min_stat
, gcc
->creds
,
565 (*error_string
) = talloc_asprintf(cred
, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret
));
570 /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
571 maj_stat
= gss_set_cred_option(&min_stat
, &gcc
->creds
,
572 GSS_KRB5_CRED_NO_CI_FLAGS_X
,
581 (*error_string
) = talloc_asprintf(cred
, "gss_set_cred_option failed: %s", error_message(ret
));
585 cred
->client_gss_creds_obtained
= cred
->ccache_obtained
;
586 talloc_set_destructor(gcc
, free_gssapi_creds
);
587 cred
->client_gss_creds
= gcc
;
593 Set a gssapi cred_id_t into the credentials system. (Client case)
595 This grabs the credentials both 'intact' and getting the krb5
596 ccache out of it. This routine can be generalised in future for
597 the case where we deal with GSSAPI mechs other than krb5.
599 On sucess, the caller must not free gssapi_cred, as it now belongs
600 to the credentials system.
603 int cli_credentials_set_client_gss_creds(struct cli_credentials
*cred
,
604 struct loadparm_context
*lp_ctx
,
605 gss_cred_id_t gssapi_cred
,
606 enum credentials_obtained obtained
,
607 const char **error_string
)
610 OM_uint32 maj_stat
, min_stat
;
611 struct ccache_container
*ccc
;
612 struct gssapi_creds_container
*gcc
;
613 if (cred
->client_gss_creds_obtained
> obtained
) {
617 gcc
= talloc(cred
, struct gssapi_creds_container
);
619 (*error_string
) = error_message(ENOMEM
);
623 ret
= cli_credentials_new_ccache(cred
, lp_ctx
, NULL
, &ccc
, error_string
);
628 maj_stat
= gss_krb5_copy_ccache(&min_stat
,
629 gssapi_cred
, ccc
->ccache
);
637 (*error_string
) = error_message(ENOMEM
);
642 ret
= cli_credentials_set_from_ccache(cred
, ccc
, obtained
, error_string
);
645 cred
->ccache_obtained
= obtained
;
647 gcc
->creds
= gssapi_cred
;
648 talloc_set_destructor(gcc
, free_gssapi_creds
);
650 /* set the clinet_gss_creds_obtained here, as it just
651 got set to UNINITIALISED by the calls above */
652 cred
->client_gss_creds_obtained
= obtained
;
653 cred
->client_gss_creds
= gcc
;
658 /* Get the keytab (actually, a container containing the krb5_keytab)
659 * attached to this context. If this hasn't been done or set before,
660 * it will be generated from the password.
662 _PUBLIC_
int cli_credentials_get_keytab(struct cli_credentials
*cred
,
663 struct loadparm_context
*lp_ctx
,
664 struct keytab_container
**_ktc
)
667 struct keytab_container
*ktc
;
668 struct smb_krb5_context
*smb_krb5_context
;
669 const char *keytab_name
;
673 if (cred
->keytab_obtained
>= (MAX(cred
->principal_obtained
,
674 cred
->username_obtained
))) {
675 *_ktc
= cred
->keytab
;
679 if (cli_credentials_is_anonymous(cred
)) {
683 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
,
689 mem_ctx
= talloc_new(cred
);
694 ret
= smb_krb5_create_memory_keytab(mem_ctx
,
695 smb_krb5_context
->krb5_context
,
696 cli_credentials_get_password(cred
),
697 cli_credentials_get_username(cred
),
698 cli_credentials_get_realm(cred
),
699 cli_credentials_get_kvno(cred
),
700 &keytab
, &keytab_name
);
702 talloc_free(mem_ctx
);
706 ret
= smb_krb5_get_keytab_container(mem_ctx
, smb_krb5_context
,
707 keytab
, keytab_name
, &ktc
);
709 talloc_free(mem_ctx
);
713 cred
->keytab_obtained
= (MAX(cred
->principal_obtained
,
714 cred
->username_obtained
));
716 talloc_steal(cred
, ktc
);
718 *_ktc
= cred
->keytab
;
719 talloc_free(mem_ctx
);
723 /* Given the name of a keytab (presumably in the format
724 * FILE:/etc/krb5.keytab), open it and attach it */
726 _PUBLIC_
int cli_credentials_set_keytab_name(struct cli_credentials
*cred
,
727 struct loadparm_context
*lp_ctx
,
728 const char *keytab_name
,
729 enum credentials_obtained obtained
)
732 struct keytab_container
*ktc
;
733 struct smb_krb5_context
*smb_krb5_context
;
736 if (cred
->keytab_obtained
>= obtained
) {
740 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
, &smb_krb5_context
);
745 mem_ctx
= talloc_new(cred
);
750 ret
= smb_krb5_get_keytab_container(mem_ctx
, smb_krb5_context
,
751 NULL
, keytab_name
, &ktc
);
756 cred
->keytab_obtained
= obtained
;
758 talloc_steal(cred
, ktc
);
760 talloc_free(mem_ctx
);
765 /* Get server gss credentials (in gsskrb5, this means the keytab) */
767 _PUBLIC_
int cli_credentials_get_server_gss_creds(struct cli_credentials
*cred
,
768 struct loadparm_context
*lp_ctx
,
769 struct gssapi_creds_container
**_gcc
)
772 OM_uint32 maj_stat
, min_stat
;
773 struct gssapi_creds_container
*gcc
;
774 struct keytab_container
*ktc
;
775 struct smb_krb5_context
*smb_krb5_context
;
777 krb5_principal princ
;
778 const char *error_string
;
779 enum credentials_obtained obtained
;
781 mem_ctx
= talloc_new(cred
);
786 ret
= cli_credentials_get_krb5_context(cred
, lp_ctx
, &smb_krb5_context
);
791 ret
= principal_from_credentials(mem_ctx
, cred
, smb_krb5_context
, &princ
, &obtained
, &error_string
);
793 DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n",
795 talloc_free(mem_ctx
);
799 if (cred
->server_gss_creds_obtained
>= (MAX(cred
->keytab_obtained
, obtained
))) {
800 talloc_free(mem_ctx
);
801 *_gcc
= cred
->server_gss_creds
;
805 ret
= cli_credentials_get_keytab(cred
, lp_ctx
, &ktc
);
807 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret
)));
811 gcc
= talloc(cred
, struct gssapi_creds_container
);
813 talloc_free(mem_ctx
);
817 if (obtained
< CRED_SPECIFIED
) {
818 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
819 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, NULL
, ktc
->keytab
,
822 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
823 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, princ
, ktc
->keytab
,
834 cred
->server_gss_creds_obtained
= cred
->keytab_obtained
;
835 talloc_set_destructor(gcc
, free_gssapi_creds
);
836 cred
->server_gss_creds
= gcc
;
839 talloc_free(mem_ctx
);
847 _PUBLIC_
void cli_credentials_set_kvno(struct cli_credentials
*cred
,
854 * Return Kerberos KVNO
857 _PUBLIC_
int cli_credentials_get_kvno(struct cli_credentials
*cred
)
863 const char *cli_credentials_get_salt_principal(struct cli_credentials
*cred
)
865 return cred
->salt_principal
;
868 _PUBLIC_
void cli_credentials_set_salt_principal(struct cli_credentials
*cred
, const char *principal
)
870 talloc_free(cred
->salt_principal
);
871 cred
->salt_principal
= talloc_strdup(cred
, principal
);
874 /* The 'impersonate_principal' is used to allow one Kerberos principal
875 * (and it's associated keytab etc) to impersonate another. The
876 * ability to do this is controlled by the KDC, but it is generally
877 * permitted to impersonate anyone to yourself. This allows any
878 * member of the domain to get the groups of a user. This is also
879 * known as S4U2Self */
881 _PUBLIC_
const char *cli_credentials_get_impersonate_principal(struct cli_credentials
*cred
)
883 return cred
->impersonate_principal
;
887 * The 'self_service' is the service principal that
888 * represents the same object (by its objectSid)
889 * as the client principal (typically our machine account).
890 * When trying to impersonate 'impersonate_principal' with
893 _PUBLIC_
const char *cli_credentials_get_self_service(struct cli_credentials
*cred
)
895 return cred
->self_service
;
898 _PUBLIC_
void cli_credentials_set_impersonate_principal(struct cli_credentials
*cred
,
899 const char *principal
,
900 const char *self_service
)
902 talloc_free(cred
->impersonate_principal
);
903 cred
->impersonate_principal
= talloc_strdup(cred
, principal
);
904 talloc_free(cred
->self_service
);
905 cred
->self_service
= talloc_strdup(cred
, self_service
);
906 cli_credentials_set_kerberos_state(cred
, CRED_MUST_USE_KERBEROS
);
910 * when impersonating for S4U2proxy we need to set the target principal.
911 * Similarly, we may only be authorized to do general impersonation to
912 * some particular services.
914 * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
916 * NULL means that tickets will be obtained for the krbtgt service.
919 const char *cli_credentials_get_target_service(struct cli_credentials
*cred
)
921 return cred
->target_service
;
924 _PUBLIC_
void cli_credentials_set_target_service(struct cli_credentials
*cred
, const char *target_service
)
926 talloc_free(cred
->target_service
);
927 cred
->target_service
= talloc_strdup(cred
, target_service
);