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 talloc_reference(ccc
, ccc
->smb_krb5_context
);
147 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, name
, &ccc
->ccache
);
149 DEBUG(1,("failed to read krb5 ccache: %s: %s\n",
151 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
, ret
, ccc
)));
156 ret
= krb5_cc_default(ccc
->smb_krb5_context
->krb5_context
, &ccc
->ccache
);
158 DEBUG(3,("failed to read default krb5 ccache: %s\n",
159 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
, ret
, ccc
)));
165 talloc_set_destructor(ccc
, free_dccache
);
167 ret
= krb5_cc_get_principal(ccc
->smb_krb5_context
->krb5_context
, ccc
->ccache
, &princ
);
170 DEBUG(3,("failed to get principal from default ccache: %s\n",
171 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
, ret
, ccc
)));
176 krb5_free_principal(ccc
->smb_krb5_context
->krb5_context
, princ
);
179 talloc_steal(cred
, ccc
);
181 ret
= cli_credentials_set_from_ccache(cred
, obtained
);
191 int cli_credentials_new_ccache(struct cli_credentials
*cred
, struct ccache_container
**_ccc
)
195 struct ccache_container
*ccc
= talloc(cred
, struct ccache_container
);
201 rand_string
= generate_random_str(NULL
, 16);
207 ccache_name
= talloc_asprintf(ccc
, "MEMORY:%s",
209 talloc_free(rand_string
);
216 ret
= cli_credentials_get_krb5_context(cred
, &ccc
->smb_krb5_context
);
221 talloc_reference(ccc
, ccc
->smb_krb5_context
);
223 ret
= krb5_cc_resolve(ccc
->smb_krb5_context
->krb5_context
, ccache_name
, &ccc
->ccache
);
225 DEBUG(1,("failed to generate a new krb5 ccache (%s): %s\n",
227 smb_get_krb5_error_message(ccc
->smb_krb5_context
->krb5_context
, ret
, ccc
)));
228 talloc_free(ccache_name
);
233 talloc_set_destructor(ccc
, free_mccache
);
236 talloc_steal(cred
, ccc
);
237 talloc_free(ccache_name
);
246 int cli_credentials_get_ccache(struct cli_credentials
*cred
,
247 struct ccache_container
**ccc
)
251 if (cred
->machine_account_pending
) {
252 cli_credentials_set_machine_account(cred
);
255 if (cred
->ccache_obtained
>= (MAX(cred
->principal_obtained
,
256 cred
->username_obtained
))) {
260 if (cli_credentials_is_anonymous(cred
)) {
264 ret
= cli_credentials_new_ccache(cred
, NULL
);
268 ret
= kinit_to_ccache(cred
, cred
, cred
->ccache
->smb_krb5_context
, cred
->ccache
->ccache
);
272 ret
= cli_credentials_set_from_ccache(cred
, cred
->principal_obtained
);
281 static int free_gssapi_creds(struct gssapi_creds_container
*gcc
)
283 OM_uint32 min_stat
, maj_stat
;
284 maj_stat
= gss_release_cred(&min_stat
, &gcc
->creds
);
288 int cli_credentials_get_client_gss_creds(struct cli_credentials
*cred
,
289 struct gssapi_creds_container
**_gcc
)
292 OM_uint32 maj_stat
, min_stat
;
293 struct gssapi_creds_container
*gcc
;
294 struct ccache_container
*ccache
;
295 if (cred
->client_gss_creds_obtained
>= (MAX(cred
->ccache_obtained
,
296 MAX(cred
->principal_obtained
,
297 cred
->username_obtained
)))) {
298 *_gcc
= cred
->client_gss_creds
;
301 ret
= cli_credentials_get_ccache(cred
,
304 DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret
)));
308 gcc
= talloc(cred
, struct gssapi_creds_container
);
313 maj_stat
= gss_krb5_import_cred(&min_stat
, ccache
->ccache
, NULL
, NULL
,
323 cred
->client_gss_creds_obtained
= cred
->ccache_obtained
;
324 talloc_set_destructor(gcc
, free_gssapi_creds
);
325 cred
->client_gss_creds
= gcc
;
332 Set a gssapi cred_id_t into the credentails system. (Client case)
334 This grabs the credentials both 'intact' and getting the krb5
335 ccache out of it. This routine can be generalised in future for
336 the case where we deal with GSSAPI mechs other than krb5.
338 On sucess, the caller must not free gssapi_cred, as it now belongs
339 to the credentials system.
342 int cli_credentials_set_client_gss_creds(struct cli_credentials
*cred
,
343 gss_cred_id_t gssapi_cred
,
344 enum credentials_obtained obtained
)
347 OM_uint32 maj_stat
, min_stat
;
348 struct ccache_container
*ccc
;
349 struct gssapi_creds_container
*gcc
;
350 if (cred
->client_gss_creds_obtained
> obtained
) {
354 gcc
= talloc(cred
, struct gssapi_creds_container
);
359 ret
= cli_credentials_new_ccache(cred
, &ccc
);
364 maj_stat
= gss_krb5_copy_ccache(&min_stat
,
365 gssapi_cred
, ccc
->ccache
);
375 ret
= cli_credentials_set_from_ccache(cred
, obtained
);
378 gcc
->creds
= gssapi_cred
;
379 talloc_set_destructor(gcc
, free_gssapi_creds
);
381 cred
->client_gss_creds_obtained
= obtained
;
382 cred
->client_gss_creds
= gcc
;
387 /* Get the keytab (actually, a container containing the krb5_keytab)
388 * attached to this context. If this hasn't been done or set before,
389 * it will be generated from the password.
391 int cli_credentials_get_keytab(struct cli_credentials
*cred
,
392 struct keytab_container
**_ktc
)
395 struct keytab_container
*ktc
;
396 struct smb_krb5_context
*smb_krb5_context
;
399 if (cred
->keytab_obtained
>= (MAX(cred
->principal_obtained
,
400 cred
->username_obtained
))) {
401 *_ktc
= cred
->keytab
;
405 if (cli_credentials_is_anonymous(cred
)) {
409 ret
= cli_credentials_get_krb5_context(cred
, &smb_krb5_context
);
414 mem_ctx
= talloc_new(cred
);
419 ret
= smb_krb5_create_memory_keytab(mem_ctx
, cred
, smb_krb5_context
, &ktc
);
421 talloc_free(mem_ctx
);
425 cred
->keytab_obtained
= (MAX(cred
->principal_obtained
,
426 cred
->username_obtained
));
428 talloc_steal(cred
, ktc
);
430 *_ktc
= cred
->keytab
;
431 talloc_free(mem_ctx
);
435 /* Given the name of a keytab (presumably in the format
436 * FILE:/etc/krb5.keytab), open it and attach it */
438 int cli_credentials_set_keytab_name(struct cli_credentials
*cred
,
439 const char *keytab_name
,
440 enum credentials_obtained obtained
)
443 struct keytab_container
*ktc
;
444 struct smb_krb5_context
*smb_krb5_context
;
447 if (cred
->keytab_obtained
>= obtained
) {
451 ret
= cli_credentials_get_krb5_context(cred
, &smb_krb5_context
);
456 mem_ctx
= talloc_new(cred
);
461 ret
= smb_krb5_open_keytab(mem_ctx
, smb_krb5_context
,
467 cred
->keytab_obtained
= obtained
;
469 talloc_steal(cred
, ktc
);
471 talloc_free(mem_ctx
);
476 int cli_credentials_update_keytab(struct cli_credentials
*cred
)
479 struct keytab_container
*ktc
;
480 struct smb_krb5_context
*smb_krb5_context
;
483 mem_ctx
= talloc_new(cred
);
488 ret
= cli_credentials_get_krb5_context(cred
, &smb_krb5_context
);
490 talloc_free(mem_ctx
);
494 ret
= cli_credentials_get_keytab(cred
, &ktc
);
496 talloc_free(mem_ctx
);
500 ret
= smb_krb5_update_keytab(mem_ctx
, cred
, smb_krb5_context
, ktc
);
502 talloc_free(mem_ctx
);
506 /* Get server gss credentials (in gsskrb5, this means the keytab) */
508 int cli_credentials_get_server_gss_creds(struct cli_credentials
*cred
,
509 struct gssapi_creds_container
**_gcc
)
512 OM_uint32 maj_stat
, min_stat
;
513 struct gssapi_creds_container
*gcc
;
514 struct keytab_container
*ktc
;
515 struct smb_krb5_context
*smb_krb5_context
;
517 krb5_principal princ
;
519 if (cred
->server_gss_creds_obtained
>= (MAX(cred
->keytab_obtained
,
520 MAX(cred
->principal_obtained
,
521 cred
->username_obtained
)))) {
522 *_gcc
= cred
->server_gss_creds
;
526 ret
= cli_credentials_get_krb5_context(cred
, &smb_krb5_context
);
531 ret
= cli_credentials_get_keytab(cred
,
534 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret
)));
538 mem_ctx
= talloc_new(cred
);
543 ret
= principal_from_credentials(mem_ctx
, cred
, smb_krb5_context
, &princ
);
545 DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
546 smb_get_krb5_error_message(smb_krb5_context
->krb5_context
,
548 talloc_free(mem_ctx
);
552 gcc
= talloc(cred
, struct gssapi_creds_container
);
554 talloc_free(mem_ctx
);
558 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
559 maj_stat
= gss_krb5_import_cred(&min_stat
, NULL
, princ
, ktc
->keytab
,
569 cred
->server_gss_creds_obtained
= cred
->keytab_obtained
;
570 talloc_set_destructor(gcc
, free_gssapi_creds
);
571 cred
->server_gss_creds
= gcc
;
574 talloc_free(mem_ctx
);
582 void cli_credentials_set_kvno(struct cli_credentials
*cred
,
589 * Return Kerberos KVNO
592 int cli_credentials_get_kvno(struct cli_credentials
*cred
)
597 const char *cli_credentials_get_salt_principal(struct cli_credentials
*cred
)
599 return cred
->salt_principal
;
602 void cli_credentials_set_salt_principal(struct cli_credentials
*cred
, const char *principal
)
604 cred
->salt_principal
= talloc_strdup(cred
, principal
);