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 #if _SAMBA_BUILD_ == 4
34 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
36 /******************************************************************************
37 Open or create the schannel session store tdb. Non-static so it can
38 be called from parent processes to corectly handle TDB_CLEAR_IF_FIRST
39 *******************************************************************************/
41 struct tdb_wrap
*open_schannel_session_store(TALLOC_CTX
*mem_ctx
,
42 const char *private_dir
)
44 struct tdb_wrap
*tdb_sc
= NULL
;
45 char *fname
= talloc_asprintf(mem_ctx
, "%s/schannel_store.tdb", private_dir
);
51 tdb_sc
= tdb_wrap_open(mem_ctx
, fname
, 0, TDB_CLEAR_IF_FIRST
|TDB_NOSYNC
, O_RDWR
|O_CREAT
, 0600);
54 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
55 fname
, strerror(errno
)));
65 /********************************************************************
66 ********************************************************************/
69 NTSTATUS
schannel_store_session_key_tdb(struct tdb_wrap
*tdb_sc
,
71 struct netlogon_creds_CredentialState
*creds
)
73 enum ndr_err_code ndr_err
;
80 name_upper
= strupper_talloc(mem_ctx
, creds
->computer_name
);
82 return NT_STATUS_NO_MEMORY
;
85 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
86 SECRETS_SCHANNEL_STATE
, name_upper
);
87 TALLOC_FREE(name_upper
);
89 return NT_STATUS_NO_MEMORY
;
92 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, creds
,
93 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
94 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
96 return ndr_map_error2ntstatus(ndr_err
);
99 value
.dptr
= blob
.data
;
100 value
.dsize
= blob
.length
;
102 ret
= tdb_store_bystring(tdb_sc
->tdb
, keystr
, value
, TDB_REPLACE
);
103 if (ret
!= TDB_SUCCESS
) {
104 DEBUG(0,("Unable to add %s to session key db - %s\n",
105 keystr
, tdb_errorstr(tdb_sc
->tdb
)));
107 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
110 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
113 if (DEBUGLEVEL
>= 10) {
114 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
122 /********************************************************************
123 ********************************************************************/
126 NTSTATUS
schannel_fetch_session_key_tdb(struct tdb_wrap
*tdb_sc
,
128 const char *computer_name
,
129 struct netlogon_creds_CredentialState
**pcreds
)
133 enum ndr_err_code ndr_err
;
135 struct netlogon_creds_CredentialState
*creds
= NULL
;
141 name_upper
= strupper_talloc(mem_ctx
, computer_name
);
143 return NT_STATUS_NO_MEMORY
;
146 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
147 SECRETS_SCHANNEL_STATE
, name_upper
);
148 TALLOC_FREE(name_upper
);
150 return NT_STATUS_NO_MEMORY
;
153 value
= tdb_fetch_bystring(tdb_sc
->tdb
, keystr
);
155 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
157 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
161 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
163 status
= NT_STATUS_NO_MEMORY
;
167 blob
= data_blob_const(value
.dptr
, value
.dsize
);
169 ndr_err
= ndr_pull_struct_blob(&blob
, creds
, creds
,
170 (ndr_pull_flags_fn_t
)ndr_pull_netlogon_creds_CredentialState
);
171 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
172 status
= ndr_map_error2ntstatus(ndr_err
);
176 if (DEBUGLEVEL
>= 10) {
177 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
180 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
183 status
= NT_STATUS_OK
;
188 SAFE_FREE(value
.dptr
);
190 if (!NT_STATUS_IS_OK(status
)) {
200 /******************************************************************************
201 Wrapper around schannel_fetch_session_key_tdb()
202 Note we must be root here.
203 *******************************************************************************/
205 NTSTATUS
schannel_get_creds_state(TALLOC_CTX
*mem_ctx
,
206 const char *db_priv_dir
,
207 const char *computer_name
,
208 struct netlogon_creds_CredentialState
**_creds
)
211 struct tdb_wrap
*tdb_sc
;
212 struct netlogon_creds_CredentialState
*creds
;
215 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_get_creds_state");
217 return NT_STATUS_NO_MEMORY
;
220 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
222 return NT_STATUS_ACCESS_DENIED
;
225 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
,
226 computer_name
, &creds
);
227 if (NT_STATUS_IS_OK(status
)) {
228 *_creds
= talloc_steal(mem_ctx
, creds
);
230 status
= NT_STATUS_NO_MEMORY
;
238 /******************************************************************************
239 Wrapper around schannel_store_session_key_tdb()
240 Note we must be root here.
241 *******************************************************************************/
243 NTSTATUS
schannel_save_creds_state(TALLOC_CTX
*mem_ctx
,
244 const char *db_priv_dir
,
245 struct netlogon_creds_CredentialState
*creds
)
248 struct tdb_wrap
*tdb_sc
;
251 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_save_creds_state");
253 return NT_STATUS_NO_MEMORY
;
256 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
258 return NT_STATUS_ACCESS_DENIED
;
261 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, creds
);
267 /********************************************************************
268 Validate an incoming authenticator against the credentials for the
269 remote machine stored in the schannel database.
271 The credentials are (re)read and from the schannel database, and
272 written back after the caclulations are performed.
274 If the creds_out parameter is not NULL returns the credentials.
275 ********************************************************************/
277 NTSTATUS
schannel_check_creds_state(TALLOC_CTX
*mem_ctx
,
278 const char *db_priv_dir
,
279 const char *computer_name
,
280 struct netr_Authenticator
*received_authenticator
,
281 struct netr_Authenticator
*return_authenticator
,
282 struct netlogon_creds_CredentialState
**creds_out
)
285 struct tdb_wrap
*tdb_sc
;
286 struct netlogon_creds_CredentialState
*creds
;
290 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_check_creds_state");
292 return NT_STATUS_NO_MEMORY
;
295 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
297 status
= NT_STATUS_ACCESS_DENIED
;
301 ret
= tdb_transaction_start(tdb_sc
->tdb
);
303 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
307 /* Because this is a shared structure (even across
308 * disconnects) we must update the database every time we
309 * update the structure */
311 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
,
312 computer_name
, &creds
);
313 if (!NT_STATUS_IS_OK(status
)) {
314 tdb_transaction_cancel(tdb_sc
->tdb
);
318 status
= netlogon_creds_server_step_check(creds
,
319 received_authenticator
,
320 return_authenticator
);
321 if (!NT_STATUS_IS_OK(status
)) {
322 tdb_transaction_cancel(tdb_sc
->tdb
);
326 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, creds
);
327 if (!NT_STATUS_IS_OK(status
)) {
328 tdb_transaction_cancel(tdb_sc
->tdb
);
332 tdb_transaction_commit(tdb_sc
->tdb
);
335 *creds_out
= talloc_steal(mem_ctx
, creds
);
337 status
= NT_STATUS_NO_MEMORY
;
342 status
= NT_STATUS_OK
;