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 2 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, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "system/kerberos.h"
27 #include "auth/kerberos/kerberos.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/credentials/credentials_krb5.h"
31 int cli_credentials_get_krb5_context(struct cli_credentials *cred,
32 struct smb_krb5_context **smb_krb5_context)
35 if (cred->smb_krb5_context) {
36 *smb_krb5_context = cred->smb_krb5_context;
40 ret = smb_krb5_init_context(cred, &cred->smb_krb5_context);
44 *smb_krb5_context = cred->smb_krb5_context;
48 /* This needs to be called directly after the cli_credentials_init(),
49 * otherwise we might have problems with the krb5 context already
52 NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred,
53 struct smb_krb5_context *smb_krb5_context)
55 if (!talloc_reference(cred, smb_krb5_context)) {
56 return NT_STATUS_NO_MEMORY;
58 cred->smb_krb5_context = smb_krb5_context;
62 int cli_credentials_set_from_ccache(struct cli_credentials *cred,
63 enum credentials_obtained obtained)
71 if (cred->ccache_obtained > obtained) {
75 ret = krb5_cc_get_principal(cred->ccache->smb_krb5_context->krb5_context,
76 cred->ccache->ccache, &princ);
79 char *err_mess = smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context, ret, cred);
80 DEBUG(1,("failed to get principal from ccache: %s\n",
82 talloc_free(err_mess);
86 ret = krb5_unparse_name(cred->ccache->smb_krb5_context->krb5_context, princ, &name);
88 char *err_mess = smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context, ret, cred);
89 DEBUG(1,("failed to unparse principal from ccache: %s\n",
91 talloc_free(err_mess);
95 realm = krb5_princ_realm(cred->ccache->smb_krb5_context->krb5_context, princ);
97 cli_credentials_set_principal(cred, name, obtained);
101 krb5_free_principal(cred->ccache->smb_krb5_context->krb5_context, princ);
103 cred->ccache_obtained = obtained;
108 /* Free a memory ccache */
109 static int free_mccache(struct ccache_container *ccc)
111 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache);
116 /* Free a disk-based ccache */
117 static int free_dccache(struct ccache_container *ccc) {
118 krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache);
123 int cli_credentials_set_ccache(struct cli_credentials *cred,
125 enum credentials_obtained obtained)
128 krb5_principal princ;
129 struct ccache_container *ccc;
130 if (cred->ccache_obtained > obtained) {
134 ccc = talloc(cred, struct ccache_container);
139 ret = cli_credentials_get_krb5_context(cred, &ccc->smb_krb5_context);
144 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
150 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
152 DEBUG(1,("failed to read krb5 ccache: %s: %s\n",
154 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
159 ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
161 DEBUG(3,("failed to read default krb5 ccache: %s\n",
162 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
168 talloc_set_destructor(ccc, free_dccache);
170 ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
173 DEBUG(3,("failed to get principal from default ccache: %s\n",
174 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
179 krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ);
182 talloc_steal(cred, ccc);
184 ret = cli_credentials_set_from_ccache(cred, obtained);
194 int cli_credentials_new_ccache(struct cli_credentials *cred, struct ccache_container **_ccc)
198 struct ccache_container *ccc = talloc(cred, struct ccache_container);
204 rand_string = generate_random_str(NULL, 16);
210 ccache_name = talloc_asprintf(ccc, "MEMORY:%s",
212 talloc_free(rand_string);
219 ret = cli_credentials_get_krb5_context(cred, &ccc->smb_krb5_context);
224 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
229 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name, &ccc->ccache);
231 DEBUG(1,("failed to generate a new krb5 ccache (%s): %s\n",
233 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
234 talloc_free(ccache_name);
239 talloc_set_destructor(ccc, free_mccache);
242 talloc_steal(cred, ccc);
243 talloc_free(ccache_name);
252 int cli_credentials_get_ccache(struct cli_credentials *cred,
253 struct ccache_container **ccc)
257 if (cred->machine_account_pending) {
258 cli_credentials_set_machine_account(cred);
261 if (cred->ccache_obtained >= (MAX(cred->principal_obtained,
262 cred->username_obtained))) {
266 if (cli_credentials_is_anonymous(cred)) {
270 ret = cli_credentials_new_ccache(cred, NULL);
274 ret = kinit_to_ccache(cred, cred, cred->ccache->smb_krb5_context, cred->ccache->ccache);
278 ret = cli_credentials_set_from_ccache(cred, cred->principal_obtained);
287 static int free_gssapi_creds(struct gssapi_creds_container *gcc)
289 OM_uint32 min_stat, maj_stat;
290 maj_stat = gss_release_cred(&min_stat, &gcc->creds);
294 int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
295 struct gssapi_creds_container **_gcc)
298 OM_uint32 maj_stat, min_stat;
299 struct gssapi_creds_container *gcc;
300 struct ccache_container *ccache;
301 if (cred->client_gss_creds_obtained >= (MAX(cred->ccache_obtained,
302 MAX(cred->principal_obtained,
303 cred->username_obtained)))) {
304 *_gcc = cred->client_gss_creds;
307 ret = cli_credentials_get_ccache(cred,
310 DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret)));
314 gcc = talloc(cred, struct gssapi_creds_container);
319 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
329 cred->client_gss_creds_obtained = cred->ccache_obtained;
330 talloc_set_destructor(gcc, free_gssapi_creds);
331 cred->client_gss_creds = gcc;
338 Set a gssapi cred_id_t into the credentails system. (Client case)
340 This grabs the credentials both 'intact' and getting the krb5
341 ccache out of it. This routine can be generalised in future for
342 the case where we deal with GSSAPI mechs other than krb5.
344 On sucess, the caller must not free gssapi_cred, as it now belongs
345 to the credentials system.
348 int cli_credentials_set_client_gss_creds(struct cli_credentials *cred,
349 gss_cred_id_t gssapi_cred,
350 enum credentials_obtained obtained)
353 OM_uint32 maj_stat, min_stat;
354 struct ccache_container *ccc;
355 struct gssapi_creds_container *gcc;
356 if (cred->client_gss_creds_obtained > obtained) {
360 gcc = talloc(cred, struct gssapi_creds_container);
365 ret = cli_credentials_new_ccache(cred, &ccc);
370 maj_stat = gss_krb5_copy_ccache(&min_stat,
371 gssapi_cred, ccc->ccache);
381 ret = cli_credentials_set_from_ccache(cred, obtained);
384 gcc->creds = gssapi_cred;
385 talloc_set_destructor(gcc, free_gssapi_creds);
387 cred->client_gss_creds_obtained = obtained;
388 cred->client_gss_creds = gcc;
393 /* Get the keytab (actually, a container containing the krb5_keytab)
394 * attached to this context. If this hasn't been done or set before,
395 * it will be generated from the password.
397 int cli_credentials_get_keytab(struct cli_credentials *cred,
398 struct keytab_container **_ktc)
401 struct keytab_container *ktc;
402 struct smb_krb5_context *smb_krb5_context;
403 const char **enctype_strings;
406 if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
407 cred->username_obtained))) {
408 *_ktc = cred->keytab;
412 if (cli_credentials_is_anonymous(cred)) {
416 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
421 mem_ctx = talloc_new(cred);
426 enctype_strings = cli_credentials_get_enctype_strings(cred);
428 ret = smb_krb5_create_memory_keytab(mem_ctx, cred,
430 enctype_strings, &ktc);
432 talloc_free(mem_ctx);
436 cred->keytab_obtained = (MAX(cred->principal_obtained,
437 cred->username_obtained));
439 talloc_steal(cred, ktc);
441 *_ktc = cred->keytab;
442 talloc_free(mem_ctx);
446 /* Given the name of a keytab (presumably in the format
447 * FILE:/etc/krb5.keytab), open it and attach it */
449 int cli_credentials_set_keytab_name(struct cli_credentials *cred,
450 const char *keytab_name,
451 enum credentials_obtained obtained)
454 struct keytab_container *ktc;
455 struct smb_krb5_context *smb_krb5_context;
458 if (cred->keytab_obtained >= obtained) {
462 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
467 mem_ctx = talloc_new(cred);
472 ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context,
478 cred->keytab_obtained = obtained;
480 talloc_steal(cred, ktc);
482 talloc_free(mem_ctx);
487 int cli_credentials_update_keytab(struct cli_credentials *cred)
490 struct keytab_container *ktc;
491 struct smb_krb5_context *smb_krb5_context;
492 const char **enctype_strings;
495 mem_ctx = talloc_new(cred);
500 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
502 talloc_free(mem_ctx);
506 enctype_strings = cli_credentials_get_enctype_strings(cred);
508 ret = cli_credentials_get_keytab(cred, &ktc);
510 talloc_free(mem_ctx);
514 ret = smb_krb5_update_keytab(mem_ctx, cred, smb_krb5_context, enctype_strings, ktc);
516 talloc_free(mem_ctx);
520 /* Get server gss credentials (in gsskrb5, this means the keytab) */
522 int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
523 struct gssapi_creds_container **_gcc)
526 OM_uint32 maj_stat, min_stat;
527 struct gssapi_creds_container *gcc;
528 struct keytab_container *ktc;
529 struct smb_krb5_context *smb_krb5_context;
531 krb5_principal princ;
533 if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained,
534 MAX(cred->principal_obtained,
535 cred->username_obtained)))) {
536 *_gcc = cred->server_gss_creds;
540 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
545 ret = cli_credentials_get_keytab(cred,
548 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
552 mem_ctx = talloc_new(cred);
557 ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ);
559 DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
560 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
562 talloc_free(mem_ctx);
566 gcc = talloc(cred, struct gssapi_creds_container);
568 talloc_free(mem_ctx);
572 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
573 maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab,
583 cred->server_gss_creds_obtained = cred->keytab_obtained;
584 talloc_set_destructor(gcc, free_gssapi_creds);
585 cred->server_gss_creds = gcc;
588 talloc_free(mem_ctx);
596 void cli_credentials_set_kvno(struct cli_credentials *cred,
603 * Return Kerberos KVNO
606 int cli_credentials_get_kvno(struct cli_credentials *cred)
612 const char **cli_credentials_get_enctype_strings(struct cli_credentials *cred)
614 /* If this is ever made user-configurable, we need to add code
615 * to remove/hide the other entries from the generated
617 static const char *default_enctypes[] = {
619 "aes256-cts-hmac-sha1-96",
624 return default_enctypes;
627 const char *cli_credentials_get_salt_principal(struct cli_credentials *cred)
629 return cred->salt_principal;
632 void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal)
634 cred->salt_principal = talloc_strdup(cred, principal);