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 "param/param.h"
33 _PUBLIC_
int cli_credentials_get_krb5_context(struct cli_credentials
*cred
,
34 struct tevent_context
*event_ctx
,
35 struct loadparm_context
*lp_ctx
,
36 struct smb_krb5_context
**smb_krb5_context
)
39 if (cred
->smb_krb5_context
) {
40 *smb_krb5_context
= cred
->smb_krb5_context
;
44 ret
= smb_krb5_init_context(cred
, event_ctx
, lp_ctx
,
45 &cred
->smb_krb5_context
);
47 cred
->smb_krb5_context
= NULL
;
50 *smb_krb5_context
= cred
->smb_krb5_context
;
54 /* This needs to be called directly after the cli_credentials_init(),
55 * otherwise we might have problems with the krb5 context already
58 _PUBLIC_ NTSTATUS
cli_credentials_set_krb5_context(struct cli_credentials
*cred
,
59 struct smb_krb5_context
*smb_krb5_context
)
61 if (!talloc_reference(cred
, smb_krb5_context
)) {
62 return NT_STATUS_NO_MEMORY
;
64 cred
->smb_krb5_context
= smb_krb5_context
;
68 static int cli_credentials_set_from_ccache(struct cli_credentials
*cred
,
69 struct ccache_container
*ccache
,
70 enum credentials_obtained obtained
,
71 const char **error_string
)
78 if (cred
->ccache_obtained
> obtained
) {
82 ret
= krb5_cc_get_principal(ccache
->smb_krb5_context
->krb5_context
,
83 ccache
->ccache
, &princ
);
86 (*error_string
) = talloc_asprintf(cred
, "failed to get principal from ccache: %s\n",
87 smb_get_krb5_error_message(ccache
->smb_krb5_context
->krb5_context
,
92 ret
= krb5_unparse_name(ccache
->smb_krb5_context
->krb5_context
, princ
, &name
);
94 (*error_string
) = talloc_asprintf(cred
, "failed to unparse principal from ccache: %s\n",
95 smb_get_krb5_error_message(ccache
->smb_krb5_context
->krb5_context
,
100 cli_credentials_set_principal(cred
, name
, obtained
);
104 krb5_free_principal(ccache
->smb_krb5_context
->krb5_context
, princ
);
106 /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */
107 cred
->ccache_obtained
= obtained
;
112 /* Free a memory ccache */
113 static int free_mccache(struct ccache_container
*ccc
)
115 krb5_cc_destroy(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
);
120 /* Free a disk-based ccache */
121 static int free_dccache(struct ccache_container
*ccc
) {
122 krb5_cc_close(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
);
127 _PUBLIC_
int cli_credentials_set_ccache(struct cli_credentials
*cred
,
128 struct tevent_context
*event_ctx
,
129 struct loadparm_context
*lp_ctx
,
131 enum credentials_obtained obtained
,
132 const char **error_string
)
135 krb5_principal princ
;
136 struct ccache_container
*ccc
;
137 if (cred
->ccache_obtained
> obtained
) {
141 ccc
= talloc(cred
, struct ccache_container
);
143 (*error_string
) = error_message(ENOMEM
);
147 ret
= cli_credentials_get_krb5_context(cred
, event_ctx
, lp_ctx
,
148 &ccc
->smb_krb5_context
);
150 (*error_string
) = error_message(ret
);
154 if (!talloc_reference(ccc
, ccc
->smb_krb5_context
)) {
156 (*error_string
) = error_message(ENOMEM
);
161 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, name
, &ccc
->ccache
);
163 (*error_string
) = talloc_asprintf(cred
, "failed to read krb5 ccache: %s: %s\n",
165 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
171 ret
= krb5_cc_default(ccc
->smb_krb5_context
->krb5_context
, &ccc
->ccache
);
173 (*error_string
) = talloc_asprintf(cred
, "failed to read default krb5 ccache: %s\n",
174 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
181 talloc_set_destructor(ccc
, free_dccache
);
183 ret
= krb5_cc_get_principal(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
, &princ
);
186 krb5_free_principal(ccc
->smb_krb5_context
->krb5_context
, princ
);
187 ret
= cli_credentials_set_from_ccache(cred
, ccc
, obtained
, error_string
);
190 (*error_string
) = error_message(ret
);
195 cred
->ccache_obtained
= obtained
;
196 talloc_steal(cred
, ccc
);
198 cli_credentials_invalidate_client_gss_creds(cred
, cred
->ccache_obtained
);
205 static int cli_credentials_new_ccache(struct cli_credentials
*cred
,
206 struct tevent_context
*event_ctx
,
207 struct loadparm_context
*lp_ctx
,
209 struct ccache_container
**_ccc
,
210 const char **error_string
)
212 bool must_free_cc_name
= false;
214 struct ccache_container
*ccc
= talloc(cred
, struct ccache_container
);
219 ret
= cli_credentials_get_krb5_context(cred
, event_ctx
, lp_ctx
,
220 &ccc
->smb_krb5_context
);
223 (*error_string
) = talloc_asprintf(cred
, "Failed to get krb5_context: %s",
227 if (!talloc_reference(ccc
, ccc
->smb_krb5_context
)) {
229 (*error_string
) = strerror(ENOMEM
);
234 must_free_cc_name
= true;
235 ccache_name
= talloc_asprintf(ccc
, "MEMORY:%p",
240 (*error_string
) = strerror(ENOMEM
);
245 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, ccache_name
,
248 (*error_string
) = talloc_asprintf(cred
, "failed to resolve a krb5 ccache (%s): %s\n",
250 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
,
252 talloc_free(ccache_name
);
257 if (strncasecmp(ccache_name
, "MEMORY:", 7) == 0) {
258 talloc_set_destructor(ccc
, free_mccache
);
260 talloc_set_destructor(ccc
, free_dccache
);
263 if (must_free_cc_name
) {
264 talloc_free(ccache_name
);
272 _PUBLIC_
int cli_credentials_get_named_ccache(struct cli_credentials
*cred
,
273 struct tevent_context
*event_ctx
,
274 struct loadparm_context
*lp_ctx
,
276 struct ccache_container
**ccc
,
277 const char **error_string
)
280 enum credentials_obtained obtained
;
282 if (cred
->machine_account_pending
) {
283 cli_credentials_set_machine_account(cred
, lp_ctx
);
286 if (cred
->ccache_obtained
>= cred
->ccache_threshold
&&
287 cred
->ccache_obtained
> CRED_UNINITIALISED
) {
291 if (cli_credentials_is_anonymous(cred
)) {
292 (*error_string
) = "Cannot get anonymous kerberos credentials";
296 ret
= cli_credentials_new_ccache(cred
, event_ctx
, lp_ctx
, ccache_name
, ccc
, error_string
);
301 ret
= kinit_to_ccache(cred
, cred
, (*ccc
)->smb_krb5_context
, (*ccc
)->ccache
, &obtained
, error_string
);
306 ret
= cli_credentials_set_from_ccache(cred
, *ccc
,
307 obtained
, error_string
);
310 cred
->ccache_obtained
= cred
->principal_obtained
;
314 cli_credentials_invalidate_client_gss_creds(cred
, cred
->ccache_obtained
);
318 _PUBLIC_
int cli_credentials_get_ccache(struct cli_credentials
*cred
,
319 struct tevent_context
*event_ctx
,
320 struct loadparm_context
*lp_ctx
,
321 struct ccache_container
**ccc
,
322 const char **error_string
)
324 return cli_credentials_get_named_ccache(cred
, event_ctx
, lp_ctx
, NULL
, ccc
, error_string
);
327 /* We have good reason to think the ccache in these credentials is invalid - blow it away */
328 static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials
*cred
)
330 if (cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
331 talloc_unlink(cred
, cred
->client_gss_creds
);
332 cred
->client_gss_creds
= NULL
;
334 cred
->client_gss_creds_obtained
= CRED_UNINITIALISED
;
337 void cli_credentials_invalidate_client_gss_creds(struct cli_credentials
*cred
,
338 enum credentials_obtained obtained
)
340 /* If the caller just changed the username/password etc, then
341 * any cached credentials are now invalid */
342 if (obtained
>= cred
->client_gss_creds_obtained
) {
343 if (cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
344 talloc_unlink(cred
, cred
->client_gss_creds
);
345 cred
->client_gss_creds
= NULL
;
347 cred
->client_gss_creds_obtained
= CRED_UNINITIALISED
;
349 /* Now that we know that the data is 'this specified', then
350 * don't allow something less 'known' to be returned as a
351 * ccache. Ie, if the username is on the commmand line, we
352 * don't want to later guess to use a file-based ccache */
353 if (obtained
> cred
->client_gss_creds_threshold
) {
354 cred
->client_gss_creds_threshold
= obtained
;
358 /* We have good reason to think this CCACHE is invalid. Blow it away */
359 static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials
*cred
)
361 if (cred
->ccache_obtained
> CRED_UNINITIALISED
) {
362 talloc_unlink(cred
, cred
->ccache
);
365 cred
->ccache_obtained
= CRED_UNINITIALISED
;
367 cli_credentials_unconditionally_invalidate_client_gss_creds(cred
);
370 _PUBLIC_
void cli_credentials_invalidate_ccache(struct cli_credentials
*cred
,
371 enum credentials_obtained obtained
)
373 /* If the caller just changed the username/password etc, then
374 * any cached credentials are now invalid */
375 if (obtained
>= cred
->ccache_obtained
) {
376 if (cred
->ccache_obtained
> CRED_UNINITIALISED
) {
377 talloc_unlink(cred
, cred
->ccache
);
380 cred
->ccache_obtained
= CRED_UNINITIALISED
;
382 /* Now that we know that the data is 'this specified', then
383 * don't allow something less 'known' to be returned as a
384 * ccache. Ie, if the username is on the commmand line, we
385 * don't want to later guess to use a file-based ccache */
386 if (obtained
> cred
->ccache_threshold
) {
387 cred
->ccache_threshold
= obtained
;
390 cli_credentials_invalidate_client_gss_creds(cred
,
394 static int free_gssapi_creds(struct gssapi_creds_container
*gcc
)
396 OM_uint32 min_stat
, maj_stat
;
397 maj_stat
= gss_release_cred(&min_stat
, &gcc
->creds
);
401 _PUBLIC_
int cli_credentials_get_client_gss_creds(struct cli_credentials
*cred
,
402 struct tevent_context
*event_ctx
,
403 struct loadparm_context
*lp_ctx
,
404 struct gssapi_creds_container
**_gcc
,
405 const char **error_string
)
408 OM_uint32 maj_stat
, min_stat
;
409 struct gssapi_creds_container
*gcc
;
410 struct ccache_container
*ccache
;
411 gss_buffer_desc empty_buffer
= GSS_C_EMPTY_BUFFER
;
412 krb5_enctype
*etypes
= NULL
;
414 if (cred
->client_gss_creds_obtained
>= cred
->client_gss_creds_threshold
&&
415 cred
->client_gss_creds_obtained
> CRED_UNINITIALISED
) {
416 *_gcc
= cred
->client_gss_creds
;
420 ret
= cli_credentials_get_ccache(cred
, event_ctx
, lp_ctx
,
421 &ccache
, error_string
);
423 DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret
)));
427 gcc
= talloc(cred
, struct gssapi_creds_container
);
429 (*error_string
) = error_message(ENOMEM
);
433 maj_stat
= gss_krb5_import_cred(&min_stat
, ccache
->ccache
, NULL
, NULL
,
435 if ((maj_stat
== GSS_S_FAILURE
) && (min_stat
== (OM_uint32
)KRB5_CC_END
|| min_stat
== (OM_uint32
) KRB5_CC_NOTFOUND
)) {
436 /* This CCACHE is no good. Ensure we don't use it again */
437 cli_credentials_unconditionally_invalidate_ccache(cred
);
439 /* Now try again to get a ccache */
440 ret
= cli_credentials_get_ccache(cred
, event_ctx
, lp_ctx
,
441 &ccache
, error_string
);
443 DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret
)));
447 maj_stat
= gss_krb5_import_cred(&min_stat
, ccache
->ccache
, NULL
, NULL
,
459 (*error_string
) = talloc_asprintf(cred
, "gss_krb5_import_cred failed: %s", error_message(ret
));
464 * transfer the enctypes from the smb_krb5_context to the gssapi layer
466 * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
467 * to configure the enctypes via the krb5.conf.
469 * And the gss_init_sec_context() creates it's own krb5_context and
470 * the TGS-REQ had all enctypes in it and only the ones configured
471 * and used for the AS-REQ, so it wasn't possible to disable the usage
474 min_stat
= krb5_get_default_in_tkt_etypes(ccache
->smb_krb5_context
->krb5_context
,
477 OM_uint32 num_ktypes
;
479 for (num_ktypes
= 0; etypes
[num_ktypes
]; num_ktypes
++);
481 maj_stat
= gss_krb5_set_allowable_enctypes(&min_stat
, gcc
->creds
,
491 (*error_string
) = talloc_asprintf(cred
, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret
));
496 /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
497 maj_stat
= gss_set_cred_option(&min_stat
, &gcc
->creds
,
498 GSS_KRB5_CRED_NO_CI_FLAGS_X
,
507 (*error_string
) = talloc_asprintf(cred
, "gss_set_cred_option failed: %s", error_message(ret
));
511 cred
->client_gss_creds_obtained
= cred
->ccache_obtained
;
512 talloc_set_destructor(gcc
, free_gssapi_creds
);
513 cred
->client_gss_creds
= gcc
;
519 Set a gssapi cred_id_t into the credentials system. (Client case)
521 This grabs the credentials both 'intact' and getting the krb5
522 ccache out of it. This routine can be generalised in future for
523 the case where we deal with GSSAPI mechs other than krb5.
525 On sucess, the caller must not free gssapi_cred, as it now belongs
526 to the credentials system.
529 int cli_credentials_set_client_gss_creds(struct cli_credentials
*cred
,
530 struct tevent_context
*event_ctx
,
531 struct loadparm_context
*lp_ctx
,
532 gss_cred_id_t gssapi_cred
,
533 enum credentials_obtained obtained
,
534 const char **error_string
)
537 OM_uint32 maj_stat
, min_stat
;
538 struct ccache_container
*ccc
;
539 struct gssapi_creds_container
*gcc
;
540 if (cred
->client_gss_creds_obtained
> obtained
) {
544 gcc
= talloc(cred
, struct gssapi_creds_container
);
546 (*error_string
) = error_message(ENOMEM
);
550 ret
= cli_credentials_new_ccache(cred
, event_ctx
, lp_ctx
, NULL
, &ccc
, error_string
);
555 maj_stat
= gss_krb5_copy_ccache(&min_stat
,
556 gssapi_cred
, ccc
->ccache
);
564 (*error_string
) = error_message(ENOMEM
);
569 ret
= cli_credentials_set_from_ccache(cred
, ccc
, obtained
, error_string
);
572 cred
->ccache_obtained
= obtained
;
574 gcc
->creds
= gssapi_cred
;
575 talloc_set_destructor(gcc
, free_gssapi_creds
);
577 /* set the clinet_gss_creds_obtained here, as it just
578 got set to UNINITIALISED by the calls above */
579 cred
->client_gss_creds_obtained
= obtained
;
580 cred
->client_gss_creds
= gcc
;
585 /* Get the keytab (actually, a container containing the krb5_keytab)
586 * attached to this context. If this hasn't been done or set before,
587 * it will be generated from the password.
589 _PUBLIC_
int cli_credentials_get_keytab(struct cli_credentials
*cred
,
590 struct tevent_context
*event_ctx
,
591 struct loadparm_context
*lp_ctx
,
592 struct keytab_container
**_ktc
)
595 struct keytab_container
*ktc
;
596 struct smb_krb5_context
*smb_krb5_context
;
597 const char **enctype_strings
;
600 if (cred
->keytab_obtained
>= (MAX(cred
->principal_obtained
,
601 cred
->username_obtained
))) {
602 *_ktc
= cred
->keytab
;
606 if (cli_credentials_is_anonymous(cred
)) {
610 ret
= cli_credentials_get_krb5_context(cred
, event_ctx
, lp_ctx
,
616 mem_ctx
= talloc_new(cred
);
621 enctype_strings
= cli_credentials_get_enctype_strings(cred
);
623 ret
= smb_krb5_create_memory_keytab(mem_ctx
, cred
,
625 enctype_strings
, &ktc
);
627 talloc_free(mem_ctx
);
631 cred
->keytab_obtained
= (MAX(cred
->principal_obtained
,
632 cred
->username_obtained
));
634 talloc_steal(cred
, ktc
);
636 *_ktc
= cred
->keytab
;
637 talloc_free(mem_ctx
);
641 /* Given the name of a keytab (presumably in the format
642 * FILE:/etc/krb5.keytab), open it and attach it */
644 _PUBLIC_
int cli_credentials_set_keytab_name(struct cli_credentials
*cred
,
645 struct tevent_context
*event_ctx
,
646 struct loadparm_context
*lp_ctx
,
647 const char *keytab_name
,
648 enum credentials_obtained obtained
)
651 struct keytab_container
*ktc
;
652 struct smb_krb5_context
*smb_krb5_context
;
655 if (cred
->keytab_obtained
>= obtained
) {
659 ret
= cli_credentials_get_krb5_context(cred
, event_ctx
, lp_ctx
, &smb_krb5_context
);
664 mem_ctx
= talloc_new(cred
);
669 ret
= smb_krb5_open_keytab(mem_ctx
, smb_krb5_context
,
675 cred
->keytab_obtained
= obtained
;
677 talloc_steal(cred
, ktc
);
679 talloc_free(mem_ctx
);
684 _PUBLIC_
int cli_credentials_update_keytab(struct cli_credentials
*cred
,
685 struct tevent_context
*event_ctx
,
686 struct loadparm_context
*lp_ctx
)
689 struct keytab_container
*ktc
;
690 struct smb_krb5_context
*smb_krb5_context
;
691 const char **enctype_strings
;
694 mem_ctx
= talloc_new(cred
);
699 ret
= cli_credentials_get_krb5_context(cred
, event_ctx
, lp_ctx
, &smb_krb5_context
);
701 talloc_free(mem_ctx
);
705 enctype_strings
= cli_credentials_get_enctype_strings(cred
);
707 ret
= cli_credentials_get_keytab(cred
, event_ctx
, lp_ctx
, &ktc
);
709 talloc_free(mem_ctx
);
713 ret
= smb_krb5_update_keytab(mem_ctx
, cred
, smb_krb5_context
, enctype_strings
, ktc
);
715 talloc_free(mem_ctx
);
719 /* Get server gss credentials (in gsskrb5, this means the keytab) */
721 _PUBLIC_
int cli_credentials_get_server_gss_creds(struct cli_credentials
*cred
,
722 struct tevent_context
*event_ctx
,
723 struct loadparm_context
*lp_ctx
,
724 struct gssapi_creds_container
**_gcc
)
727 OM_uint32 maj_stat
, min_stat
;
728 struct gssapi_creds_container
*gcc
;
729 struct keytab_container
*ktc
;
730 struct smb_krb5_context
*smb_krb5_context
;
732 krb5_principal princ
;
733 const char *error_string
;
734 enum credentials_obtained obtained
;
736 mem_ctx
= talloc_new(cred
);
741 ret
= cli_credentials_get_krb5_context(cred
, event_ctx
, lp_ctx
, &smb_krb5_context
);
746 ret
= principal_from_credentials(mem_ctx
, cred
, smb_krb5_context
, &princ
, &obtained
, &error_string
);
748 DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
750 talloc_free(mem_ctx
);
754 if (cred
->server_gss_creds_obtained
>= (MAX(cred
->keytab_obtained
, obtained
))) {
755 talloc_free(mem_ctx
);
756 *_gcc
= cred
->server_gss_creds
;
760 ret
= cli_credentials_get_keytab(cred
, event_ctx
, lp_ctx
, &ktc
);
762 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret
)));
766 gcc
= talloc(cred
, struct gssapi_creds_container
);
768 talloc_free(mem_ctx
);
772 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
773 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, princ
, ktc
->keytab
,
783 cred
->server_gss_creds_obtained
= cred
->keytab_obtained
;
784 talloc_set_destructor(gcc
, free_gssapi_creds
);
785 cred
->server_gss_creds
= gcc
;
788 talloc_free(mem_ctx
);
796 _PUBLIC_
void cli_credentials_set_kvno(struct cli_credentials
*cred
,
803 * Return Kerberos KVNO
806 _PUBLIC_
int cli_credentials_get_kvno(struct cli_credentials
*cred
)
812 const char **cli_credentials_get_enctype_strings(struct cli_credentials
*cred
)
814 /* If this is ever made user-configurable, we need to add code
815 * to remove/hide the other entries from the generated
817 static const char *default_enctypes
[] = {
819 "aes256-cts-hmac-sha1-96",
824 return default_enctypes
;
827 const char *cli_credentials_get_salt_principal(struct cli_credentials
*cred
)
829 return cred
->salt_principal
;
832 _PUBLIC_
void cli_credentials_set_salt_principal(struct cli_credentials
*cred
, const char *principal
)
834 talloc_free(cred
->salt_principal
);
835 cred
->salt_principal
= talloc_strdup(cred
, principal
);
838 /* The 'impersonate_principal' is used to allow on Kerberos principal
839 * (and it's associated keytab etc) to impersonate another. The
840 * ability to do this is controlled by the KDC, but it is generally
841 * permitted to impersonate anyone to yourself. This allows any
842 * member of the domain to get the groups of a user. This is also
843 * known as S4U2Self */
845 const char *cli_credentials_get_impersonate_principal(struct cli_credentials
*cred
)
847 return cred
->impersonate_principal
;
850 _PUBLIC_
void cli_credentials_set_impersonate_principal(struct cli_credentials
*cred
, const char *principal
)
852 talloc_free(cred
->impersonate_principal
);
853 cred
->impersonate_principal
= talloc_strdup(cred
, principal
);
856 /* when impersonating for S4U2Self we need to set the target principal
857 * to ourself, as otherwise we would need additional rights.
858 * Similarly, we may only be authorized to do general impersonation to
859 * some particular services.
861 * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
863 * NULL means that tickets will be obtained for the krbtgt service.
866 const char *cli_credentials_get_target_service(struct cli_credentials
*cred
)
868 return cred
->target_service
;
871 _PUBLIC_
void cli_credentials_set_target_service(struct cli_credentials
*cred
, const char *target_service
)
873 talloc_free(cred
->target_service
);
874 cred
->target_service
= talloc_strdup(cred
, target_service
);