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.
39 *******************************************************************************/
41 #define SCHANNEL_STORE_VERSION_1 1
42 #define SCHANNEL_STORE_VERSION_2 2 /* should not be used */
43 #define SCHANNEL_STORE_VERSION_CURRENT SCHANNEL_STORE_VERSION_1
45 static struct tdb_wrap *open_schannel_session_store(TALLOC_CTX *mem_ctx,
46 const char *private_dir)
50 struct tdb_wrap *tdb_sc = NULL;
51 char *fname = talloc_asprintf(mem_ctx, "%s/schannel_store.tdb", private_dir);
57 tdb_sc = tdb_wrap_open(mem_ctx, fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
60 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
61 fname, strerror(errno)));
67 vers = tdb_fetch_bystring(tdb_sc->tdb, "SCHANNEL_STORE_VERSION");
68 if (vers.dptr == NULL) {
69 /* First opener, no version. */
70 SIVAL(&ver,0,SCHANNEL_STORE_VERSION_CURRENT);
71 vers.dptr = (uint8_t *)&ver;
73 tdb_store_bystring(tdb_sc->tdb, "SCHANNEL_STORE_VERSION", vers, TDB_REPLACE);
75 } else if (vers.dsize == 4) {
76 ver = IVAL(vers.dptr,0);
77 if (ver == SCHANNEL_STORE_VERSION_2) {
78 DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n",
80 tdb_wipe_all(tdb_sc->tdb);
83 if (ver != SCHANNEL_STORE_VERSION_CURRENT) {
84 DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n",
90 DEBUG(0,("open_schannel_session_store: wrong version number size %d in %s\n",
91 (int)vers.dsize, fname ));
100 /********************************************************************
101 ********************************************************************/
104 NTSTATUS schannel_store_session_key_tdb(struct tdb_wrap *tdb_sc,
106 struct smb_iconv_convenience *ic,
107 struct netlogon_creds_CredentialState *creds)
109 enum ndr_err_code ndr_err;
116 name_upper = strupper_talloc(mem_ctx, creds->computer_name);
118 return NT_STATUS_NO_MEMORY;
121 keystr = talloc_asprintf(mem_ctx, "%s/%s",
122 SECRETS_SCHANNEL_STATE, name_upper);
123 TALLOC_FREE(name_upper);
125 return NT_STATUS_NO_MEMORY;
128 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, ic, creds,
129 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
130 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
132 return ndr_map_error2ntstatus(ndr_err);
135 value.dptr = blob.data;
136 value.dsize = blob.length;
138 ret = tdb_store_bystring(tdb_sc->tdb, keystr, value, TDB_REPLACE);
139 if (ret != TDB_SUCCESS) {
140 DEBUG(0,("Unable to add %s to session key db - %s\n",
141 keystr, tdb_errorstr(tdb_sc->tdb)));
143 return NT_STATUS_INTERNAL_DB_CORRUPTION;
146 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
149 if (DEBUGLEVEL >= 10) {
150 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
158 /********************************************************************
159 ********************************************************************/
162 NTSTATUS schannel_fetch_session_key_tdb(struct tdb_wrap *tdb_sc,
164 struct smb_iconv_convenience *ic,
165 const char *computer_name,
166 struct netlogon_creds_CredentialState **pcreds)
170 enum ndr_err_code ndr_err;
172 struct netlogon_creds_CredentialState *creds = NULL;
178 name_upper = strupper_talloc(mem_ctx, computer_name);
180 return NT_STATUS_NO_MEMORY;
183 keystr = talloc_asprintf(mem_ctx, "%s/%s",
184 SECRETS_SCHANNEL_STATE, name_upper);
185 TALLOC_FREE(name_upper);
187 status = NT_STATUS_NO_MEMORY;
191 value = tdb_fetch_bystring(tdb_sc->tdb, keystr);
193 DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
195 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
199 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
201 status = NT_STATUS_NO_MEMORY;
205 blob = data_blob_const(value.dptr, value.dsize);
207 ndr_err = ndr_pull_struct_blob(&blob, creds, ic, creds,
208 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
209 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
210 status = ndr_map_error2ntstatus(ndr_err);
214 if (DEBUGLEVEL >= 10) {
215 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
218 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
221 status = NT_STATUS_OK;
227 if (!NT_STATUS_IS_OK(status)) {
237 /******************************************************************************
238 Wrapper around schannel_fetch_session_key_tdb()
239 Note we must be root here.
240 *******************************************************************************/
242 NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
243 struct smb_iconv_convenience *ic,
244 const char *db_priv_dir,
245 const char *computer_name,
246 struct netlogon_creds_CredentialState **_creds)
249 struct tdb_wrap *tdb_sc;
250 struct netlogon_creds_CredentialState *creds;
253 tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
255 return NT_STATUS_NO_MEMORY;
258 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
260 return NT_STATUS_ACCESS_DENIED;
263 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx, ic,
264 computer_name, &creds);
265 if (NT_STATUS_IS_OK(status)) {
266 *_creds = talloc_steal(mem_ctx, creds);
268 status = NT_STATUS_NO_MEMORY;
276 /******************************************************************************
277 Wrapper around schannel_store_session_key_tdb()
278 Note we must be root here.
279 *******************************************************************************/
281 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
282 struct smb_iconv_convenience *ic,
283 const char *db_priv_dir,
284 struct netlogon_creds_CredentialState *creds)
287 struct tdb_wrap *tdb_sc;
290 tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
292 return NT_STATUS_NO_MEMORY;
295 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
297 return NT_STATUS_ACCESS_DENIED;
300 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, ic, creds);
306 /********************************************************************
307 Validate an incoming authenticator against the credentials for the
308 remote machine stored in the schannel database.
310 The credentials are (re)read and from the schannel database, and
311 written back after the caclulations are performed.
313 If the creds_out parameter is not NULL returns the credentials.
314 ********************************************************************/
316 NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
317 struct smb_iconv_convenience *ic,
318 const char *db_priv_dir,
319 const char *computer_name,
320 struct netr_Authenticator *received_authenticator,
321 struct netr_Authenticator *return_authenticator,
322 struct netlogon_creds_CredentialState **creds_out)
325 struct tdb_wrap *tdb_sc;
326 struct netlogon_creds_CredentialState *creds;
330 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
332 return NT_STATUS_NO_MEMORY;
335 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
337 status = NT_STATUS_ACCESS_DENIED;
341 ret = tdb_transaction_start(tdb_sc->tdb);
343 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
347 /* Because this is a shared structure (even across
348 * disconnects) we must update the database every time we
349 * update the structure */
351 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx, ic,
352 computer_name, &creds);
353 if (!NT_STATUS_IS_OK(status)) {
354 tdb_transaction_cancel(tdb_sc->tdb);
358 status = netlogon_creds_server_step_check(creds,
359 received_authenticator,
360 return_authenticator);
361 if (!NT_STATUS_IS_OK(status)) {
362 tdb_transaction_cancel(tdb_sc->tdb);
366 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, ic, creds);
367 if (!NT_STATUS_IS_OK(status)) {
368 tdb_transaction_cancel(tdb_sc->tdb);
372 tdb_transaction_commit(tdb_sc->tdb);
375 *creds_out = talloc_steal(mem_ctx, creds);
377 status = NT_STATUS_NO_MEMORY;
382 status = NT_STATUS_OK;