2 Unix SMB/CIFS implementation.
4 module to store/fetch session keys for the schannel server
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2009
8 Copyright (C) Guenther Deschner 2009
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 3 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, see <http://www.gnu.org/licenses/>.
25 #include "system/filesys.h"
27 #include "../lib/util/util_tdb.h"
28 #include "../libcli/auth/libcli_auth.h"
29 #include "../libcli/auth/schannel_state.h"
30 #include "../librpc/gen_ndr/ndr_schannel.h"
31 #if _SAMBA_BUILD_ == 4
35 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
37 /******************************************************************************
38 Open or create the schannel session store tdb. Non-static so it can
39 be called from parent processes to corectly handle TDB_CLEAR_IF_FIRST
40 *******************************************************************************/
42 struct tdb_wrap *open_schannel_session_store(TALLOC_CTX *mem_ctx,
43 const char *private_dir)
45 struct tdb_wrap *tdb_sc = NULL;
46 char *fname = talloc_asprintf(mem_ctx, "%s/schannel_store.tdb", private_dir);
52 tdb_sc = tdb_wrap_open(mem_ctx, fname, 0, TDB_CLEAR_IF_FIRST|TDB_NOSYNC, O_RDWR|O_CREAT, 0600);
55 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
56 fname, strerror(errno)));
66 /********************************************************************
67 ********************************************************************/
70 NTSTATUS schannel_store_session_key_tdb(struct tdb_wrap *tdb_sc,
72 struct netlogon_creds_CredentialState *creds)
74 enum ndr_err_code ndr_err;
81 name_upper = strupper_talloc(mem_ctx, creds->computer_name);
83 return NT_STATUS_NO_MEMORY;
86 keystr = talloc_asprintf(mem_ctx, "%s/%s",
87 SECRETS_SCHANNEL_STATE, name_upper);
88 TALLOC_FREE(name_upper);
90 return NT_STATUS_NO_MEMORY;
93 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
94 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
95 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
97 return ndr_map_error2ntstatus(ndr_err);
100 value.dptr = blob.data;
101 value.dsize = blob.length;
103 ret = tdb_store_bystring(tdb_sc->tdb, keystr, value, TDB_REPLACE);
104 if (ret != TDB_SUCCESS) {
105 DEBUG(0,("Unable to add %s to session key db - %s\n",
106 keystr, tdb_errorstr(tdb_sc->tdb)));
108 return NT_STATUS_INTERNAL_DB_CORRUPTION;
111 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
114 if (DEBUGLEVEL >= 10) {
115 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
123 /********************************************************************
124 ********************************************************************/
127 NTSTATUS schannel_fetch_session_key_tdb(struct tdb_wrap *tdb_sc,
129 const char *computer_name,
130 struct netlogon_creds_CredentialState **pcreds)
134 enum ndr_err_code ndr_err;
136 struct netlogon_creds_CredentialState *creds = NULL;
142 name_upper = strupper_talloc(mem_ctx, computer_name);
144 return NT_STATUS_NO_MEMORY;
147 keystr = talloc_asprintf(mem_ctx, "%s/%s",
148 SECRETS_SCHANNEL_STATE, name_upper);
149 TALLOC_FREE(name_upper);
151 return NT_STATUS_NO_MEMORY;
154 value = tdb_fetch_bystring(tdb_sc->tdb, keystr);
156 DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
158 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
162 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
164 status = NT_STATUS_NO_MEMORY;
168 blob = data_blob_const(value.dptr, value.dsize);
170 ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
171 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
172 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
173 status = ndr_map_error2ntstatus(ndr_err);
177 if (DEBUGLEVEL >= 10) {
178 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
181 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
184 status = NT_STATUS_OK;
189 SAFE_FREE(value.dptr);
191 if (!NT_STATUS_IS_OK(status)) {
201 /******************************************************************************
202 Wrapper around schannel_fetch_session_key_tdb()
203 Note we must be root here.
204 *******************************************************************************/
206 NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
207 const char *db_priv_dir,
208 const char *computer_name,
209 struct netlogon_creds_CredentialState **_creds)
212 struct tdb_wrap *tdb_sc;
213 struct netlogon_creds_CredentialState *creds;
216 tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
218 return NT_STATUS_NO_MEMORY;
221 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
223 return NT_STATUS_ACCESS_DENIED;
226 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx,
227 computer_name, &creds);
228 if (NT_STATUS_IS_OK(status)) {
229 *_creds = talloc_steal(mem_ctx, creds);
231 status = NT_STATUS_NO_MEMORY;
239 /******************************************************************************
240 Wrapper around schannel_store_session_key_tdb()
241 Note we must be root here.
242 *******************************************************************************/
244 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
245 const char *db_priv_dir,
246 struct netlogon_creds_CredentialState *creds)
249 struct tdb_wrap *tdb_sc;
252 tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
254 return NT_STATUS_NO_MEMORY;
257 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
259 return NT_STATUS_ACCESS_DENIED;
262 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
268 /********************************************************************
269 Validate an incoming authenticator against the credentials for the
270 remote machine stored in the schannel database.
272 The credentials are (re)read and from the schannel database, and
273 written back after the caclulations are performed.
275 If the creds_out parameter is not NULL returns the credentials.
276 ********************************************************************/
278 NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
279 const char *db_priv_dir,
280 const char *computer_name,
281 struct netr_Authenticator *received_authenticator,
282 struct netr_Authenticator *return_authenticator,
283 struct netlogon_creds_CredentialState **creds_out)
286 struct tdb_wrap *tdb_sc;
287 struct netlogon_creds_CredentialState *creds;
291 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
293 return NT_STATUS_NO_MEMORY;
296 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
298 status = NT_STATUS_ACCESS_DENIED;
302 ret = tdb_transaction_start(tdb_sc->tdb);
304 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
308 /* Because this is a shared structure (even across
309 * disconnects) we must update the database every time we
310 * update the structure */
312 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx,
313 computer_name, &creds);
314 if (!NT_STATUS_IS_OK(status)) {
315 tdb_transaction_cancel(tdb_sc->tdb);
319 status = netlogon_creds_server_step_check(creds,
320 received_authenticator,
321 return_authenticator);
322 if (!NT_STATUS_IS_OK(status)) {
323 tdb_transaction_cancel(tdb_sc->tdb);
327 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
328 if (!NT_STATUS_IS_OK(status)) {
329 tdb_transaction_cancel(tdb_sc->tdb);
333 tdb_transaction_commit(tdb_sc->tdb);
336 *creds_out = talloc_steal(mem_ctx, creds);
338 status = NT_STATUS_NO_MEMORY;
343 status = NT_STATUS_OK;