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"
29 int cli_credentials_get_krb5_context(struct cli_credentials
*cred
,
30 struct smb_krb5_context
**smb_krb5_context
)
33 if (cred
->smb_krb5_context
) {
34 *smb_krb5_context
= cred
->smb_krb5_context
;
38 ret
= smb_krb5_init_context(cred
, &cred
->smb_krb5_context
);
42 *smb_krb5_context
= cred
->smb_krb5_context
;
46 int cli_credentials_set_from_ccache(struct cli_credentials
*cred
,
47 enum credentials_obtained obtained
)
55 if (cred
->ccache_obtained
> obtained
) {
59 ret
= krb5_cc_get_principal(cred
->ccache
->smb_krb5_context
->krb5_context
,
60 cred
->ccache
->ccache
, &princ
);
63 char *err_mess
= smb_get_krb5_error_message(cred
->ccache
->smb_krb5_context
->krb5_context
, ret
, cred
);
64 DEBUG(1,("failed to get principal from ccache: %s\n",
66 talloc_free(err_mess
);
70 ret
= krb5_unparse_name(cred
->ccache
->smb_krb5_context
->krb5_context
, princ
, &name
);
72 char *err_mess
= smb_get_krb5_error_message(cred
->ccache
->smb_krb5_context
->krb5_context
, ret
, cred
);
73 DEBUG(1,("failed to unparse principal from ccache: %s\n",
75 talloc_free(err_mess
);
79 realm
= krb5_princ_realm(cred
->ccache
->smb_krb5_context
->krb5_context
, princ
);
81 cli_credentials_set_principal(cred
, name
, obtained
);
85 krb5_free_principal(cred
->ccache
->smb_krb5_context
->krb5_context
, princ
);
87 cred
->ccache_obtained
= obtained
;
92 /* Free a memory ccache */
93 static int free_mccache(void *ptr
) {
94 struct ccache_container
*ccc
= ptr
;
95 krb5_cc_destroy(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
);
100 /* Free a disk-based ccache */
101 static int free_dccache(void *ptr
) {
102 struct ccache_container
*ccc
= ptr
;
103 krb5_cc_close(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
);
108 int cli_credentials_set_ccache(struct cli_credentials
*cred
,
110 enum credentials_obtained obtained
)
113 krb5_principal princ
;
114 struct ccache_container
*ccc
;
115 if (cred
->ccache_obtained
> obtained
) {
119 ccc
= talloc(cred
, struct ccache_container
);
124 ret
= cli_credentials_get_krb5_context(cred
, &ccc
->smb_krb5_context
);
129 talloc_reference(ccc
, ccc
->smb_krb5_context
);
132 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, name
, &ccc
->ccache
);
134 DEBUG(1,("failed to read krb5 ccache: %s: %s\n",
136 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
, ret
, ccc
)));
141 ret
= krb5_cc_default(ccc
->smb_krb5_context
->krb5_context
, &ccc
->ccache
);
143 DEBUG(3,("failed to read default krb5 ccache: %s\n",
144 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
, ret
, ccc
)));
150 talloc_set_destructor(ccc
, free_dccache
);
152 ret
= krb5_cc_get_principal(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
, &princ
);
155 DEBUG(3,("failed to get principal from default ccache: %s\n",
156 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
, ret
, ccc
)));
161 krb5_free_principal(ccc
->smb_krb5_context
->krb5_context
, princ
);
164 talloc_steal(cred
, ccc
);
166 ret
= cli_credentials_set_from_ccache(cred
, obtained
);
176 int cli_credentials_new_ccache(struct cli_credentials
*cred
, struct ccache_container
**_ccc
)
180 struct ccache_container
*ccc
= talloc(cred
, struct ccache_container
);
186 rand_string
= generate_random_str(NULL
, 16);
192 ccache_name
= talloc_asprintf(ccc
, "MEMORY:%s",
194 talloc_free(rand_string
);
201 ret
= cli_credentials_get_krb5_context(cred
, &ccc
->smb_krb5_context
);
206 talloc_reference(ccc
, ccc
->smb_krb5_context
);
208 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, ccache_name
, &ccc
->ccache
);
210 DEBUG(1,("failed to generate a new krb5 ccache (%s): %s\n",
212 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
, ret
, ccc
)));
213 talloc_free(ccache_name
);
218 talloc_set_destructor(ccc
, free_mccache
);
221 talloc_steal(cred
, ccc
);
222 talloc_free(ccache_name
);
231 int cli_credentials_get_ccache(struct cli_credentials
*cred
,
232 struct ccache_container
**ccc
)
236 if (cred
->ccache_obtained
>= (MAX(cred
->principal_obtained
,
237 cred
->username_obtained
))) {
241 if (cli_credentials_is_anonymous(cred
)) {
245 ret
= cli_credentials_new_ccache(cred
, NULL
);
249 ret
= kinit_to_ccache(cred
, cred
, cred
->ccache
->smb_krb5_context
, cred
->ccache
->ccache
);
253 ret
= cli_credentials_set_from_ccache(cred
, cred
->principal_obtained
);
262 static int free_gssapi_creds(void *ptr
) {
263 OM_uint32 min_stat
, maj_stat
;
264 struct gssapi_creds_container
*gcc
= ptr
;
265 maj_stat
= gss_release_cred(&min_stat
,
270 int cli_credentials_get_client_gss_creds(struct cli_credentials
*cred
,
271 struct gssapi_creds_container
**_gcc
)
274 OM_uint32 maj_stat
, min_stat
;
275 struct gssapi_creds_container
*gcc
;
276 struct ccache_container
*ccache
;
277 if (cred
->client_gss_creds_obtained
>= (MAX(cred
->ccache_obtained
,
278 MAX(cred
->principal_obtained
,
279 cred
->username_obtained
)))) {
280 *_gcc
= cred
->client_gss_creds
;
283 ret
= cli_credentials_get_ccache(cred
,
286 DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret
)));
290 gcc
= talloc(cred
, struct gssapi_creds_container
);
295 maj_stat
= gss_krb5_import_cred(&min_stat
, ccache
->ccache
, NULL
, NULL
,
305 cred
->client_gss_creds_obtained
= cred
->ccache_obtained
;
306 talloc_set_destructor(gcc
, free_gssapi_creds
);
307 cred
->client_gss_creds
= gcc
;
314 Set a gssapi cred_id_t into the credentails system. (Client case)
316 This grabs the credentials both 'intact' and getting the krb5
317 ccache out of it. This routine can be generalised in future for
318 the case where we deal with GSSAPI mechs other than krb5.
320 On sucess, the caller must not free gssapi_cred, as it now belongs
321 to the credentials system.
324 int cli_credentials_set_client_gss_creds(struct cli_credentials
*cred
,
325 gss_cred_id_t gssapi_cred
,
326 enum credentials_obtained obtained
)
329 OM_uint32 maj_stat
, min_stat
;
330 struct ccache_container
*ccc
;
331 struct gssapi_creds_container
*gcc
;
332 if (cred
->client_gss_creds_obtained
> obtained
) {
336 gcc
= talloc(cred
, struct gssapi_creds_container
);
341 ret
= cli_credentials_new_ccache(cred
, &ccc
);
346 maj_stat
= gss_krb5_copy_ccache(&min_stat
,
347 gssapi_cred
, ccc
->ccache
);
357 ret
= cli_credentials_set_from_ccache(cred
, obtained
);
360 gcc
->creds
= gssapi_cred
;
361 talloc_set_destructor(gcc
, free_gssapi_creds
);
363 cred
->client_gss_creds_obtained
= obtained
;
364 cred
->client_gss_creds
= gcc
;
369 /* Get the keytab (actually, a container containing the krb5_keytab)
370 * attached to this context. If this hasn't been done or set before,
371 * it will be generated from the password.
373 int cli_credentials_get_keytab(struct cli_credentials
*cred
,
374 struct keytab_container
**_ktc
)
377 struct keytab_container
*ktc
;
378 struct smb_krb5_context
*smb_krb5_context
;
381 if (cred
->keytab_obtained
>= (MAX(cred
->principal_obtained
,
382 cred
->username_obtained
))) {
383 *_ktc
= cred
->keytab
;
387 if (cli_credentials_is_anonymous(cred
)) {
391 ret
= cli_credentials_get_krb5_context(cred
, &smb_krb5_context
);
396 mem_ctx
= talloc_new(cred
);
401 ret
= smb_krb5_create_memory_keytab(mem_ctx
, cred
, smb_krb5_context
, &ktc
);
403 talloc_free(mem_ctx
);
407 cred
->keytab_obtained
= (MAX(cred
->principal_obtained
,
408 cred
->username_obtained
));
410 talloc_steal(cred
, ktc
);
412 *_ktc
= cred
->keytab
;
413 talloc_free(mem_ctx
);
417 /* Given the name of a keytab (presumably in the format
418 * FILE:/etc/krb5.keytab), open it and attach it */
420 int cli_credentials_set_keytab_name(struct cli_credentials
*cred
,
421 const char *keytab_name
,
422 enum credentials_obtained obtained
)
425 struct keytab_container
*ktc
;
426 struct smb_krb5_context
*smb_krb5_context
;
429 if (cred
->keytab_obtained
>= obtained
) {
433 ret
= cli_credentials_get_krb5_context(cred
, &smb_krb5_context
);
438 mem_ctx
= talloc_new(cred
);
443 ret
= smb_krb5_open_keytab(mem_ctx
, smb_krb5_context
,
449 cred
->keytab_obtained
= obtained
;
451 talloc_steal(cred
, ktc
);
453 talloc_free(mem_ctx
);
458 int cli_credentials_update_keytab(struct cli_credentials
*cred
)
461 struct keytab_container
*ktc
;
462 struct smb_krb5_context
*smb_krb5_context
;
465 mem_ctx
= talloc_new(cred
);
470 ret
= cli_credentials_get_krb5_context(cred
, &smb_krb5_context
);
472 talloc_free(mem_ctx
);
476 ret
= cli_credentials_get_keytab(cred
, &ktc
);
478 talloc_free(mem_ctx
);
482 ret
= smb_krb5_update_keytab(mem_ctx
, cred
, smb_krb5_context
, ktc
);
484 talloc_free(mem_ctx
);
488 /* Get server gss credentials (in gsskrb5, this means the keytab) */
490 int cli_credentials_get_server_gss_creds(struct cli_credentials
*cred
,
491 struct gssapi_creds_container
**_gcc
)
494 OM_uint32 maj_stat
, min_stat
;
495 struct gssapi_creds_container
*gcc
;
496 struct keytab_container
*ktc
;
497 struct smb_krb5_context
*smb_krb5_context
;
499 krb5_principal princ
;
501 if (cred
->server_gss_creds_obtained
>= (MAX(cred
->keytab_obtained
,
502 MAX(cred
->principal_obtained
,
503 cred
->username_obtained
)))) {
504 *_gcc
= cred
->server_gss_creds
;
508 ret
= cli_credentials_get_krb5_context(cred
, &smb_krb5_context
);
513 ret
= cli_credentials_get_keytab(cred
,
516 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret
)));
520 mem_ctx
= talloc_new(cred
);
525 ret
= principal_from_credentials(mem_ctx
, cred
, smb_krb5_context
, &princ
);
527 DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
528 smb_get_krb5_error_message(smb_krb5_context
->krb5_context
,
530 talloc_free(mem_ctx
);
534 gcc
= talloc(cred
, struct gssapi_creds_container
);
536 talloc_free(mem_ctx
);
540 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
541 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, princ
, ktc
->keytab
,
551 cred
->server_gss_creds_obtained
= cred
->keytab_obtained
;
552 talloc_set_destructor(gcc
, free_gssapi_creds
);
553 cred
->server_gss_creds
= gcc
;
556 talloc_free(mem_ctx
);
564 void cli_credentials_set_kvno(struct cli_credentials
*cred
,
571 * Return Kerberos KVNO
574 int cli_credentials_get_kvno(struct cli_credentials
*cred
)
579 const char *cli_credentials_get_salt_principal(struct cli_credentials
*cred
)
581 return cred
->salt_principal
;
584 void cli_credentials_set_salt_principal(struct cli_credentials
*cred
, const char *principal
)
586 cred
->salt_principal
= talloc_strdup(cred
, principal
);