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, cli_credentials_get_event_context(cred),
41 &cred->smb_krb5_context);
45 *smb_krb5_context = cred->smb_krb5_context;
49 /* This needs to be called directly after the cli_credentials_init(),
50 * otherwise we might have problems with the krb5 context already
53 NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred,
54 struct smb_krb5_context *smb_krb5_context)
56 if (!talloc_reference(cred, smb_krb5_context)) {
57 return NT_STATUS_NO_MEMORY;
59 cred->smb_krb5_context = smb_krb5_context;
63 int cli_credentials_set_from_ccache(struct cli_credentials *cred,
64 enum credentials_obtained obtained)
72 if (cred->ccache_obtained > obtained) {
76 ret = krb5_cc_get_principal(cred->ccache->smb_krb5_context->krb5_context,
77 cred->ccache->ccache, &princ);
80 char *err_mess = smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context, ret, cred);
81 DEBUG(1,("failed to get principal from ccache: %s\n",
83 talloc_free(err_mess);
87 ret = krb5_unparse_name(cred->ccache->smb_krb5_context->krb5_context, princ, &name);
89 char *err_mess = smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context, ret, cred);
90 DEBUG(1,("failed to unparse principal from ccache: %s\n",
92 talloc_free(err_mess);
96 realm = krb5_princ_realm(cred->ccache->smb_krb5_context->krb5_context, princ);
98 cli_credentials_set_principal(cred, name, obtained);
102 krb5_free_principal(cred->ccache->smb_krb5_context->krb5_context, princ);
104 cred->ccache_obtained = obtained;
109 /* Free a memory ccache */
110 static int free_mccache(struct ccache_container *ccc)
112 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache);
117 /* Free a disk-based ccache */
118 static int free_dccache(struct ccache_container *ccc) {
119 krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache);
124 int cli_credentials_set_ccache(struct cli_credentials *cred,
126 enum credentials_obtained obtained)
129 krb5_principal princ;
130 struct ccache_container *ccc;
131 if (cred->ccache_obtained > obtained) {
135 ccc = talloc(cred, struct ccache_container);
140 ret = cli_credentials_get_krb5_context(cred, &ccc->smb_krb5_context);
145 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
151 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
153 DEBUG(1,("failed to read krb5 ccache: %s: %s\n",
155 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
160 ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
162 DEBUG(3,("failed to read default krb5 ccache: %s\n",
163 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
169 talloc_set_destructor(ccc, free_dccache);
171 ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
174 DEBUG(3,("failed to get principal from default ccache: %s\n",
175 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
180 krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ);
183 talloc_steal(cred, ccc);
185 ret = cli_credentials_set_from_ccache(cred, obtained);
195 int cli_credentials_new_ccache(struct cli_credentials *cred, struct ccache_container **_ccc)
199 struct ccache_container *ccc = talloc(cred, struct ccache_container);
205 rand_string = generate_random_str(NULL, 16);
211 ccache_name = talloc_asprintf(ccc, "MEMORY:%s",
213 talloc_free(rand_string);
220 ret = cli_credentials_get_krb5_context(cred, &ccc->smb_krb5_context);
225 if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
230 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name, &ccc->ccache);
232 DEBUG(1,("failed to generate a new krb5 ccache (%s): %s\n",
234 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
235 talloc_free(ccache_name);
240 talloc_set_destructor(ccc, free_mccache);
243 talloc_steal(cred, ccc);
244 talloc_free(ccache_name);
253 int cli_credentials_get_ccache(struct cli_credentials *cred,
254 struct ccache_container **ccc)
258 if (cred->machine_account_pending) {
259 cli_credentials_set_machine_account(cred);
262 if (cred->ccache_obtained >= (MAX(cred->principal_obtained,
263 cred->username_obtained))) {
267 if (cli_credentials_is_anonymous(cred)) {
271 ret = cli_credentials_new_ccache(cred, NULL);
275 ret = kinit_to_ccache(cred, cred, cred->ccache->smb_krb5_context, cred->ccache->ccache);
279 ret = cli_credentials_set_from_ccache(cred, cred->principal_obtained);
288 static int free_gssapi_creds(struct gssapi_creds_container *gcc)
290 OM_uint32 min_stat, maj_stat;
291 maj_stat = gss_release_cred(&min_stat, &gcc->creds);
295 int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
296 struct gssapi_creds_container **_gcc)
299 OM_uint32 maj_stat, min_stat;
300 struct gssapi_creds_container *gcc;
301 struct ccache_container *ccache;
302 if (cred->client_gss_creds_obtained >= (MAX(cred->ccache_obtained,
303 MAX(cred->principal_obtained,
304 cred->username_obtained)))) {
305 *_gcc = cred->client_gss_creds;
308 ret = cli_credentials_get_ccache(cred,
311 DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret)));
315 gcc = talloc(cred, struct gssapi_creds_container);
320 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
330 cred->client_gss_creds_obtained = cred->ccache_obtained;
331 talloc_set_destructor(gcc, free_gssapi_creds);
332 cred->client_gss_creds = gcc;
339 Set a gssapi cred_id_t into the credentails system. (Client case)
341 This grabs the credentials both 'intact' and getting the krb5
342 ccache out of it. This routine can be generalised in future for
343 the case where we deal with GSSAPI mechs other than krb5.
345 On sucess, the caller must not free gssapi_cred, as it now belongs
346 to the credentials system.
349 int cli_credentials_set_client_gss_creds(struct cli_credentials *cred,
350 gss_cred_id_t gssapi_cred,
351 enum credentials_obtained obtained)
354 OM_uint32 maj_stat, min_stat;
355 struct ccache_container *ccc;
356 struct gssapi_creds_container *gcc;
357 if (cred->client_gss_creds_obtained > obtained) {
361 gcc = talloc(cred, struct gssapi_creds_container);
366 ret = cli_credentials_new_ccache(cred, &ccc);
371 maj_stat = gss_krb5_copy_ccache(&min_stat,
372 gssapi_cred, ccc->ccache);
382 ret = cli_credentials_set_from_ccache(cred, obtained);
385 gcc->creds = gssapi_cred;
386 talloc_set_destructor(gcc, free_gssapi_creds);
388 cred->client_gss_creds_obtained = obtained;
389 cred->client_gss_creds = gcc;
394 /* Get the keytab (actually, a container containing the krb5_keytab)
395 * attached to this context. If this hasn't been done or set before,
396 * it will be generated from the password.
398 int cli_credentials_get_keytab(struct cli_credentials *cred,
399 struct keytab_container **_ktc)
402 struct keytab_container *ktc;
403 struct smb_krb5_context *smb_krb5_context;
404 const char **enctype_strings;
407 if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
408 cred->username_obtained))) {
409 *_ktc = cred->keytab;
413 if (cli_credentials_is_anonymous(cred)) {
417 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
422 mem_ctx = talloc_new(cred);
427 enctype_strings = cli_credentials_get_enctype_strings(cred);
429 ret = smb_krb5_create_memory_keytab(mem_ctx, cred,
431 enctype_strings, &ktc);
433 talloc_free(mem_ctx);
437 cred->keytab_obtained = (MAX(cred->principal_obtained,
438 cred->username_obtained));
440 talloc_steal(cred, ktc);
442 *_ktc = cred->keytab;
443 talloc_free(mem_ctx);
447 /* Given the name of a keytab (presumably in the format
448 * FILE:/etc/krb5.keytab), open it and attach it */
450 int cli_credentials_set_keytab_name(struct cli_credentials *cred,
451 const char *keytab_name,
452 enum credentials_obtained obtained)
455 struct keytab_container *ktc;
456 struct smb_krb5_context *smb_krb5_context;
459 if (cred->keytab_obtained >= obtained) {
463 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
468 mem_ctx = talloc_new(cred);
473 ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context,
479 cred->keytab_obtained = obtained;
481 talloc_steal(cred, ktc);
483 talloc_free(mem_ctx);
488 int cli_credentials_update_keytab(struct cli_credentials *cred)
491 struct keytab_container *ktc;
492 struct smb_krb5_context *smb_krb5_context;
493 const char **enctype_strings;
496 mem_ctx = talloc_new(cred);
501 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
503 talloc_free(mem_ctx);
507 enctype_strings = cli_credentials_get_enctype_strings(cred);
509 ret = cli_credentials_get_keytab(cred, &ktc);
511 talloc_free(mem_ctx);
515 ret = smb_krb5_update_keytab(mem_ctx, cred, smb_krb5_context, enctype_strings, ktc);
517 talloc_free(mem_ctx);
521 /* Get server gss credentials (in gsskrb5, this means the keytab) */
523 int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
524 struct gssapi_creds_container **_gcc)
527 OM_uint32 maj_stat, min_stat;
528 struct gssapi_creds_container *gcc;
529 struct keytab_container *ktc;
530 struct smb_krb5_context *smb_krb5_context;
532 krb5_principal princ;
534 if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained,
535 MAX(cred->principal_obtained,
536 cred->username_obtained)))) {
537 *_gcc = cred->server_gss_creds;
541 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
546 ret = cli_credentials_get_keytab(cred,
549 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
553 mem_ctx = talloc_new(cred);
558 ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ);
560 DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
561 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
563 talloc_free(mem_ctx);
567 gcc = talloc(cred, struct gssapi_creds_container);
569 talloc_free(mem_ctx);
573 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
574 maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab,
584 cred->server_gss_creds_obtained = cred->keytab_obtained;
585 talloc_set_destructor(gcc, free_gssapi_creds);
586 cred->server_gss_creds = gcc;
589 talloc_free(mem_ctx);
597 void cli_credentials_set_kvno(struct cli_credentials *cred,
604 * Return Kerberos KVNO
607 int cli_credentials_get_kvno(struct cli_credentials *cred)
613 const char **cli_credentials_get_enctype_strings(struct cli_credentials *cred)
615 /* If this is ever made user-configurable, we need to add code
616 * to remove/hide the other entries from the generated
618 static const char *default_enctypes[] = {
620 "aes256-cts-hmac-sha1-96",
625 return default_enctypes;
628 const char *cli_credentials_get_salt_principal(struct cli_credentials *cred)
630 return cred->salt_principal;
633 void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal)
635 cred->salt_principal = talloc_strdup(cred, principal);