summaryrefslogtreecommitdiff
path: root/libcli/auth/schannel_state_tdb.c
diff options
context:
space:
mode:
authorGünther Deschner <gd@samba.org>2009-08-25 21:16:27 +0200
committerGünther Deschner <gd@samba.org>2009-08-27 15:55:19 +0200
commit04310cc1c510025c8d5dc10d744ab9825eae3fee (patch)
tree86ba78c98c216d7553c23af9ebb74f862e76e4ed /libcli/auth/schannel_state_tdb.c
parent699266920b23fd9ea6079d8ae8e4682bb5141f0d (diff)
downloadsamba-04310cc1c510025c8d5dc10d744ab9825eae3fee.tar.gz
samba-04310cc1c510025c8d5dc10d744ab9825eae3fee.tar.bz2
samba-04310cc1c510025c8d5dc10d744ab9825eae3fee.zip
libcli/auth: add tdb backend for schannel state.
Guenther
Diffstat (limited to 'libcli/auth/schannel_state_tdb.c')
-rw-r--r--libcli/auth/schannel_state_tdb.c222
1 files changed, 222 insertions, 0 deletions
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;
+}