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/schannel.h"
29 #include "../librpc/gen_ndr/ndr_schannel.h"
30 #include "lib/util/tdb_wrap.h"
32 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
34 /******************************************************************************
35 Open or create the schannel session store tdb. Non-static so it can
36 be called from parent processes to corectly handle TDB_CLEAR_IF_FIRST
37 *******************************************************************************/
39 struct tdb_wrap
*open_schannel_session_store(TALLOC_CTX
*mem_ctx
,
40 const char *private_dir
)
42 struct tdb_wrap
*tdb_sc
= NULL
;
43 char *fname
= talloc_asprintf(mem_ctx
, "%s/schannel_store.tdb", private_dir
);
49 tdb_sc
= tdb_wrap_open(mem_ctx
, fname
, 0, TDB_CLEAR_IF_FIRST
|TDB_NOSYNC
, O_RDWR
|O_CREAT
, 0600);
52 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
53 fname
, strerror(errno
)));
63 /********************************************************************
64 ********************************************************************/
67 NTSTATUS
schannel_store_session_key_tdb(struct tdb_wrap
*tdb_sc
,
69 struct netlogon_creds_CredentialState
*creds
)
71 enum ndr_err_code ndr_err
;
78 name_upper
= strupper_talloc(mem_ctx
, creds
->computer_name
);
80 return NT_STATUS_NO_MEMORY
;
83 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
84 SECRETS_SCHANNEL_STATE
, name_upper
);
85 TALLOC_FREE(name_upper
);
87 return NT_STATUS_NO_MEMORY
;
90 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, creds
,
91 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
92 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
94 return ndr_map_error2ntstatus(ndr_err
);
97 value
.dptr
= blob
.data
;
98 value
.dsize
= blob
.length
;
100 ret
= tdb_store_bystring(tdb_sc
->tdb
, keystr
, value
, TDB_REPLACE
);
101 if (ret
!= TDB_SUCCESS
) {
102 DEBUG(0,("Unable to add %s to session key db - %s\n",
103 keystr
, tdb_errorstr(tdb_sc
->tdb
)));
105 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
108 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
111 if (DEBUGLEVEL
>= 10) {
112 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
120 /********************************************************************
121 ********************************************************************/
124 NTSTATUS
schannel_fetch_session_key_tdb(struct tdb_wrap
*tdb_sc
,
126 const char *computer_name
,
127 struct netlogon_creds_CredentialState
**pcreds
)
131 enum ndr_err_code ndr_err
;
133 struct netlogon_creds_CredentialState
*creds
= NULL
;
139 name_upper
= strupper_talloc(mem_ctx
, computer_name
);
141 return NT_STATUS_NO_MEMORY
;
144 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
145 SECRETS_SCHANNEL_STATE
, name_upper
);
146 TALLOC_FREE(name_upper
);
148 return NT_STATUS_NO_MEMORY
;
151 value
= tdb_fetch_bystring(tdb_sc
->tdb
, keystr
);
153 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
155 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
159 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
161 status
= NT_STATUS_NO_MEMORY
;
165 blob
= data_blob_const(value
.dptr
, value
.dsize
);
167 ndr_err
= ndr_pull_struct_blob(&blob
, creds
, creds
,
168 (ndr_pull_flags_fn_t
)ndr_pull_netlogon_creds_CredentialState
);
169 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
170 status
= ndr_map_error2ntstatus(ndr_err
);
174 if (DEBUGLEVEL
>= 10) {
175 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
178 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
181 status
= NT_STATUS_OK
;
186 SAFE_FREE(value
.dptr
);
188 if (!NT_STATUS_IS_OK(status
)) {
198 /******************************************************************************
199 Wrapper around schannel_fetch_session_key_tdb()
200 Note we must be root here.
201 *******************************************************************************/
203 NTSTATUS
schannel_get_creds_state(TALLOC_CTX
*mem_ctx
,
204 const char *db_priv_dir
,
205 const char *computer_name
,
206 struct netlogon_creds_CredentialState
**_creds
)
209 struct tdb_wrap
*tdb_sc
;
210 struct netlogon_creds_CredentialState
*creds
;
213 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_get_creds_state");
215 return NT_STATUS_NO_MEMORY
;
218 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
220 return NT_STATUS_ACCESS_DENIED
;
223 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
,
224 computer_name
, &creds
);
225 if (NT_STATUS_IS_OK(status
)) {
226 *_creds
= talloc_steal(mem_ctx
, creds
);
228 status
= NT_STATUS_NO_MEMORY
;
236 /******************************************************************************
237 Wrapper around schannel_store_session_key_tdb()
238 Note we must be root here.
239 *******************************************************************************/
241 NTSTATUS
schannel_save_creds_state(TALLOC_CTX
*mem_ctx
,
242 const char *db_priv_dir
,
243 struct netlogon_creds_CredentialState
*creds
)
246 struct tdb_wrap
*tdb_sc
;
249 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_save_creds_state");
251 return NT_STATUS_NO_MEMORY
;
254 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
256 return NT_STATUS_ACCESS_DENIED
;
259 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, 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 *db_priv_dir
,
277 const char *computer_name
,
278 struct netr_Authenticator
*received_authenticator
,
279 struct netr_Authenticator
*return_authenticator
,
280 struct netlogon_creds_CredentialState
**creds_out
)
283 struct tdb_wrap
*tdb_sc
;
284 struct netlogon_creds_CredentialState
*creds
;
288 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_check_creds_state");
290 return NT_STATUS_NO_MEMORY
;
293 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
295 status
= NT_STATUS_ACCESS_DENIED
;
299 ret
= tdb_transaction_start(tdb_sc
->tdb
);
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_sc
, tmpctx
,
310 computer_name
, &creds
);
311 if (!NT_STATUS_IS_OK(status
)) {
312 tdb_transaction_cancel(tdb_sc
->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_sc
->tdb
);
324 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, creds
);
325 if (!NT_STATUS_IS_OK(status
)) {
326 tdb_transaction_cancel(tdb_sc
->tdb
);
330 tdb_transaction_commit(tdb_sc
->tdb
);
333 *creds_out
= talloc_steal(mem_ctx
, creds
);
335 status
= NT_STATUS_NO_MEMORY
;
340 status
= NT_STATUS_OK
;