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"
26 #include "../lib/tdb/include/tdb.h"
27 #include "../lib/util/util_tdb.h"
28 #include "../lib/param/param.h"
29 #include "../libcli/auth/schannel.h"
30 #include "../librpc/gen_ndr/ndr_schannel.h"
31 #include "lib/dbwrap/dbwrap.h"
33 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
35 /******************************************************************************
36 Open or create the schannel session store tdb. Non-static so it can
37 be called from parent processes to corectly handle TDB_CLEAR_IF_FIRST
38 *******************************************************************************/
40 struct db_context *open_schannel_session_store(TALLOC_CTX *mem_ctx,
41 struct loadparm_context *lp_ctx)
43 struct db_context *db_sc = NULL;
44 char *fname = lpcfg_private_db_path(mem_ctx, lp_ctx, "schannel_store");
50 db_sc = dbwrap_local_open(mem_ctx, lp_ctx, fname, 0,
51 TDB_CLEAR_IF_FIRST|TDB_NOSYNC, O_RDWR|O_CREAT,
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 db_context *db_sc,
72 struct netlogon_creds_CredentialState *creds)
74 enum ndr_err_code ndr_err;
81 if (strlen(creds->computer_name) > 15) {
83 * We may want to check for a completely
86 return STATUS_BUFFER_OVERFLOW;
89 name_upper = strupper_talloc(mem_ctx, creds->computer_name);
91 return NT_STATUS_NO_MEMORY;
94 keystr = talloc_asprintf(mem_ctx, "%s/%s",
95 SECRETS_SCHANNEL_STATE, name_upper);
96 TALLOC_FREE(name_upper);
98 return NT_STATUS_NO_MEMORY;
101 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
102 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
103 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
105 return ndr_map_error2ntstatus(ndr_err);
108 value.dptr = blob.data;
109 value.dsize = blob.length;
111 status = dbwrap_store_bystring(db_sc, keystr, value, TDB_REPLACE);
112 if (!NT_STATUS_IS_OK(status)) {
113 DEBUG(0,("Unable to add %s to session key db - %s\n",
114 keystr, nt_errstr(status)));
119 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
122 if (DEBUGLEVEL >= 10) {
123 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
131 /********************************************************************
132 ********************************************************************/
135 NTSTATUS schannel_fetch_session_key_tdb(struct db_context *db_sc,
137 const char *computer_name,
138 struct netlogon_creds_CredentialState **pcreds)
142 enum ndr_err_code ndr_err;
144 struct netlogon_creds_CredentialState *creds = NULL;
150 name_upper = strupper_talloc(mem_ctx, computer_name);
152 return NT_STATUS_NO_MEMORY;
155 keystr = talloc_asprintf(mem_ctx, "%s/%s",
156 SECRETS_SCHANNEL_STATE, name_upper);
157 TALLOC_FREE(name_upper);
159 return NT_STATUS_NO_MEMORY;
162 status = dbwrap_fetch_bystring(db_sc, keystr, keystr, &value);
163 if (!NT_STATUS_IS_OK(status)) {
164 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
169 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
171 status = NT_STATUS_NO_MEMORY;
175 blob = data_blob_const(value.dptr, value.dsize);
177 ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
178 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
179 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
180 status = ndr_map_error2ntstatus(ndr_err);
184 if (DEBUGLEVEL >= 10) {
185 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
188 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
191 status = NT_STATUS_OK;
197 if (!NT_STATUS_IS_OK(status)) {
207 /******************************************************************************
208 Wrapper around schannel_fetch_session_key_tdb()
209 Note we must be root here.
210 *******************************************************************************/
212 NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
213 struct loadparm_context *lp_ctx,
214 const char *computer_name,
215 struct netlogon_creds_CredentialState **_creds)
218 struct db_context *db_sc;
219 struct netlogon_creds_CredentialState *creds;
222 tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
224 return NT_STATUS_NO_MEMORY;
227 db_sc = open_schannel_session_store(tmpctx, lp_ctx);
229 return NT_STATUS_ACCESS_DENIED;
232 status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
233 computer_name, &creds);
234 if (NT_STATUS_IS_OK(status)) {
235 *_creds = talloc_steal(mem_ctx, creds);
237 status = NT_STATUS_NO_MEMORY;
245 /******************************************************************************
246 Wrapper around schannel_store_session_key_tdb()
247 Note we must be root here.
248 *******************************************************************************/
250 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
251 struct loadparm_context *lp_ctx,
252 struct netlogon_creds_CredentialState *creds)
255 struct db_context *db_sc;
258 tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
260 return NT_STATUS_NO_MEMORY;
263 db_sc = open_schannel_session_store(tmpctx, lp_ctx);
265 return NT_STATUS_ACCESS_DENIED;
268 status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
274 /********************************************************************
275 Validate an incoming authenticator against the credentials for the
276 remote machine stored in the schannel database.
278 The credentials are (re)read and from the schannel database, and
279 written back after the caclulations are performed.
281 If the creds_out parameter is not NULL returns the credentials.
282 ********************************************************************/
284 NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
285 struct loadparm_context *lp_ctx,
286 const char *computer_name,
287 struct netr_Authenticator *received_authenticator,
288 struct netr_Authenticator *return_authenticator,
289 struct netlogon_creds_CredentialState **creds_out)
292 struct db_context *db_sc;
293 struct netlogon_creds_CredentialState *creds;
295 char *name_upper = NULL;
297 struct db_record *record;
300 if (creds_out != NULL) {
304 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
306 return NT_STATUS_NO_MEMORY;
309 name_upper = strupper_talloc(tmpctx, computer_name);
311 status = NT_STATUS_NO_MEMORY;
315 keystr = talloc_asprintf(tmpctx, "%s/%s",
316 SECRETS_SCHANNEL_STATE, name_upper);
318 status = NT_STATUS_NO_MEMORY;
322 key = string_term_tdb_data(keystr);
324 db_sc = open_schannel_session_store(tmpctx, lp_ctx);
326 status = NT_STATUS_ACCESS_DENIED;
330 record = dbwrap_fetch_locked(db_sc, tmpctx, key);
332 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
336 /* Because this is a shared structure (even across
337 * disconnects) we must update the database every time we
338 * update the structure */
340 status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
341 computer_name, &creds);
342 if (!NT_STATUS_IS_OK(status)) {
346 status = netlogon_creds_server_step_check(creds,
347 received_authenticator,
348 return_authenticator);
349 if (!NT_STATUS_IS_OK(status)) {
353 status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
354 if (!NT_STATUS_IS_OK(status)) {
359 *creds_out = talloc_steal(mem_ctx, creds);
361 status = NT_STATUS_NO_MEMORY;
366 status = NT_STATUS_OK;