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 /* This needs to be called directly after the cli_credentials_init(),
47 * otherwise we might have problems with the krb5 context already
50 NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred,
51 struct smb_krb5_context *smb_krb5_context)
53 if (!talloc_reference(cred, smb_krb5_context)) {
54 return NT_STATUS_NO_MEMORY;
56 cred->smb_krb5_context = smb_krb5_context;
60 int cli_credentials_set_from_ccache(struct cli_credentials *cred,
61 enum credentials_obtained obtained)
69 if (cred->ccache_obtained > obtained) {
73 ret = krb5_cc_get_principal(cred->ccache->smb_krb5_context->krb5_context,
74 cred->ccache->ccache, &princ);
77 char *err_mess = smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context, ret, cred);
78 DEBUG(1,("failed to get principal from ccache: %s\n",
80 talloc_free(err_mess);
84 ret = krb5_unparse_name(cred->ccache->smb_krb5_context->krb5_context, princ, &name);
86 char *err_mess = smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context, ret, cred);
87 DEBUG(1,("failed to unparse principal from ccache: %s\n",
89 talloc_free(err_mess);
93 realm = krb5_princ_realm(cred->ccache->smb_krb5_context->krb5_context, princ);
95 cli_credentials_set_principal(cred, name, obtained);
99 krb5_free_principal(cred->ccache->smb_krb5_context->krb5_context, princ);
101 cred->ccache_obtained = obtained;
106 /* Free a memory ccache */
107 static int free_mccache(void *ptr) {
108 struct ccache_container *ccc = ptr;
109 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache);
114 /* Free a disk-based ccache */
115 static int free_dccache(void *ptr) {
116 struct ccache_container *ccc = ptr;
117 krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache);
122 int cli_credentials_set_ccache(struct cli_credentials *cred,
124 enum credentials_obtained obtained)
127 krb5_principal princ;
128 struct ccache_container *ccc;
129 if (cred->ccache_obtained > obtained) {
133 ccc = talloc(cred, struct ccache_container);
138 ret = cli_credentials_get_krb5_context(cred, &ccc->smb_krb5_context);
143 talloc_reference(ccc, ccc->smb_krb5_context);
146 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
148 DEBUG(1,("failed to read krb5 ccache: %s: %s\n",
150 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
155 ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
157 DEBUG(3,("failed to read default krb5 ccache: %s\n",
158 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
164 talloc_set_destructor(ccc, free_dccache);
166 ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
169 DEBUG(3,("failed to get principal from default ccache: %s\n",
170 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
175 krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ);
178 talloc_steal(cred, ccc);
180 ret = cli_credentials_set_from_ccache(cred, obtained);
190 int cli_credentials_new_ccache(struct cli_credentials *cred, struct ccache_container **_ccc)
194 struct ccache_container *ccc = talloc(cred, struct ccache_container);
200 rand_string = generate_random_str(NULL, 16);
206 ccache_name = talloc_asprintf(ccc, "MEMORY:%s",
208 talloc_free(rand_string);
215 ret = cli_credentials_get_krb5_context(cred, &ccc->smb_krb5_context);
220 talloc_reference(ccc, ccc->smb_krb5_context);
222 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name, &ccc->ccache);
224 DEBUG(1,("failed to generate a new krb5 ccache (%s): %s\n",
226 smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
227 talloc_free(ccache_name);
232 talloc_set_destructor(ccc, free_mccache);
235 talloc_steal(cred, ccc);
236 talloc_free(ccache_name);
245 int cli_credentials_get_ccache(struct cli_credentials *cred,
246 struct ccache_container **ccc)
250 if (cred->ccache_obtained >= (MAX(cred->principal_obtained,
251 cred->username_obtained))) {
255 if (cli_credentials_is_anonymous(cred)) {
259 ret = cli_credentials_new_ccache(cred, NULL);
263 ret = kinit_to_ccache(cred, cred, cred->ccache->smb_krb5_context, cred->ccache->ccache);
267 ret = cli_credentials_set_from_ccache(cred, cred->principal_obtained);
276 static int free_gssapi_creds(void *ptr) {
277 OM_uint32 min_stat, maj_stat;
278 struct gssapi_creds_container *gcc = ptr;
279 maj_stat = gss_release_cred(&min_stat,
284 int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
285 struct gssapi_creds_container **_gcc)
288 OM_uint32 maj_stat, min_stat;
289 struct gssapi_creds_container *gcc;
290 struct ccache_container *ccache;
291 if (cred->client_gss_creds_obtained >= (MAX(cred->ccache_obtained,
292 MAX(cred->principal_obtained,
293 cred->username_obtained)))) {
294 *_gcc = cred->client_gss_creds;
297 ret = cli_credentials_get_ccache(cred,
300 DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret)));
304 gcc = talloc(cred, struct gssapi_creds_container);
309 maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
319 cred->client_gss_creds_obtained = cred->ccache_obtained;
320 talloc_set_destructor(gcc, free_gssapi_creds);
321 cred->client_gss_creds = gcc;
328 Set a gssapi cred_id_t into the credentails system. (Client case)
330 This grabs the credentials both 'intact' and getting the krb5
331 ccache out of it. This routine can be generalised in future for
332 the case where we deal with GSSAPI mechs other than krb5.
334 On sucess, the caller must not free gssapi_cred, as it now belongs
335 to the credentials system.
338 int cli_credentials_set_client_gss_creds(struct cli_credentials *cred,
339 gss_cred_id_t gssapi_cred,
340 enum credentials_obtained obtained)
343 OM_uint32 maj_stat, min_stat;
344 struct ccache_container *ccc;
345 struct gssapi_creds_container *gcc;
346 if (cred->client_gss_creds_obtained > obtained) {
350 gcc = talloc(cred, struct gssapi_creds_container);
355 ret = cli_credentials_new_ccache(cred, &ccc);
360 maj_stat = gss_krb5_copy_ccache(&min_stat,
361 gssapi_cred, ccc->ccache);
371 ret = cli_credentials_set_from_ccache(cred, obtained);
374 gcc->creds = gssapi_cred;
375 talloc_set_destructor(gcc, free_gssapi_creds);
377 cred->client_gss_creds_obtained = obtained;
378 cred->client_gss_creds = gcc;
383 /* Get the keytab (actually, a container containing the krb5_keytab)
384 * attached to this context. If this hasn't been done or set before,
385 * it will be generated from the password.
387 int cli_credentials_get_keytab(struct cli_credentials *cred,
388 struct keytab_container **_ktc)
391 struct keytab_container *ktc;
392 struct smb_krb5_context *smb_krb5_context;
395 if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
396 cred->username_obtained))) {
397 *_ktc = cred->keytab;
401 if (cli_credentials_is_anonymous(cred)) {
405 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
410 mem_ctx = talloc_new(cred);
415 ret = smb_krb5_create_memory_keytab(mem_ctx, cred, smb_krb5_context, &ktc);
417 talloc_free(mem_ctx);
421 cred->keytab_obtained = (MAX(cred->principal_obtained,
422 cred->username_obtained));
424 talloc_steal(cred, ktc);
426 *_ktc = cred->keytab;
427 talloc_free(mem_ctx);
431 /* Given the name of a keytab (presumably in the format
432 * FILE:/etc/krb5.keytab), open it and attach it */
434 int cli_credentials_set_keytab_name(struct cli_credentials *cred,
435 const char *keytab_name,
436 enum credentials_obtained obtained)
439 struct keytab_container *ktc;
440 struct smb_krb5_context *smb_krb5_context;
443 if (cred->keytab_obtained >= obtained) {
447 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
452 mem_ctx = talloc_new(cred);
457 ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context,
463 cred->keytab_obtained = obtained;
465 talloc_steal(cred, ktc);
467 talloc_free(mem_ctx);
472 int cli_credentials_update_keytab(struct cli_credentials *cred)
475 struct keytab_container *ktc;
476 struct smb_krb5_context *smb_krb5_context;
479 mem_ctx = talloc_new(cred);
484 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
486 talloc_free(mem_ctx);
490 ret = cli_credentials_get_keytab(cred, &ktc);
492 talloc_free(mem_ctx);
496 ret = smb_krb5_update_keytab(mem_ctx, cred, smb_krb5_context, ktc);
498 talloc_free(mem_ctx);
502 /* Get server gss credentials (in gsskrb5, this means the keytab) */
504 int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
505 struct gssapi_creds_container **_gcc)
508 OM_uint32 maj_stat, min_stat;
509 struct gssapi_creds_container *gcc;
510 struct keytab_container *ktc;
511 struct smb_krb5_context *smb_krb5_context;
513 krb5_principal princ;
515 if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained,
516 MAX(cred->principal_obtained,
517 cred->username_obtained)))) {
518 *_gcc = cred->server_gss_creds;
522 ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
527 ret = cli_credentials_get_keytab(cred,
530 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
534 mem_ctx = talloc_new(cred);
539 ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ);
541 DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
542 smb_get_krb5_error_message(smb_krb5_context->krb5_context,
544 talloc_free(mem_ctx);
548 gcc = talloc(cred, struct gssapi_creds_container);
550 talloc_free(mem_ctx);
554 /* This creates a GSSAPI cred_id_t with the principal and keytab set */
555 maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab,
565 cred->server_gss_creds_obtained = cred->keytab_obtained;
566 talloc_set_destructor(gcc, free_gssapi_creds);
567 cred->server_gss_creds = gcc;
570 talloc_free(mem_ctx);
578 void cli_credentials_set_kvno(struct cli_credentials *cred,
585 * Return Kerberos KVNO
588 int cli_credentials_get_kvno(struct cli_credentials *cred)
593 const char *cli_credentials_get_salt_principal(struct cli_credentials *cred)
595 return cred->salt_principal;
598 void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal)
600 cred->salt_principal = talloc_strdup(cred, principal);