s4:auth/credentials: pass 'self_service' to cli_credentials_set_impersonate_principal()
[Samba.git] / source4 / auth / credentials / credentials_krb5.c
blob5883282c2501f9a8b1284a45648852f33ed0b9f5
1 /*
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/>.
24 #include "includes.h"
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 _PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred,
35 struct loadparm_context *lp_ctx,
36 struct smb_krb5_context **smb_krb5_context)
38 int ret;
39 if (cred->smb_krb5_context) {
40 *smb_krb5_context = cred->smb_krb5_context;
41 return 0;
44 ret = smb_krb5_init_context(cred, NULL, lp_ctx,
45 &cred->smb_krb5_context);
46 if (ret) {
47 cred->smb_krb5_context = NULL;
48 return ret;
50 *smb_krb5_context = cred->smb_krb5_context;
51 return 0;
54 /* For most predictable behaviour, this needs to be called directly after the cli_credentials_init(),
55 * otherwise we may still have references to the old smb_krb5_context in a credential cache etc
57 _PUBLIC_ NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred,
58 struct smb_krb5_context *smb_krb5_context)
60 if (smb_krb5_context == NULL) {
61 talloc_unlink(cred, cred->smb_krb5_context);
62 cred->smb_krb5_context = NULL;
63 return NT_STATUS_OK;
66 if (!talloc_reference(cred, smb_krb5_context)) {
67 return NT_STATUS_NO_MEMORY;
69 cred->smb_krb5_context = smb_krb5_context;
70 return NT_STATUS_OK;
73 static int cli_credentials_set_from_ccache(struct cli_credentials *cred,
74 struct ccache_container *ccache,
75 enum credentials_obtained obtained,
76 const char **error_string)
79 krb5_principal princ;
80 krb5_error_code ret;
81 char *name;
83 if (cred->ccache_obtained > obtained) {
84 return 0;
87 ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context,
88 ccache->ccache, &princ);
90 if (ret) {
91 (*error_string) = talloc_asprintf(cred, "failed to get principal from ccache: %s\n",
92 smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context,
93 ret, cred));
94 return ret;
97 ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name);
98 if (ret) {
99 (*error_string) = talloc_asprintf(cred, "failed to unparse principal from ccache: %s\n",
100 smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context,
101 ret, cred));
102 return ret;
105 cli_credentials_set_principal(cred, name, obtained);
107 free(name);
109 krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ);
111 /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */
112 cred->ccache_obtained = obtained;
114 return 0;
117 /* Free a memory ccache */
118 static int free_mccache(struct ccache_container *ccc)
120 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache);
122 return 0;
125 /* Free a disk-based ccache */
126 static int free_dccache(struct ccache_container *ccc) {
127 krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache);
129 return 0;
132 _PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred,
133 struct loadparm_context *lp_ctx,
134 const char *name,
135 enum credentials_obtained obtained,
136 const char **error_string)
138 krb5_error_code ret;
139 krb5_principal princ;
140 struct ccache_container *ccc;
141 if (cred->ccache_obtained > obtained) {
142 return 0;
145 ccc = talloc(cred, struct ccache_container);
146 if (!ccc) {
147 (*error_string) = error_message(ENOMEM);
148 return ENOMEM;
151 ret = cli_credentials_get_krb5_context(cred, lp_ctx,
152 &ccc->smb_krb5_context);
153 if (ret) {
154 (*error_string) = error_message(ret);
155 talloc_free(ccc);
156 return ret;
158 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
159 talloc_free(ccc);
160 (*error_string) = error_message(ENOMEM);
161 return ENOMEM;
164 if (name) {
165 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
166 if (ret) {
167 (*error_string) = talloc_asprintf(cred, "failed to read krb5 ccache: %s: %s\n",
168 name,
169 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
170 ret, ccc));
171 talloc_free(ccc);
172 return ret;
174 } else {
175 ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
176 if (ret) {
177 (*error_string) = talloc_asprintf(cred, "failed to read default krb5 ccache: %s\n",
178 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
179 ret, ccc));
180 talloc_free(ccc);
181 return ret;
185 talloc_set_destructor(ccc, free_dccache);
187 ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
189 if (ret == 0) {
190 krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ);
191 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
193 if (ret) {
194 (*error_string) = error_message(ret);
195 return ret;
198 cred->ccache = ccc;
199 cred->ccache_obtained = obtained;
200 talloc_steal(cred, ccc);
202 cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
203 return 0;
205 return 0;
209 static int cli_credentials_new_ccache(struct cli_credentials *cred,
210 struct loadparm_context *lp_ctx,
211 char *ccache_name,
212 struct ccache_container **_ccc,
213 const char **error_string)
215 bool must_free_cc_name = false;
216 krb5_error_code ret;
217 struct ccache_container *ccc = talloc(cred, struct ccache_container);
218 if (!ccc) {
219 return ENOMEM;
222 ret = cli_credentials_get_krb5_context(cred, lp_ctx,
223 &ccc->smb_krb5_context);
224 if (ret) {
225 talloc_free(ccc);
226 (*error_string) = talloc_asprintf(cred, "Failed to get krb5_context: %s",
227 error_message(ret));
228 return ret;
230 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
231 talloc_free(ccc);
232 (*error_string) = strerror(ENOMEM);
233 return ENOMEM;
236 if (!ccache_name) {
237 must_free_cc_name = true;
238 ccache_name = talloc_asprintf(ccc, "MEMORY:%p",
239 ccc);
241 if (!ccache_name) {
242 talloc_free(ccc);
243 (*error_string) = strerror(ENOMEM);
244 return ENOMEM;
248 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name,
249 &ccc->ccache);
250 if (ret) {
251 (*error_string) = talloc_asprintf(cred, "failed to resolve a krb5 ccache (%s): %s\n",
252 ccache_name,
253 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
254 ret, ccc));
255 talloc_free(ccache_name);
256 talloc_free(ccc);
257 return ret;
260 if (strncasecmp(ccache_name, "MEMORY:", 7) == 0) {
261 talloc_set_destructor(ccc, free_mccache);
262 } else {
263 talloc_set_destructor(ccc, free_dccache);
266 if (must_free_cc_name) {
267 talloc_free(ccache_name);
270 *_ccc = ccc;
272 return 0;
275 _PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
276 struct tevent_context *event_ctx,
277 struct loadparm_context *lp_ctx,
278 char *ccache_name,
279 struct ccache_container **ccc,
280 const char **error_string)
282 krb5_error_code ret;
283 enum credentials_obtained obtained;
285 if (cred->machine_account_pending) {
286 cli_credentials_set_machine_account(cred, lp_ctx);
289 if (cred->ccache_obtained >= cred->ccache_threshold &&
290 cred->ccache_obtained > CRED_UNINITIALISED) {
291 *ccc = cred->ccache;
292 return 0;
294 if (cli_credentials_is_anonymous(cred)) {
295 (*error_string) = "Cannot get anonymous kerberos credentials";
296 return EINVAL;
299 ret = cli_credentials_new_ccache(cred, lp_ctx, ccache_name, ccc, error_string);
300 if (ret) {
301 return ret;
304 ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, event_ctx, (*ccc)->ccache, &obtained, error_string);
305 if (ret) {
306 return ret;
309 ret = cli_credentials_set_from_ccache(cred, *ccc,
310 obtained, error_string);
312 cred->ccache = *ccc;
313 cred->ccache_obtained = cred->principal_obtained;
314 if (ret) {
315 return ret;
317 cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
318 return 0;
321 _PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred,
322 struct tevent_context *event_ctx,
323 struct loadparm_context *lp_ctx,
324 struct ccache_container **ccc,
325 const char **error_string)
327 return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string);
330 /* We have good reason to think the ccache in these credentials is invalid - blow it away */
331 static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials *cred)
333 if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
334 talloc_unlink(cred, cred->client_gss_creds);
335 cred->client_gss_creds = NULL;
337 cred->client_gss_creds_obtained = CRED_UNINITIALISED;
340 void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred,
341 enum credentials_obtained obtained)
343 /* If the caller just changed the username/password etc, then
344 * any cached credentials are now invalid */
345 if (obtained >= cred->client_gss_creds_obtained) {
346 if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
347 talloc_unlink(cred, cred->client_gss_creds);
348 cred->client_gss_creds = NULL;
350 cred->client_gss_creds_obtained = CRED_UNINITIALISED;
352 /* Now that we know that the data is 'this specified', then
353 * don't allow something less 'known' to be returned as a
354 * ccache. Ie, if the username is on the commmand line, we
355 * don't want to later guess to use a file-based ccache */
356 if (obtained > cred->client_gss_creds_threshold) {
357 cred->client_gss_creds_threshold = obtained;
361 /* We have good reason to think this CCACHE is invalid. Blow it away */
362 static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred)
364 if (cred->ccache_obtained > CRED_UNINITIALISED) {
365 talloc_unlink(cred, cred->ccache);
366 cred->ccache = NULL;
368 cred->ccache_obtained = CRED_UNINITIALISED;
370 cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
373 _PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred,
374 enum credentials_obtained obtained)
376 /* If the caller just changed the username/password etc, then
377 * any cached credentials are now invalid */
378 if (obtained >= cred->ccache_obtained) {
379 if (cred->ccache_obtained > CRED_UNINITIALISED) {
380 talloc_unlink(cred, cred->ccache);
381 cred->ccache = NULL;
383 cred->ccache_obtained = CRED_UNINITIALISED;
385 /* Now that we know that the data is 'this specified', then
386 * don't allow something less 'known' to be returned as a
387 * ccache. Ie, if the username is on the commmand line, we
388 * don't want to later guess to use a file-based ccache */
389 if (obtained > cred->ccache_threshold) {
390 cred->ccache_threshold = obtained;
393 cli_credentials_invalidate_client_gss_creds(cred,
394 obtained);
397 static int free_gssapi_creds(struct gssapi_creds_container *gcc)
399 OM_uint32 min_stat, maj_stat;
400 maj_stat = gss_release_cred(&min_stat, &gcc->creds);
401 return 0;
404 _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
405 struct tevent_context *event_ctx,
406 struct loadparm_context *lp_ctx,
407 struct gssapi_creds_container **_gcc,
408 const char **error_string)
410 int ret = 0;
411 OM_uint32 maj_stat, min_stat;
412 struct gssapi_creds_container *gcc;
413 struct ccache_container *ccache;
414 gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
415 krb5_enctype *etypes = NULL;
417 if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold &&
418 cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
419 *_gcc = cred->client_gss_creds;
420 return 0;
423 ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
424 &ccache, error_string);
425 if (ret) {
426 DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret)));
427 return ret;
430 gcc = talloc(cred, struct gssapi_creds_container);
431 if (!gcc) {
432 (*error_string) = error_message(ENOMEM);
433 return ENOMEM;
436 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
437 &gcc->creds);
438 if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) {
439 /* This CCACHE is no good. Ensure we don't use it again */
440 cli_credentials_unconditionally_invalidate_ccache(cred);
442 /* Now try again to get a ccache */
443 ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
444 &ccache, error_string);
445 if (ret) {
446 DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret)));
447 return ret;
450 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
451 &gcc->creds);
455 if (maj_stat) {
456 talloc_free(gcc);
457 if (min_stat) {
458 ret = min_stat;
459 } else {
460 ret = EINVAL;
462 (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret));
463 return ret;
467 * transfer the enctypes from the smb_krb5_context to the gssapi layer
469 * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
470 * to configure the enctypes via the krb5.conf.
472 * And the gss_init_sec_context() creates it's own krb5_context and
473 * the TGS-REQ had all enctypes in it and only the ones configured
474 * and used for the AS-REQ, so it wasn't possible to disable the usage
475 * of AES keys.
477 min_stat = krb5_get_default_in_tkt_etypes(ccache->smb_krb5_context->krb5_context,
478 &etypes);
479 if (min_stat == 0) {
480 OM_uint32 num_ktypes;
482 for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++);
484 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds,
485 num_ktypes,
486 (int32_t *) etypes);
487 krb5_xfree (etypes);
488 if (maj_stat) {
489 talloc_free(gcc);
490 if (min_stat) {
491 ret = min_stat;
492 } else {
493 ret = EINVAL;
495 (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret));
496 return ret;
500 /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
501 maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
502 GSS_KRB5_CRED_NO_CI_FLAGS_X,
503 &empty_buffer);
504 if (maj_stat) {
505 talloc_free(gcc);
506 if (min_stat) {
507 ret = min_stat;
508 } else {
509 ret = EINVAL;
511 (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret));
512 return ret;
515 cred->client_gss_creds_obtained = cred->ccache_obtained;
516 talloc_set_destructor(gcc, free_gssapi_creds);
517 cred->client_gss_creds = gcc;
518 *_gcc = gcc;
519 return 0;
523 Set a gssapi cred_id_t into the credentials system. (Client case)
525 This grabs the credentials both 'intact' and getting the krb5
526 ccache out of it. This routine can be generalised in future for
527 the case where we deal with GSSAPI mechs other than krb5.
529 On sucess, the caller must not free gssapi_cred, as it now belongs
530 to the credentials system.
533 int cli_credentials_set_client_gss_creds(struct cli_credentials *cred,
534 struct loadparm_context *lp_ctx,
535 gss_cred_id_t gssapi_cred,
536 enum credentials_obtained obtained,
537 const char **error_string)
539 int ret;
540 OM_uint32 maj_stat, min_stat;
541 struct ccache_container *ccc;
542 struct gssapi_creds_container *gcc;
543 if (cred->client_gss_creds_obtained > obtained) {
544 return 0;
547 gcc = talloc(cred, struct gssapi_creds_container);
548 if (!gcc) {
549 (*error_string) = error_message(ENOMEM);
550 return ENOMEM;
553 ret = cli_credentials_new_ccache(cred, lp_ctx, NULL, &ccc, error_string);
554 if (ret != 0) {
555 return ret;
558 maj_stat = gss_krb5_copy_ccache(&min_stat,
559 gssapi_cred, ccc->ccache);
560 if (maj_stat) {
561 if (min_stat) {
562 ret = min_stat;
563 } else {
564 ret = EINVAL;
566 if (ret) {
567 (*error_string) = error_message(ENOMEM);
571 if (ret == 0) {
572 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
574 cred->ccache = ccc;
575 cred->ccache_obtained = obtained;
576 if (ret == 0) {
577 gcc->creds = gssapi_cred;
578 talloc_set_destructor(gcc, free_gssapi_creds);
580 /* set the clinet_gss_creds_obtained here, as it just
581 got set to UNINITIALISED by the calls above */
582 cred->client_gss_creds_obtained = obtained;
583 cred->client_gss_creds = gcc;
585 return ret;
588 /* Get the keytab (actually, a container containing the krb5_keytab)
589 * attached to this context. If this hasn't been done or set before,
590 * it will be generated from the password.
592 _PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred,
593 struct loadparm_context *lp_ctx,
594 struct keytab_container **_ktc)
596 krb5_error_code ret;
597 struct keytab_container *ktc;
598 struct smb_krb5_context *smb_krb5_context;
599 TALLOC_CTX *mem_ctx;
601 if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
602 cred->username_obtained))) {
603 *_ktc = cred->keytab;
604 return 0;
607 if (cli_credentials_is_anonymous(cred)) {
608 return EINVAL;
611 ret = cli_credentials_get_krb5_context(cred, lp_ctx,
612 &smb_krb5_context);
613 if (ret) {
614 return ret;
617 mem_ctx = talloc_new(cred);
618 if (!mem_ctx) {
619 return ENOMEM;
622 ret = smb_krb5_create_memory_keytab(mem_ctx, cred,
623 smb_krb5_context, &ktc);
624 if (ret) {
625 talloc_free(mem_ctx);
626 return ret;
629 cred->keytab_obtained = (MAX(cred->principal_obtained,
630 cred->username_obtained));
632 talloc_steal(cred, ktc);
633 cred->keytab = ktc;
634 *_ktc = cred->keytab;
635 talloc_free(mem_ctx);
636 return ret;
639 /* Given the name of a keytab (presumably in the format
640 * FILE:/etc/krb5.keytab), open it and attach it */
642 _PUBLIC_ int cli_credentials_set_keytab_name(struct cli_credentials *cred,
643 struct loadparm_context *lp_ctx,
644 const char *keytab_name,
645 enum credentials_obtained obtained)
647 krb5_error_code ret;
648 struct keytab_container *ktc;
649 struct smb_krb5_context *smb_krb5_context;
650 TALLOC_CTX *mem_ctx;
652 if (cred->keytab_obtained >= obtained) {
653 return 0;
656 ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
657 if (ret) {
658 return ret;
661 mem_ctx = talloc_new(cred);
662 if (!mem_ctx) {
663 return ENOMEM;
666 ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context,
667 keytab_name, &ktc);
668 if (ret) {
669 return ret;
672 cred->keytab_obtained = obtained;
674 talloc_steal(cred, ktc);
675 cred->keytab = ktc;
676 talloc_free(mem_ctx);
678 return ret;
681 /* Get server gss credentials (in gsskrb5, this means the keytab) */
683 _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
684 struct loadparm_context *lp_ctx,
685 struct gssapi_creds_container **_gcc)
687 int ret = 0;
688 OM_uint32 maj_stat, min_stat;
689 struct gssapi_creds_container *gcc;
690 struct keytab_container *ktc;
691 struct smb_krb5_context *smb_krb5_context;
692 TALLOC_CTX *mem_ctx;
693 krb5_principal princ;
694 const char *error_string;
695 enum credentials_obtained obtained;
697 mem_ctx = talloc_new(cred);
698 if (!mem_ctx) {
699 return ENOMEM;
702 ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
703 if (ret) {
704 return ret;
707 ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string);
708 if (ret) {
709 DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n",
710 error_string));
711 talloc_free(mem_ctx);
712 return ret;
715 if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) {
716 talloc_free(mem_ctx);
717 *_gcc = cred->server_gss_creds;
718 return 0;
721 ret = cli_credentials_get_keytab(cred, lp_ctx, &ktc);
722 if (ret) {
723 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
724 return ret;
727 gcc = talloc(cred, struct gssapi_creds_container);
728 if (!gcc) {
729 talloc_free(mem_ctx);
730 return ENOMEM;
733 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
734 maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab,
735 &gcc->creds);
736 if (maj_stat) {
737 if (min_stat) {
738 ret = min_stat;
739 } else {
740 ret = EINVAL;
743 if (ret == 0) {
744 cred->server_gss_creds_obtained = cred->keytab_obtained;
745 talloc_set_destructor(gcc, free_gssapi_creds);
746 cred->server_gss_creds = gcc;
747 *_gcc = gcc;
749 talloc_free(mem_ctx);
750 return ret;
753 /**
754 * Set Kerberos KVNO
757 _PUBLIC_ void cli_credentials_set_kvno(struct cli_credentials *cred,
758 int kvno)
760 cred->kvno = kvno;
764 * Return Kerberos KVNO
767 _PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred)
769 return cred->kvno;
773 const char *cli_credentials_get_salt_principal(struct cli_credentials *cred)
775 return cred->salt_principal;
778 _PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal)
780 talloc_free(cred->salt_principal);
781 cred->salt_principal = talloc_strdup(cred, principal);
784 /* The 'impersonate_principal' is used to allow on Kerberos principal
785 * (and it's associated keytab etc) to impersonate another. The
786 * ability to do this is controlled by the KDC, but it is generally
787 * permitted to impersonate anyone to yourself. This allows any
788 * member of the domain to get the groups of a user. This is also
789 * known as S4U2Self */
791 _PUBLIC_ const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred)
793 return cred->impersonate_principal;
797 * The 'self_service' is the service principal that
798 * represents the same object (by its objectSid)
799 * as the client principal (typically our machine account).
800 * When trying to impersonate 'impersonate_principal' with
801 * S4U2Self.
803 _PUBLIC_ const char *cli_credentials_get_self_service(struct cli_credentials *cred)
805 return cred->self_service;
808 _PUBLIC_ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred,
809 const char *principal,
810 const char *self_service)
812 talloc_free(cred->impersonate_principal);
813 cred->impersonate_principal = talloc_strdup(cred, principal);
814 talloc_free(cred->self_service);
815 cred->self_service = talloc_strdup(cred, self_service);
819 * when impersonating for S4U2proxy we need to set the target principal.
820 * Similarly, we may only be authorized to do general impersonation to
821 * some particular services.
823 * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
825 * NULL means that tickets will be obtained for the krbtgt service.
828 const char *cli_credentials_get_target_service(struct cli_credentials *cred)
830 return cred->target_service;
833 _PUBLIC_ void cli_credentials_set_target_service(struct cli_credentials *cred, const char *target_service)
835 talloc_free(cred->target_service);
836 cred->target_service = talloc_strdup(cred, target_service);