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 "../libcli/auth/libcli_auth.h"
26 #include "../libcli/auth/schannel_state.h"
27 #include "../librpc/gen_ndr/ndr_schannel.h"
29 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
31 /******************************************************************************
32 Open or create the schannel session store tdb.
33 *******************************************************************************/
35 #define SCHANNEL_STORE_VERSION_1 1
36 #define SCHANNEL_STORE_VERSION_2 2 /* should not be used */
37 #define SCHANNEL_STORE_VERSION_CURRENT SCHANNEL_STORE_VERSION_1
39 static TDB_CONTEXT *open_schannel_session_store(TALLOC_CTX *mem_ctx)
43 TDB_CONTEXT *tdb_sc = NULL;
44 char *fname = talloc_asprintf(mem_ctx, "%s/schannel_store.tdb", lp_private_dir());
50 tdb_sc = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
53 DEBUG(0,("open_schannel_session_store: Failed to open %s\n", fname));
59 vers = tdb_fetch_bystring(tdb_sc, "SCHANNEL_STORE_VERSION");
60 if (vers.dptr == NULL) {
61 /* First opener, no version. */
62 SIVAL(&ver,0,SCHANNEL_STORE_VERSION_CURRENT);
63 vers.dptr = (uint8 *)&ver;
65 tdb_store_bystring(tdb_sc, "SCHANNEL_STORE_VERSION", vers, TDB_REPLACE);
67 } else if (vers.dsize == 4) {
68 ver = IVAL(vers.dptr,0);
69 if (ver == SCHANNEL_STORE_VERSION_2) {
70 DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n",
75 if (ver != SCHANNEL_STORE_VERSION_CURRENT) {
76 DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n",
84 DEBUG(0,("open_schannel_session_store: wrong version number size %d in %s\n",
85 (int)vers.dsize, fname ));
94 /********************************************************************
95 ********************************************************************/
98 NTSTATUS schannel_store_session_key_tdb(struct tdb_context *tdb,
100 struct netlogon_creds_CredentialState *creds)
102 enum ndr_err_code ndr_err;
108 keystr = talloc_asprintf_strupper_m(mem_ctx, "%s/%s",
109 SECRETS_SCHANNEL_STATE,
110 creds->computer_name);
112 return NT_STATUS_NO_MEMORY;
115 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, creds,
116 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
117 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
119 return ndr_map_error2ntstatus(ndr_err);
122 value.dptr = blob.data;
123 value.dsize = blob.length;
125 ret = tdb_store_bystring(tdb, keystr, value, TDB_REPLACE);
126 if (ret != TDB_SUCCESS) {
127 DEBUG(0,("Unable to add %s to session key db - %s\n",
128 keystr, tdb_errorstr(tdb)));
130 return NT_STATUS_INTERNAL_DB_CORRUPTION;
133 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
136 if (DEBUGLEVEL >= 10) {
137 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
145 /********************************************************************
146 ********************************************************************/
149 NTSTATUS schannel_fetch_session_key_tdb(struct tdb_context *tdb,
151 const char *computer_name,
152 struct netlogon_creds_CredentialState **pcreds)
156 enum ndr_err_code ndr_err;
158 struct netlogon_creds_CredentialState *creds = NULL;
163 keystr = talloc_asprintf_strupper_m(mem_ctx, "%s/%s",
164 SECRETS_SCHANNEL_STATE,
167 status = NT_STATUS_NO_MEMORY;
171 value = tdb_fetch_bystring(tdb, keystr);
173 DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
175 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
179 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
181 status = NT_STATUS_NO_MEMORY;
185 blob = data_blob_const(value.dptr, value.dsize);
187 ndr_err = ndr_pull_struct_blob(&blob, creds, NULL, creds,
188 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
189 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
190 status = ndr_map_error2ntstatus(ndr_err);
194 if (DEBUGLEVEL >= 10) {
195 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
198 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
201 status = NT_STATUS_OK;
207 if (!NT_STATUS_IS_OK(status)) {
217 /******************************************************************************
218 Wrapper around schannel_fetch_session_key_tdb()
219 Note we must be root here.
220 *******************************************************************************/
222 NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
223 const char *computer_name,
224 struct netlogon_creds_CredentialState **creds)
226 struct tdb_context *tdb;
229 tdb = open_schannel_session_store(mem_ctx);
231 return NT_STATUS_ACCESS_DENIED;
234 status = schannel_fetch_session_key_tdb(tdb, mem_ctx,
235 computer_name, creds);
242 /******************************************************************************
243 Wrapper around schannel_store_session_key_tdb()
244 Note we must be root here.
245 *******************************************************************************/
247 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
248 struct netlogon_creds_CredentialState *creds)
250 struct tdb_context *tdb;
253 tdb = open_schannel_session_store(mem_ctx);
255 return NT_STATUS_ACCESS_DENIED;
258 status = schannel_store_session_key_tdb(tdb, mem_ctx, creds);
265 /********************************************************************
266 Validate an incoming authenticator against the credentials for the
267 remote machine stored in the schannel database.
269 The credentials are (re)read and from the schannel database, and
270 written back after the caclulations are performed.
272 If the creds_out parameter is not NULL returns the credentials.
273 ********************************************************************/
275 NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
276 const char *computer_name,
277 struct netr_Authenticator *received_authenticator,
278 struct netr_Authenticator *return_authenticator,
279 struct netlogon_creds_CredentialState **creds_out)
282 struct tdb_context *tdb;
283 struct netlogon_creds_CredentialState *creds;
287 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
289 return NT_STATUS_NO_MEMORY;
292 tdb = open_schannel_session_store(tmpctx);
294 status = NT_STATUS_ACCESS_DENIED;
298 ret = tdb_transaction_start(tdb);
300 return NT_STATUS_INTERNAL_DB_CORRUPTION;
301 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
305 /* Because this is a shared structure (even across
306 * disconnects) we must update the database every time we
307 * update the structure */
309 status = schannel_fetch_session_key_tdb(tdb, tmpctx,
310 computer_name, &creds);
311 if (!NT_STATUS_IS_OK(status)) {
312 tdb_transaction_cancel(tdb);
316 status = netlogon_creds_server_step_check(creds,
317 received_authenticator,
318 return_authenticator);
319 if (!NT_STATUS_IS_OK(status)) {
320 tdb_transaction_cancel(tdb);
324 status = schannel_store_session_key_tdb(tdb, tmpctx, creds);
325 if (!NT_STATUS_IS_OK(status)) {
326 tdb_transaction_cancel(tdb);
330 tdb_transaction_commit(tdb);
333 *creds_out = talloc_steal(mem_ctx, creds);
335 status = NT_STATUS_NO_MEMORY;
340 status = NT_STATUS_OK;
344 if (tdb) tdb_close(tdb);