Don't use sigev_value.sival_int to just store the mid, use sigev_value.sival_ptr...
[Samba/ekacnet.git] / source4 / auth / credentials / credentials_krb5.c
blobf4ee2641d9826b5937423000c655455c012b4701
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 "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)
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, event_ctx, 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 /* This needs to be called directly after the cli_credentials_init(),
55 * otherwise we might have problems with the krb5 context already
56 * being here.
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;
65 return NT_STATUS_OK;
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)
74 krb5_principal princ;
75 krb5_error_code ret;
76 char *name;
78 if (cred->ccache_obtained > obtained) {
79 return 0;
82 ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context,
83 ccache->ccache, &princ);
85 if (ret) {
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,
88 ret, cred));
89 return ret;
92 ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name);
93 if (ret) {
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,
96 ret, cred));
97 return ret;
100 cli_credentials_set_principal(cred, name, obtained);
102 free(name);
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;
109 return 0;
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);
117 return 0;
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);
124 return 0;
127 _PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred,
128 struct tevent_context *event_ctx,
129 struct loadparm_context *lp_ctx,
130 const char *name,
131 enum credentials_obtained obtained,
132 const char **error_string)
134 krb5_error_code ret;
135 krb5_principal princ;
136 struct ccache_container *ccc;
137 if (cred->ccache_obtained > obtained) {
138 return 0;
141 ccc = talloc(cred, struct ccache_container);
142 if (!ccc) {
143 (*error_string) = error_message(ENOMEM);
144 return ENOMEM;
147 ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx,
148 &ccc->smb_krb5_context);
149 if (ret) {
150 (*error_string) = error_message(ret);
151 talloc_free(ccc);
152 return ret;
154 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
155 talloc_free(ccc);
156 (*error_string) = error_message(ENOMEM);
157 return ENOMEM;
160 if (name) {
161 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
162 if (ret) {
163 (*error_string) = talloc_asprintf(cred, "failed to read krb5 ccache: %s: %s\n",
164 name,
165 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
166 ret, ccc));
167 talloc_free(ccc);
168 return ret;
170 } else {
171 ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
172 if (ret) {
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,
175 ret, ccc));
176 talloc_free(ccc);
177 return ret;
181 talloc_set_destructor(ccc, free_dccache);
183 ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
185 if (ret == 0) {
186 krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ);
187 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
189 if (ret) {
190 (*error_string) = error_message(ret);
191 return ret;
194 cred->ccache = ccc;
195 cred->ccache_obtained = obtained;
196 talloc_steal(cred, ccc);
198 cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
199 return 0;
201 return 0;
205 static int cli_credentials_new_ccache(struct cli_credentials *cred,
206 struct tevent_context *event_ctx,
207 struct loadparm_context *lp_ctx,
208 char *ccache_name,
209 struct ccache_container **_ccc,
210 const char **error_string)
212 bool must_free_cc_name = false;
213 krb5_error_code ret;
214 struct ccache_container *ccc = talloc(cred, struct ccache_container);
215 if (!ccc) {
216 return ENOMEM;
219 ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx,
220 &ccc->smb_krb5_context);
221 if (ret) {
222 talloc_free(ccc);
223 (*error_string) = talloc_asprintf(cred, "Failed to get krb5_context: %s",
224 error_message(ret));
225 return ret;
227 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
228 talloc_free(ccc);
229 (*error_string) = strerror(ENOMEM);
230 return ENOMEM;
233 if (!ccache_name) {
234 must_free_cc_name = true;
235 ccache_name = talloc_asprintf(ccc, "MEMORY:%p",
236 ccc);
238 if (!ccache_name) {
239 talloc_free(ccc);
240 (*error_string) = strerror(ENOMEM);
241 return ENOMEM;
245 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name,
246 &ccc->ccache);
247 if (ret) {
248 (*error_string) = talloc_asprintf(cred, "failed to resolve a krb5 ccache (%s): %s\n",
249 ccache_name,
250 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
251 ret, ccc));
252 talloc_free(ccache_name);
253 talloc_free(ccc);
254 return ret;
257 if (strncasecmp(ccache_name, "MEMORY:", 7) == 0) {
258 talloc_set_destructor(ccc, free_mccache);
259 } else {
260 talloc_set_destructor(ccc, free_dccache);
263 if (must_free_cc_name) {
264 talloc_free(ccache_name);
267 *_ccc = ccc;
269 return 0;
272 _PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
273 struct tevent_context *event_ctx,
274 struct loadparm_context *lp_ctx,
275 char *ccache_name,
276 struct ccache_container **ccc,
277 const char **error_string)
279 krb5_error_code ret;
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) {
288 *ccc = cred->ccache;
289 return 0;
291 if (cli_credentials_is_anonymous(cred)) {
292 (*error_string) = "Cannot get anonymous kerberos credentials";
293 return EINVAL;
296 ret = cli_credentials_new_ccache(cred, event_ctx, lp_ctx, ccache_name, ccc, error_string);
297 if (ret) {
298 return ret;
301 ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, (*ccc)->ccache, &obtained, error_string);
302 if (ret) {
303 return ret;
306 ret = cli_credentials_set_from_ccache(cred, *ccc,
307 obtained, error_string);
309 cred->ccache = *ccc;
310 cred->ccache_obtained = cred->principal_obtained;
311 if (ret) {
312 return ret;
314 cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
315 return 0;
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);
363 cred->ccache = NULL;
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);
378 cred->ccache = NULL;
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,
391 obtained);
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);
398 return 0;
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)
407 int ret = 0;
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;
417 return 0;
420 ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
421 &ccache, error_string);
422 if (ret) {
423 DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret)));
424 return ret;
427 gcc = talloc(cred, struct gssapi_creds_container);
428 if (!gcc) {
429 (*error_string) = error_message(ENOMEM);
430 return ENOMEM;
433 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
434 &gcc->creds);
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);
442 if (ret) {
443 DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret)));
444 return ret;
447 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
448 &gcc->creds);
452 if (maj_stat) {
453 talloc_free(gcc);
454 if (min_stat) {
455 ret = min_stat;
456 } else {
457 ret = EINVAL;
459 (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret));
460 return 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
472 * of AES keys.
474 min_stat = krb5_get_default_in_tkt_etypes(ccache->smb_krb5_context->krb5_context,
475 &etypes);
476 if (min_stat == 0) {
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,
482 num_ktypes, etypes);
483 krb5_xfree (etypes);
484 if (maj_stat) {
485 talloc_free(gcc);
486 if (min_stat) {
487 ret = min_stat;
488 } else {
489 ret = EINVAL;
491 (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret));
492 return 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,
499 &empty_buffer);
500 if (maj_stat) {
501 talloc_free(gcc);
502 if (min_stat) {
503 ret = min_stat;
504 } else {
505 ret = EINVAL;
507 (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret));
508 return ret;
511 cred->client_gss_creds_obtained = cred->ccache_obtained;
512 talloc_set_destructor(gcc, free_gssapi_creds);
513 cred->client_gss_creds = gcc;
514 *_gcc = gcc;
515 return 0;
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)
536 int ret;
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) {
541 return 0;
544 gcc = talloc(cred, struct gssapi_creds_container);
545 if (!gcc) {
546 (*error_string) = error_message(ENOMEM);
547 return ENOMEM;
550 ret = cli_credentials_new_ccache(cred, event_ctx, lp_ctx, NULL, &ccc, error_string);
551 if (ret != 0) {
552 return ret;
555 maj_stat = gss_krb5_copy_ccache(&min_stat,
556 gssapi_cred, ccc->ccache);
557 if (maj_stat) {
558 if (min_stat) {
559 ret = min_stat;
560 } else {
561 ret = EINVAL;
563 if (ret) {
564 (*error_string) = error_message(ENOMEM);
568 if (ret == 0) {
569 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
571 cred->ccache = ccc;
572 cred->ccache_obtained = obtained;
573 if (ret == 0) {
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;
582 return ret;
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)
594 krb5_error_code ret;
595 struct keytab_container *ktc;
596 struct smb_krb5_context *smb_krb5_context;
597 const char **enctype_strings;
598 TALLOC_CTX *mem_ctx;
600 if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
601 cred->username_obtained))) {
602 *_ktc = cred->keytab;
603 return 0;
606 if (cli_credentials_is_anonymous(cred)) {
607 return EINVAL;
610 ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx,
611 &smb_krb5_context);
612 if (ret) {
613 return ret;
616 mem_ctx = talloc_new(cred);
617 if (!mem_ctx) {
618 return ENOMEM;
621 enctype_strings = cli_credentials_get_enctype_strings(cred);
623 ret = smb_krb5_create_memory_keytab(mem_ctx, cred,
624 smb_krb5_context,
625 enctype_strings, &ktc);
626 if (ret) {
627 talloc_free(mem_ctx);
628 return ret;
631 cred->keytab_obtained = (MAX(cred->principal_obtained,
632 cred->username_obtained));
634 talloc_steal(cred, ktc);
635 cred->keytab = ktc;
636 *_ktc = cred->keytab;
637 talloc_free(mem_ctx);
638 return ret;
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)
650 krb5_error_code ret;
651 struct keytab_container *ktc;
652 struct smb_krb5_context *smb_krb5_context;
653 TALLOC_CTX *mem_ctx;
655 if (cred->keytab_obtained >= obtained) {
656 return 0;
659 ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, &smb_krb5_context);
660 if (ret) {
661 return ret;
664 mem_ctx = talloc_new(cred);
665 if (!mem_ctx) {
666 return ENOMEM;
669 ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context,
670 keytab_name, &ktc);
671 if (ret) {
672 return ret;
675 cred->keytab_obtained = obtained;
677 talloc_steal(cred, ktc);
678 cred->keytab = ktc;
679 talloc_free(mem_ctx);
681 return ret;
684 _PUBLIC_ int cli_credentials_update_keytab(struct cli_credentials *cred,
685 struct tevent_context *event_ctx,
686 struct loadparm_context *lp_ctx)
688 krb5_error_code ret;
689 struct keytab_container *ktc;
690 struct smb_krb5_context *smb_krb5_context;
691 const char **enctype_strings;
692 TALLOC_CTX *mem_ctx;
694 mem_ctx = talloc_new(cred);
695 if (!mem_ctx) {
696 return ENOMEM;
699 ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, &smb_krb5_context);
700 if (ret) {
701 talloc_free(mem_ctx);
702 return ret;
705 enctype_strings = cli_credentials_get_enctype_strings(cred);
707 ret = cli_credentials_get_keytab(cred, event_ctx, lp_ctx, &ktc);
708 if (ret != 0) {
709 talloc_free(mem_ctx);
710 return ret;
713 ret = smb_krb5_update_keytab(mem_ctx, cred, smb_krb5_context, enctype_strings, ktc);
715 talloc_free(mem_ctx);
716 return ret;
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)
726 int ret = 0;
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;
731 TALLOC_CTX *mem_ctx;
732 krb5_principal princ;
733 const char *error_string;
734 enum credentials_obtained obtained;
736 mem_ctx = talloc_new(cred);
737 if (!mem_ctx) {
738 return ENOMEM;
741 ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, &smb_krb5_context);
742 if (ret) {
743 return ret;
746 ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string);
747 if (ret) {
748 DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
749 error_string));
750 talloc_free(mem_ctx);
751 return ret;
754 if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) {
755 talloc_free(mem_ctx);
756 *_gcc = cred->server_gss_creds;
757 return 0;
760 ret = cli_credentials_get_keytab(cred, event_ctx, lp_ctx, &ktc);
761 if (ret) {
762 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
763 return ret;
766 gcc = talloc(cred, struct gssapi_creds_container);
767 if (!gcc) {
768 talloc_free(mem_ctx);
769 return ENOMEM;
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,
774 &gcc->creds);
775 if (maj_stat) {
776 if (min_stat) {
777 ret = min_stat;
778 } else {
779 ret = EINVAL;
782 if (ret == 0) {
783 cred->server_gss_creds_obtained = cred->keytab_obtained;
784 talloc_set_destructor(gcc, free_gssapi_creds);
785 cred->server_gss_creds = gcc;
786 *_gcc = gcc;
788 talloc_free(mem_ctx);
789 return ret;
792 /**
793 * Set Kerberos KVNO
796 _PUBLIC_ void cli_credentials_set_kvno(struct cli_credentials *cred,
797 int kvno)
799 cred->kvno = kvno;
803 * Return Kerberos KVNO
806 _PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred)
808 return cred->kvno;
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
816 * keytab */
817 static const char *default_enctypes[] = {
818 "des-cbc-md5",
819 "aes256-cts-hmac-sha1-96",
820 "des3-cbc-sha1",
821 "arcfour-hmac-md5",
822 NULL
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);