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_util.h"
32 #include "param/param.h"
34 static void cli_credentials_invalidate_client_gss_creds(
35 struct cli_credentials *cred,
36 enum credentials_obtained obtained);
38 _PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred,
39 struct loadparm_context *lp_ctx,
40 struct smb_krb5_context **smb_krb5_context)
43 if (cred->smb_krb5_context) {
44 *smb_krb5_context = cred->smb_krb5_context;
48 ret = smb_krb5_init_context(cred, NULL, lp_ctx,
49 &cred->smb_krb5_context);
51 cred->smb_krb5_context = NULL;
54 *smb_krb5_context = cred->smb_krb5_context;
58 /* For most predictable behaviour, this needs to be called directly after the cli_credentials_init(),
59 * otherwise we may still have references to the old smb_krb5_context in a credential cache etc
61 _PUBLIC_ NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred,
62 struct smb_krb5_context *smb_krb5_context)
64 if (smb_krb5_context == NULL) {
65 talloc_unlink(cred, cred->smb_krb5_context);
66 cred->smb_krb5_context = NULL;
70 if (!talloc_reference(cred, smb_krb5_context)) {
71 return NT_STATUS_NO_MEMORY;
73 cred->smb_krb5_context = smb_krb5_context;
77 static int cli_credentials_set_from_ccache(struct cli_credentials *cred,
78 struct ccache_container *ccache,
79 enum credentials_obtained obtained,
80 const char **error_string)
87 if (cred->ccache_obtained > obtained) {
91 ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context,
92 ccache->ccache, &princ);
95 (*error_string) = talloc_asprintf(cred, "failed to get principal from ccache: %s\n",
96 smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context,
101 ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name);
103 (*error_string) = talloc_asprintf(cred, "failed to unparse principal from ccache: %s\n",
104 smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context,
109 cli_credentials_set_principal(cred, name, obtained);
113 krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ);
115 /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */
116 cred->ccache_obtained = obtained;
121 /* Free a memory ccache */
122 static int free_mccache(struct ccache_container *ccc)
124 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache);
129 /* Free a disk-based ccache */
130 static int free_dccache(struct ccache_container *ccc) {
131 krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache);
136 _PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred,
137 struct loadparm_context *lp_ctx,
139 enum credentials_obtained obtained,
140 const char **error_string)
143 krb5_principal princ;
144 struct ccache_container *ccc;
145 if (cred->ccache_obtained > obtained) {
149 ccc = talloc(cred, struct ccache_container);
151 (*error_string) = error_message(ENOMEM);
155 ret = cli_credentials_get_krb5_context(cred, lp_ctx,
156 &ccc->smb_krb5_context);
158 (*error_string) = error_message(ret);
162 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
164 (*error_string) = error_message(ENOMEM);
169 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
171 (*error_string) = talloc_asprintf(cred, "failed to read krb5 ccache: %s: %s\n",
173 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
179 ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
181 (*error_string) = talloc_asprintf(cred, "failed to read default krb5 ccache: %s\n",
182 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
189 talloc_set_destructor(ccc, free_dccache);
191 ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
194 krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ);
195 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
198 (*error_string) = error_message(ret);
203 cred->ccache_obtained = obtained;
204 talloc_steal(cred, ccc);
206 cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
213 static int cli_credentials_new_ccache(struct cli_credentials *cred,
214 struct loadparm_context *lp_ctx,
216 struct ccache_container **_ccc,
217 const char **error_string)
219 bool must_free_cc_name = false;
221 struct ccache_container *ccc = talloc(cred, struct ccache_container);
226 ret = cli_credentials_get_krb5_context(cred, lp_ctx,
227 &ccc->smb_krb5_context);
230 (*error_string) = talloc_asprintf(cred, "Failed to get krb5_context: %s",
234 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
236 (*error_string) = strerror(ENOMEM);
241 must_free_cc_name = true;
243 if (lpcfg_parm_bool(lp_ctx, NULL, "credentials", "krb5_cc_file", false)) {
244 ccache_name = talloc_asprintf(ccc, "FILE:/tmp/krb5_cc_samba_%u_%p",
245 (unsigned int)getpid(), ccc);
247 ccache_name = talloc_asprintf(ccc, "MEMORY:%p",
253 (*error_string) = strerror(ENOMEM);
258 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name,
261 (*error_string) = talloc_asprintf(cred, "failed to resolve a krb5 ccache (%s): %s\n",
263 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
265 talloc_free(ccache_name);
270 if (strncasecmp(ccache_name, "MEMORY:", 7) == 0) {
271 talloc_set_destructor(ccc, free_mccache);
273 talloc_set_destructor(ccc, free_dccache);
276 if (must_free_cc_name) {
277 talloc_free(ccache_name);
285 _PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
286 struct tevent_context *event_ctx,
287 struct loadparm_context *lp_ctx,
289 struct ccache_container **ccc,
290 const char **error_string)
293 enum credentials_obtained obtained;
295 if (cred->machine_account_pending) {
296 cli_credentials_set_machine_account(cred, lp_ctx);
299 if (cred->ccache_obtained >= cred->ccache_threshold &&
300 cred->ccache_obtained > CRED_UNINITIALISED) {
302 bool expired = false;
303 ret = krb5_cc_get_lifetime(cred->ccache->smb_krb5_context->krb5_context,
304 cred->ccache->ccache, &lifetime);
305 if (ret == KRB5_CC_END) {
306 /* If we have a particular ccache set, without
307 * an initial ticket, then assume there is a
309 } else if (ret == 0) {
311 DEBUG(3, ("Ticket in credentials cache for %s expired, will refresh\n",
312 cli_credentials_get_principal(cred, cred)));
314 } else if (lifetime < 300) {
315 DEBUG(3, ("Ticket in credentials cache for %s will shortly expire (%u secs), will refresh\n",
316 cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
320 (*error_string) = talloc_asprintf(cred, "failed to get ccache lifetime: %s\n",
321 smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context,
326 DEBUG(5, ("Ticket in credentials cache for %s will expire in %u secs\n",
327 cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
334 if (cli_credentials_is_anonymous(cred)) {
335 (*error_string) = "Cannot get anonymous kerberos credentials";
339 ret = cli_credentials_new_ccache(cred, lp_ctx, ccache_name, ccc, error_string);
344 ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, event_ctx, (*ccc)->ccache, &obtained, error_string);
349 ret = cli_credentials_set_from_ccache(cred, *ccc,
350 obtained, error_string);
353 cred->ccache_obtained = cred->principal_obtained;
357 cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
361 _PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred,
362 struct tevent_context *event_ctx,
363 struct loadparm_context *lp_ctx,
364 struct ccache_container **ccc,
365 const char **error_string)
367 return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string);
370 /* We have good reason to think the ccache in these credentials is invalid - blow it away */
371 static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials *cred)
373 if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
374 talloc_unlink(cred, cred->client_gss_creds);
375 cred->client_gss_creds = NULL;
377 cred->client_gss_creds_obtained = CRED_UNINITIALISED;
380 void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred,
381 enum credentials_obtained obtained)
383 /* If the caller just changed the username/password etc, then
384 * any cached credentials are now invalid */
385 if (obtained >= cred->client_gss_creds_obtained) {
386 if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
387 talloc_unlink(cred, cred->client_gss_creds);
388 cred->client_gss_creds = NULL;
390 cred->client_gss_creds_obtained = CRED_UNINITIALISED;
392 /* Now that we know that the data is 'this specified', then
393 * don't allow something less 'known' to be returned as a
394 * ccache. Ie, if the username is on the command line, we
395 * don't want to later guess to use a file-based ccache */
396 if (obtained > cred->client_gss_creds_threshold) {
397 cred->client_gss_creds_threshold = obtained;
401 /* We have good reason to think this CCACHE is invalid. Blow it away */
402 static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred)
404 if (cred->ccache_obtained > CRED_UNINITIALISED) {
405 talloc_unlink(cred, cred->ccache);
408 cred->ccache_obtained = CRED_UNINITIALISED;
410 cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
413 _PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred,
414 enum credentials_obtained obtained)
416 /* If the caller just changed the username/password etc, then
417 * any cached credentials are now invalid */
418 if (obtained >= cred->ccache_obtained) {
419 if (cred->ccache_obtained > CRED_UNINITIALISED) {
420 talloc_unlink(cred, cred->ccache);
423 cred->ccache_obtained = CRED_UNINITIALISED;
425 /* Now that we know that the data is 'this specified', then
426 * don't allow something less 'known' to be returned as a
427 * ccache. i.e, if the username is on the command line, we
428 * don't want to later guess to use a file-based ccache */
429 if (obtained > cred->ccache_threshold) {
430 cred->ccache_threshold = obtained;
433 cli_credentials_invalidate_client_gss_creds(cred,
437 static int free_gssapi_creds(struct gssapi_creds_container *gcc)
440 (void)gss_release_cred(&min_stat, &gcc->creds);
444 _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
445 struct tevent_context *event_ctx,
446 struct loadparm_context *lp_ctx,
447 struct gssapi_creds_container **_gcc,
448 const char **error_string)
451 OM_uint32 maj_stat, min_stat;
452 struct gssapi_creds_container *gcc;
453 struct ccache_container *ccache;
454 gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
455 krb5_enctype *etypes = NULL;
457 if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold &&
458 cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
459 bool expired = false;
460 OM_uint32 lifetime = 0;
461 gss_cred_usage_t usage = 0;
462 maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds,
463 NULL, &lifetime, &usage, NULL);
464 if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) {
465 DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred)));
467 } else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) {
468 DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime));
470 } else if (maj_stat != GSS_S_COMPLETE) {
471 *error_string = talloc_asprintf(cred, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
472 gssapi_error_string(cred, maj_stat, min_stat, NULL));
476 cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
478 DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n",
479 cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
481 *_gcc = cred->client_gss_creds;
486 ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
487 &ccache, error_string);
489 if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) {
490 DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string));
492 DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string));
497 gcc = talloc(cred, struct gssapi_creds_container);
499 (*error_string) = error_message(ENOMEM);
503 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
505 if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) {
506 /* This CCACHE is no good. Ensure we don't use it again */
507 cli_credentials_unconditionally_invalidate_ccache(cred);
509 /* Now try again to get a ccache */
510 ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
511 &ccache, error_string);
513 DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret)));
517 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
529 (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret));
534 * transfer the enctypes from the smb_krb5_context to the gssapi layer
536 * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
537 * to configure the enctypes via the krb5.conf.
539 * And the gss_init_sec_context() creates it's own krb5_context and
540 * the TGS-REQ had all enctypes in it and only the ones configured
541 * and used for the AS-REQ, so it wasn't possible to disable the usage
544 min_stat = krb5_get_default_in_tkt_etypes(ccache->smb_krb5_context->krb5_context,
548 OM_uint32 num_ktypes;
550 for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++);
552 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds,
563 (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret));
568 /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
569 maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
570 GSS_KRB5_CRED_NO_CI_FLAGS_X,
579 (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret));
583 cred->client_gss_creds_obtained = cred->ccache_obtained;
584 talloc_set_destructor(gcc, free_gssapi_creds);
585 cred->client_gss_creds = gcc;
591 Set a gssapi cred_id_t into the credentials system. (Client case)
593 This grabs the credentials both 'intact' and getting the krb5
594 ccache out of it. This routine can be generalised in future for
595 the case where we deal with GSSAPI mechs other than krb5.
597 On sucess, the caller must not free gssapi_cred, as it now belongs
598 to the credentials system.
601 int cli_credentials_set_client_gss_creds(struct cli_credentials *cred,
602 struct loadparm_context *lp_ctx,
603 gss_cred_id_t gssapi_cred,
604 enum credentials_obtained obtained,
605 const char **error_string)
608 OM_uint32 maj_stat, min_stat;
609 struct ccache_container *ccc;
610 struct gssapi_creds_container *gcc;
611 if (cred->client_gss_creds_obtained > obtained) {
615 gcc = talloc(cred, struct gssapi_creds_container);
617 (*error_string) = error_message(ENOMEM);
621 ret = cli_credentials_new_ccache(cred, lp_ctx, NULL, &ccc, error_string);
626 maj_stat = gss_krb5_copy_ccache(&min_stat,
627 gssapi_cred, ccc->ccache);
635 (*error_string) = error_message(ENOMEM);
640 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
643 cred->ccache_obtained = obtained;
645 gcc->creds = gssapi_cred;
646 talloc_set_destructor(gcc, free_gssapi_creds);
648 /* set the clinet_gss_creds_obtained here, as it just
649 got set to UNINITIALISED by the calls above */
650 cred->client_gss_creds_obtained = obtained;
651 cred->client_gss_creds = gcc;
656 /* Get the keytab (actually, a container containing the krb5_keytab)
657 * attached to this context. If this hasn't been done or set before,
658 * it will be generated from the password.
660 _PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred,
661 struct loadparm_context *lp_ctx,
662 struct keytab_container **_ktc)
665 struct keytab_container *ktc;
666 struct smb_krb5_context *smb_krb5_context;
669 if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
670 cred->username_obtained))) {
671 *_ktc = cred->keytab;
675 if (cli_credentials_is_anonymous(cred)) {
679 ret = cli_credentials_get_krb5_context(cred, lp_ctx,
685 mem_ctx = talloc_new(cred);
690 ret = smb_krb5_create_memory_keytab(mem_ctx, cred,
691 smb_krb5_context, &ktc);
693 talloc_free(mem_ctx);
697 cred->keytab_obtained = (MAX(cred->principal_obtained,
698 cred->username_obtained));
700 talloc_steal(cred, ktc);
702 *_ktc = cred->keytab;
703 talloc_free(mem_ctx);
707 /* Given the name of a keytab (presumably in the format
708 * FILE:/etc/krb5.keytab), open it and attach it */
710 _PUBLIC_ int cli_credentials_set_keytab_name(struct cli_credentials *cred,
711 struct loadparm_context *lp_ctx,
712 const char *keytab_name,
713 enum credentials_obtained obtained)
716 struct keytab_container *ktc;
717 struct smb_krb5_context *smb_krb5_context;
720 if (cred->keytab_obtained >= obtained) {
724 ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
729 mem_ctx = talloc_new(cred);
734 ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context,
740 cred->keytab_obtained = obtained;
742 talloc_steal(cred, ktc);
744 talloc_free(mem_ctx);
749 /* Get server gss credentials (in gsskrb5, this means the keytab) */
751 _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
752 struct loadparm_context *lp_ctx,
753 struct gssapi_creds_container **_gcc)
756 OM_uint32 maj_stat, min_stat;
757 struct gssapi_creds_container *gcc;
758 struct keytab_container *ktc;
759 struct smb_krb5_context *smb_krb5_context;
761 krb5_principal princ;
762 const char *error_string;
763 enum credentials_obtained obtained;
765 mem_ctx = talloc_new(cred);
770 ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
775 ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string);
777 DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n",
779 talloc_free(mem_ctx);
783 if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) {
784 talloc_free(mem_ctx);
785 *_gcc = cred->server_gss_creds;
789 ret = cli_credentials_get_keytab(cred, lp_ctx, &ktc);
791 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
795 gcc = talloc(cred, struct gssapi_creds_container);
797 talloc_free(mem_ctx);
801 if (obtained < CRED_SPECIFIED) {
802 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
803 maj_stat = gss_krb5_import_cred(&min_stat, NULL, NULL, ktc->keytab,
806 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
807 maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab,
818 cred->server_gss_creds_obtained = cred->keytab_obtained;
819 talloc_set_destructor(gcc, free_gssapi_creds);
820 cred->server_gss_creds = gcc;
823 talloc_free(mem_ctx);
831 _PUBLIC_ void cli_credentials_set_kvno(struct cli_credentials *cred,
838 * Return Kerberos KVNO
841 _PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred)
847 const char *cli_credentials_get_salt_principal(struct cli_credentials *cred)
849 return cred->salt_principal;
852 _PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal)
854 talloc_free(cred->salt_principal);
855 cred->salt_principal = talloc_strdup(cred, principal);
858 /* The 'impersonate_principal' is used to allow one Kerberos principal
859 * (and it's associated keytab etc) to impersonate another. The
860 * ability to do this is controlled by the KDC, but it is generally
861 * permitted to impersonate anyone to yourself. This allows any
862 * member of the domain to get the groups of a user. This is also
863 * known as S4U2Self */
865 _PUBLIC_ const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred)
867 return cred->impersonate_principal;
871 * The 'self_service' is the service principal that
872 * represents the same object (by its objectSid)
873 * as the client principal (typically our machine account).
874 * When trying to impersonate 'impersonate_principal' with
877 _PUBLIC_ const char *cli_credentials_get_self_service(struct cli_credentials *cred)
879 return cred->self_service;
882 _PUBLIC_ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred,
883 const char *principal,
884 const char *self_service)
886 talloc_free(cred->impersonate_principal);
887 cred->impersonate_principal = talloc_strdup(cred, principal);
888 talloc_free(cred->self_service);
889 cred->self_service = talloc_strdup(cred, self_service);
890 cli_credentials_set_kerberos_state(cred, CRED_MUST_USE_KERBEROS);
894 * when impersonating for S4U2proxy we need to set the target principal.
895 * Similarly, we may only be authorized to do general impersonation to
896 * some particular services.
898 * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
900 * NULL means that tickets will be obtained for the krbtgt service.
903 const char *cli_credentials_get_target_service(struct cli_credentials *cred)
905 return cred->target_service;
908 _PUBLIC_ void cli_credentials_set_target_service(struct cli_credentials *cred, const char *target_service)
910 talloc_free(cred->target_service);
911 cred->target_service = talloc_strdup(cred, target_service);