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 netlogon_creds_CredentialState
*creds
)
108 enum ndr_err_code ndr_err
;
115 name_upper
= strupper_talloc(mem_ctx
, creds
->computer_name
);
117 return NT_STATUS_NO_MEMORY
;
120 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
121 SECRETS_SCHANNEL_STATE
, name_upper
);
122 TALLOC_FREE(name_upper
);
124 return NT_STATUS_NO_MEMORY
;
127 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, creds
,
128 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
129 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
131 return ndr_map_error2ntstatus(ndr_err
);
134 value
.dptr
= blob
.data
;
135 value
.dsize
= blob
.length
;
137 ret
= tdb_store_bystring(tdb_sc
->tdb
, keystr
, value
, TDB_REPLACE
);
138 if (ret
!= TDB_SUCCESS
) {
139 DEBUG(0,("Unable to add %s to session key db - %s\n",
140 keystr
, tdb_errorstr(tdb_sc
->tdb
)));
142 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
145 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
148 if (DEBUGLEVEL
>= 10) {
149 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
157 /********************************************************************
158 ********************************************************************/
161 NTSTATUS
schannel_fetch_session_key_tdb(struct tdb_wrap
*tdb_sc
,
163 const char *computer_name
,
164 struct netlogon_creds_CredentialState
**pcreds
)
168 enum ndr_err_code ndr_err
;
170 struct netlogon_creds_CredentialState
*creds
= NULL
;
176 name_upper
= strupper_talloc(mem_ctx
, computer_name
);
178 return NT_STATUS_NO_MEMORY
;
181 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
182 SECRETS_SCHANNEL_STATE
, name_upper
);
183 TALLOC_FREE(name_upper
);
185 return NT_STATUS_NO_MEMORY
;
188 value
= tdb_fetch_bystring(tdb_sc
->tdb
, keystr
);
190 DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
192 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
196 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
198 status
= NT_STATUS_NO_MEMORY
;
202 blob
= data_blob_const(value
.dptr
, value
.dsize
);
204 ndr_err
= ndr_pull_struct_blob(&blob
, creds
, creds
,
205 (ndr_pull_flags_fn_t
)ndr_pull_netlogon_creds_CredentialState
);
206 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
207 status
= ndr_map_error2ntstatus(ndr_err
);
211 if (DEBUGLEVEL
>= 10) {
212 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
215 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
218 status
= NT_STATUS_OK
;
223 SAFE_FREE(value
.dptr
);
225 if (!NT_STATUS_IS_OK(status
)) {
235 /******************************************************************************
236 Wrapper around schannel_fetch_session_key_tdb()
237 Note we must be root here.
238 *******************************************************************************/
240 NTSTATUS
schannel_get_creds_state(TALLOC_CTX
*mem_ctx
,
241 const char *db_priv_dir
,
242 const char *computer_name
,
243 struct netlogon_creds_CredentialState
**_creds
)
246 struct tdb_wrap
*tdb_sc
;
247 struct netlogon_creds_CredentialState
*creds
;
250 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_get_creds_state");
252 return NT_STATUS_NO_MEMORY
;
255 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
257 return NT_STATUS_ACCESS_DENIED
;
260 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
,
261 computer_name
, &creds
);
262 if (NT_STATUS_IS_OK(status
)) {
263 *_creds
= talloc_steal(mem_ctx
, creds
);
265 status
= NT_STATUS_NO_MEMORY
;
273 /******************************************************************************
274 Wrapper around schannel_store_session_key_tdb()
275 Note we must be root here.
276 *******************************************************************************/
278 NTSTATUS
schannel_save_creds_state(TALLOC_CTX
*mem_ctx
,
279 const char *db_priv_dir
,
280 struct netlogon_creds_CredentialState
*creds
)
283 struct tdb_wrap
*tdb_sc
;
286 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_save_creds_state");
288 return NT_STATUS_NO_MEMORY
;
291 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
293 return NT_STATUS_ACCESS_DENIED
;
296 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, creds
);
302 /********************************************************************
303 Validate an incoming authenticator against the credentials for the
304 remote machine stored in the schannel database.
306 The credentials are (re)read and from the schannel database, and
307 written back after the caclulations are performed.
309 If the creds_out parameter is not NULL returns the credentials.
310 ********************************************************************/
312 NTSTATUS
schannel_check_creds_state(TALLOC_CTX
*mem_ctx
,
313 const char *db_priv_dir
,
314 const char *computer_name
,
315 struct netr_Authenticator
*received_authenticator
,
316 struct netr_Authenticator
*return_authenticator
,
317 struct netlogon_creds_CredentialState
**creds_out
)
320 struct tdb_wrap
*tdb_sc
;
321 struct netlogon_creds_CredentialState
*creds
;
325 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_check_creds_state");
327 return NT_STATUS_NO_MEMORY
;
330 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
332 status
= NT_STATUS_ACCESS_DENIED
;
336 ret
= tdb_transaction_start(tdb_sc
->tdb
);
338 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
342 /* Because this is a shared structure (even across
343 * disconnects) we must update the database every time we
344 * update the structure */
346 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
,
347 computer_name
, &creds
);
348 if (!NT_STATUS_IS_OK(status
)) {
349 tdb_transaction_cancel(tdb_sc
->tdb
);
353 status
= netlogon_creds_server_step_check(creds
,
354 received_authenticator
,
355 return_authenticator
);
356 if (!NT_STATUS_IS_OK(status
)) {
357 tdb_transaction_cancel(tdb_sc
->tdb
);
361 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, creds
);
362 if (!NT_STATUS_IS_OK(status
)) {
363 tdb_transaction_cancel(tdb_sc
->tdb
);
367 tdb_transaction_commit(tdb_sc
->tdb
);
370 *creds_out
= talloc_steal(mem_ctx
, creds
);
372 status
= NT_STATUS_NO_MEMORY
;
377 status
= NT_STATUS_OK
;