diff options
-rw-r--r-- | libcli/auth/schannel_state.h | 1 | ||||
-rw-r--r-- | libcli/auth/schannel_state_proto.h | 16 | ||||
-rw-r--r-- | libcli/auth/schannel_state_tdb.c | 222 | ||||
-rw-r--r-- | source3/Makefile.in | 4 |
4 files changed, 242 insertions, 1 deletions
diff --git a/libcli/auth/schannel_state.h b/libcli/auth/schannel_state.h index 048baa90d2..e60f4d9891 100644 --- a/libcli/auth/schannel_state.h +++ b/libcli/auth/schannel_state.h @@ -21,4 +21,5 @@ */ struct ldb_context; +struct tdb_context; #include "libcli/auth/schannel_state_proto.h" diff --git a/libcli/auth/schannel_state_proto.h b/libcli/auth/schannel_state_proto.h index 042e1dd940..c582c3e8b8 100644 --- a/libcli/auth/schannel_state_proto.h +++ b/libcli/auth/schannel_state_proto.h @@ -26,6 +26,22 @@ NTSTATUS schannel_creds_server_step_check_ldb(struct ldb_context *ldb, struct netr_Authenticator *received_authenticator, struct netr_Authenticator *return_authenticator, struct netlogon_creds_CredentialState **creds_out); +NTSTATUS schannel_store_session_key_tdb(struct tdb_context *tdb, + TALLOC_CTX *mem_ctx, + struct netlogon_creds_CredentialState *creds); +NTSTATUS schannel_fetch_session_key_tdb(struct tdb_context *tdb, + TALLOC_CTX *mem_ctx, + const char *computer_name, + struct netlogon_creds_CredentialState **creds); +NTSTATUS schannel_creds_server_step_check_tdb(struct tdb_context *tdb, + TALLOC_CTX *mem_ctx, + const char *computer_name, + bool schannel_required_for_call, + bool schannel_in_use, + struct netr_Authenticator *received_authenticator, + struct netr_Authenticator *return_authenticator, + struct netlogon_creds_CredentialState **creds_out); + #undef _PRINTF_ATTRIBUTE #define _PRINTF_ATTRIBUTE(a1, a2) diff --git a/libcli/auth/schannel_state_tdb.c b/libcli/auth/schannel_state_tdb.c new file mode 100644 index 0000000000..7ec8b3fdea --- /dev/null +++ b/libcli/auth/schannel_state_tdb.c @@ -0,0 +1,222 @@ +/* + Unix SMB/CIFS implementation. + + module to store/fetch session keys for the schannel server + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2009 + Copyright (C) Guenther Deschner 2009 + + 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 "../libcli/auth/libcli_auth.h" +#include "../libcli/auth/schannel_state.h" +#include "../librpc/gen_ndr/ndr_schannel.h" + +/******************************************************************** + ********************************************************************/ + +NTSTATUS schannel_store_session_key_tdb(struct tdb_context *tdb, + TALLOC_CTX *mem_ctx, + struct netlogon_creds_CredentialState *creds) +{ + enum ndr_err_code ndr_err; + DATA_BLOB blob; + TDB_DATA value; + int ret; + char *keystr; + + keystr = talloc_asprintf_strupper_m(mem_ctx, "%s/%s", + SECRETS_SCHANNEL_STATE, + creds->computer_name); + if (!keystr) { + return NT_STATUS_NO_MEMORY; + } + + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, creds, + (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(keystr); + return ndr_map_error2ntstatus(ndr_err); + } + + value.dptr = blob.data; + value.dsize = blob.length; + + ret = tdb_store_bystring(tdb, keystr, value, TDB_REPLACE); + if (ret != TDB_SUCCESS) { + DEBUG(0,("Unable to add %s to session key db - %s\n", + keystr, tdb_errorstr(tdb))); + talloc_free(keystr); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n", + keystr)); + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds); + } + + talloc_free(keystr); + + return NT_STATUS_OK; +} + +/******************************************************************** + ********************************************************************/ + +NTSTATUS schannel_fetch_session_key_tdb(struct tdb_context *tdb, + TALLOC_CTX *mem_ctx, + const char *computer_name, + struct netlogon_creds_CredentialState **pcreds) +{ + NTSTATUS status; + TDB_DATA value; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + struct netlogon_creds_CredentialState *creds = NULL; + char *keystr = NULL; + + *pcreds = NULL; + + keystr = talloc_asprintf_strupper_m(mem_ctx, "%s/%s", + SECRETS_SCHANNEL_STATE, + computer_name); + if (!keystr) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + value = tdb_fetch_bystring(tdb, keystr); + if (!value.dptr) { + DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n", + keystr )); + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto done; + } + + creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState); + if (!creds) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + blob = data_blob_const(value.dptr, value.dsize); + + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, creds, + (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = ndr_map_error2ntstatus(ndr_err); + goto done; + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds); + } + + DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n", + keystr)); + + status = NT_STATUS_OK; + + done: + + talloc_free(keystr); + + if (!NT_STATUS_IS_OK(status)) { + talloc_free(creds); + return status; + } + + *pcreds = creds; + + return NT_STATUS_OK; +} + +/******************************************************************** + + Validate an incoming authenticator against the credentials for the remote + machine. + + The credentials are (re)read and from the schannel database, and + written back after the caclulations are performed. + + The creds_out parameter (if not NULL) returns the credentials, if + the caller needs some of that information. + + ********************************************************************/ + +NTSTATUS schannel_creds_server_step_check_tdb(struct tdb_context *tdb, + TALLOC_CTX *mem_ctx, + const char *computer_name, + bool schannel_required_for_call, + bool schannel_in_use, + struct netr_Authenticator *received_authenticator, + struct netr_Authenticator *return_authenticator, + struct netlogon_creds_CredentialState **creds_out) +{ + struct netlogon_creds_CredentialState *creds; + NTSTATUS status; + int ret; + + ret = tdb_transaction_start(tdb); + if (ret != 0) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + /* Because this is a shared structure (even across + * disconnects) we must update the database every time we + * update the structure */ + + status = schannel_fetch_session_key_tdb(tdb, mem_ctx, computer_name, + &creds); + + /* If we are flaged that schannel is required for a call, and + * it is not in use, then make this an error */ + + /* It would be good to make this mandatory once schannel is + * negotiated, but this is not what windows does */ + if (schannel_required_for_call && !schannel_in_use) { + DEBUG(0,("schannel_creds_server_step_check_tdb: " + "client %s not using schannel for netlogon, despite negotiating it\n", + creds->computer_name )); + tdb_transaction_cancel(tdb); + return NT_STATUS_ACCESS_DENIED; + } + + if (NT_STATUS_IS_OK(status)) { + status = netlogon_creds_server_step_check(creds, + received_authenticator, + return_authenticator); + } + + if (NT_STATUS_IS_OK(status)) { + status = schannel_store_session_key_tdb(tdb, mem_ctx, creds); + } + + if (NT_STATUS_IS_OK(status)) { + tdb_transaction_commit(tdb); + if (creds_out) { + *creds_out = creds; + talloc_steal(mem_ctx, creds); + } + } else { + tdb_transaction_cancel(tdb); + } + + return status; +} diff --git a/source3/Makefile.in b/source3/Makefile.in index fe96fe4fa6..765250595d 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -490,7 +490,9 @@ CLDAP_OBJ = libads/cldap.o \ TLDAP_OBJ = lib/tldap.o lib/tldap_util.o lib/util_tsock.o SCHANNEL_OBJ = libsmb/credentials.o \ - ../libcli/auth/credentials.o + ../libcli/auth/credentials.o \ + ../libcli/auth/schannel_state_tdb.o \ + ../librpc/gen_ndr/ndr_schannel.o LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \ libsmb/clikrb5.o libsmb/clispnego.o ../lib/util/asn1.o \ |