📄 credentials_krb5.c
字号:
/* Unix SMB/CIFS implementation. Handle user credentials (as regards krb5) Copyright (C) Jelmer Vernooij 2005 Copyright (C) Tim Potter 2001 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "system/kerberos.h"#include "auth/kerberos/kerberos.h"#include "auth/credentials/credentials.h"#include "auth/credentials/credentials_proto.h"#include "auth/credentials/credentials_krb5.h"#include "param/param.h"_PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred, struct event_context *event_ctx, struct loadparm_context *lp_ctx, struct smb_krb5_context **smb_krb5_context) { int ret; if (cred->smb_krb5_context) { *smb_krb5_context = cred->smb_krb5_context; return 0; } ret = smb_krb5_init_context(cred, event_ctx, lp_ctx, &cred->smb_krb5_context); if (ret) { cred->smb_krb5_context = NULL; return ret; } *smb_krb5_context = cred->smb_krb5_context; return 0;}/* This needs to be called directly after the cli_credentials_init(), * otherwise we might have problems with the krb5 context already * being here. */_PUBLIC_ NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred, struct smb_krb5_context *smb_krb5_context){ if (!talloc_reference(cred, smb_krb5_context)) { return NT_STATUS_NO_MEMORY; } cred->smb_krb5_context = smb_krb5_context; return NT_STATUS_OK;}static int cli_credentials_set_from_ccache(struct cli_credentials *cred, struct ccache_container *ccache, enum credentials_obtained obtained){ krb5_principal princ; krb5_error_code ret; char *name; char **realm; if (cred->ccache_obtained > obtained) { return 0; } ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context, ccache->ccache, &princ); if (ret) { char *err_mess = smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context, ret, cred); DEBUG(1,("failed to get principal from ccache: %s\n", err_mess)); talloc_free(err_mess); return ret; } ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name); if (ret) { char *err_mess = smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context, ret, cred); DEBUG(1,("failed to unparse principal from ccache: %s\n", err_mess)); talloc_free(err_mess); return ret; } realm = krb5_princ_realm(ccache->smb_krb5_context->krb5_context, princ); cli_credentials_set_principal(cred, name, obtained); free(name); krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ); /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */ cred->ccache_obtained = obtained; return 0;}/* Free a memory ccache */static int free_mccache(struct ccache_container *ccc){ krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache); return 0;}/* Free a disk-based ccache */static int free_dccache(struct ccache_container *ccc) { krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache); return 0;}_PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred, struct event_context *event_ctx, struct loadparm_context *lp_ctx, const char *name, enum credentials_obtained obtained){ krb5_error_code ret; krb5_principal princ; struct ccache_container *ccc; if (cred->ccache_obtained > obtained) { return 0; } ccc = talloc(cred, struct ccache_container); if (!ccc) { return ENOMEM; } ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, &ccc->smb_krb5_context); if (ret) { talloc_free(ccc); return ret; } if (!talloc_reference(ccc, ccc->smb_krb5_context)) { talloc_free(ccc); return ENOMEM; } if (name) { ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache); if (ret) { DEBUG(1,("failed to read krb5 ccache: %s: %s\n", name, smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc))); talloc_free(ccc); return ret; } } else { ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache); if (ret) { DEBUG(3,("failed to read default krb5 ccache: %s\n", smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc))); talloc_free(ccc); return ret; } } talloc_set_destructor(ccc, free_dccache); ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ); if (ret) { DEBUG(3,("failed to get principal from default ccache: %s\n", smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc))); talloc_free(ccc); return ret; } krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ); ret = cli_credentials_set_from_ccache(cred, ccc, obtained); if (ret) { return ret; } cred->ccache = ccc; cred->ccache_obtained = obtained; talloc_steal(cred, ccc); cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained); return 0;}static int cli_credentials_new_ccache(struct cli_credentials *cred, struct event_context *event_ctx, struct loadparm_context *lp_ctx, struct ccache_container **_ccc){ krb5_error_code ret; struct ccache_container *ccc = talloc(cred, struct ccache_container); char *ccache_name; if (!ccc) { return ENOMEM; } ccache_name = talloc_asprintf(ccc, "MEMORY:%p", ccc); if (!ccache_name) { talloc_free(ccc); return ENOMEM; } ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, &ccc->smb_krb5_context); if (ret) { talloc_free(ccc); return ret; } if (!talloc_reference(ccc, ccc->smb_krb5_context)) { talloc_free(ccc); return ENOMEM; } ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name, &ccc->ccache); if (ret) { DEBUG(1,("failed to generate a new krb5 ccache (%s): %s\n", ccache_name, smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc))); talloc_free(ccache_name); talloc_free(ccc); return ret; } talloc_set_destructor(ccc, free_mccache); talloc_free(ccache_name); *_ccc = ccc; return ret;}_PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred, struct event_context *event_ctx, struct loadparm_context *lp_ctx, struct ccache_container **ccc){ krb5_error_code ret; if (cred->machine_account_pending) { cli_credentials_set_machine_account(cred, lp_ctx); } if (cred->ccache_obtained >= cred->ccache_threshold && cred->ccache_obtained > CRED_UNINITIALISED) { *ccc = cred->ccache; return 0; } if (cli_credentials_is_anonymous(cred)) { return EINVAL; } ret = cli_credentials_new_ccache(cred, event_ctx, lp_ctx, ccc); if (ret) { return ret; } ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, (*ccc)->ccache); if (ret) { return ret; } ret = cli_credentials_set_from_ccache(cred, *ccc, (MAX(MAX(cred->principal_obtained, cred->username_obtained), cred->password_obtained))); cred->ccache = *ccc; cred->ccache_obtained = cred->principal_obtained; if (ret) { return ret; } cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained); return ret;}void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred, enum credentials_obtained obtained){ /* If the caller just changed the username/password etc, then * any cached credentials are now invalid */ if (obtained >= cred->client_gss_creds_obtained) { if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) { talloc_unlink(cred, cred->client_gss_creds); cred->client_gss_creds = NULL; } cred->client_gss_creds_obtained = CRED_UNINITIALISED; } /* Now that we know that the data is 'this specified', then * don't allow something less 'known' to be returned as a * ccache. Ie, if the username is on the commmand line, we * don't want to later guess to use a file-based ccache */ if (obtained > cred->client_gss_creds_threshold) { cred->client_gss_creds_threshold = obtained; }}_PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred, enum credentials_obtained obtained){ /* If the caller just changed the username/password etc, then * any cached credentials are now invalid */ if (obtained >= cred->ccache_obtained) { if (cred->ccache_obtained > CRED_UNINITIALISED) { talloc_unlink(cred, cred->ccache); cred->ccache = NULL; } cred->ccache_obtained = CRED_UNINITIALISED; } /* Now that we know that the data is 'this specified', then * don't allow something less 'known' to be returned as a * ccache. Ie, if the username is on the commmand line, we * don't want to later guess to use a file-based ccache */ if (obtained > cred->ccache_threshold) { cred->ccache_threshold = obtained; } cli_credentials_invalidate_client_gss_creds(cred, obtained);}static int free_gssapi_creds(struct gssapi_creds_container *gcc){ OM_uint32 min_stat, maj_stat; maj_stat = gss_release_cred(&min_stat, &gcc->creds); return 0;}_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, struct event_context *event_ctx, struct loadparm_context *lp_ctx, struct gssapi_creds_container **_gcc)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -