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 "../libcli/auth/schannel_proto.h"
31 #include "../librpc/gen_ndr/ndr_schannel.h"
32 #if _SAMBA_BUILD_ == 4
36 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
38 /******************************************************************************
39 Open or create the schannel session store tdb. Non-static so it can
40 be called from parent processes to corectly handle TDB_CLEAR_IF_FIRST
41 *******************************************************************************/
43 struct tdb_wrap
*open_schannel_session_store(TALLOC_CTX
*mem_ctx
,
44 const char *private_dir
)
46 struct tdb_wrap
*tdb_sc
= NULL
;
47 char *fname
= talloc_asprintf(mem_ctx
, "%s/schannel_store.tdb", private_dir
);
53 tdb_sc
= tdb_wrap_open(mem_ctx
, fname
, 0, TDB_CLEAR_IF_FIRST
|TDB_NOSYNC
, O_RDWR
|O_CREAT
, 0600);
56 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
57 fname
, strerror(errno
)));
67 /********************************************************************
68 ********************************************************************/
71 NTSTATUS
schannel_store_session_key_tdb(struct tdb_wrap
*tdb_sc
,
73 struct netlogon_creds_CredentialState
*creds
)
75 enum ndr_err_code ndr_err
;
82 name_upper
= strupper_talloc(mem_ctx
, creds
->computer_name
);
84 return NT_STATUS_NO_MEMORY
;
87 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
88 SECRETS_SCHANNEL_STATE
, name_upper
);
89 TALLOC_FREE(name_upper
);
91 return NT_STATUS_NO_MEMORY
;
94 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, creds
,
95 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
96 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
98 return ndr_map_error2ntstatus(ndr_err
);
101 value
.dptr
= blob
.data
;
102 value
.dsize
= blob
.length
;
104 ret
= tdb_store_bystring(tdb_sc
->tdb
, keystr
, value
, TDB_REPLACE
);
105 if (ret
!= TDB_SUCCESS
) {
106 DEBUG(0,("Unable to add %s to session key db - %s\n",
107 keystr
, tdb_errorstr(tdb_sc
->tdb
)));
109 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
112 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
115 if (DEBUGLEVEL
>= 10) {
116 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
124 /********************************************************************
125 ********************************************************************/
128 NTSTATUS
schannel_fetch_session_key_tdb(struct tdb_wrap
*tdb_sc
,
130 const char *computer_name
,
131 struct netlogon_creds_CredentialState
**pcreds
)
135 enum ndr_err_code ndr_err
;
137 struct netlogon_creds_CredentialState
*creds
= NULL
;
143 name_upper
= strupper_talloc(mem_ctx
, computer_name
);
145 return NT_STATUS_NO_MEMORY
;
148 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
149 SECRETS_SCHANNEL_STATE
, name_upper
);
150 TALLOC_FREE(name_upper
);
152 return NT_STATUS_NO_MEMORY
;
155 value
= tdb_fetch_bystring(tdb_sc
->tdb
, keystr
);
157 DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
159 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
163 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
165 status
= NT_STATUS_NO_MEMORY
;
169 blob
= data_blob_const(value
.dptr
, value
.dsize
);
171 ndr_err
= ndr_pull_struct_blob(&blob
, creds
, creds
,
172 (ndr_pull_flags_fn_t
)ndr_pull_netlogon_creds_CredentialState
);
173 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
174 status
= ndr_map_error2ntstatus(ndr_err
);
178 if (DEBUGLEVEL
>= 10) {
179 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
182 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
185 status
= NT_STATUS_OK
;
190 SAFE_FREE(value
.dptr
);
192 if (!NT_STATUS_IS_OK(status
)) {
202 /******************************************************************************
203 Wrapper around schannel_fetch_session_key_tdb()
204 Note we must be root here.
205 *******************************************************************************/
207 NTSTATUS
schannel_get_creds_state(TALLOC_CTX
*mem_ctx
,
208 const char *db_priv_dir
,
209 const char *computer_name
,
210 struct netlogon_creds_CredentialState
**_creds
)
213 struct tdb_wrap
*tdb_sc
;
214 struct netlogon_creds_CredentialState
*creds
;
217 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_get_creds_state");
219 return NT_STATUS_NO_MEMORY
;
222 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
224 return NT_STATUS_ACCESS_DENIED
;
227 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
,
228 computer_name
, &creds
);
229 if (NT_STATUS_IS_OK(status
)) {
230 *_creds
= talloc_steal(mem_ctx
, creds
);
232 status
= NT_STATUS_NO_MEMORY
;
240 /******************************************************************************
241 Wrapper around schannel_store_session_key_tdb()
242 Note we must be root here.
243 *******************************************************************************/
245 NTSTATUS
schannel_save_creds_state(TALLOC_CTX
*mem_ctx
,
246 const char *db_priv_dir
,
247 struct netlogon_creds_CredentialState
*creds
)
250 struct tdb_wrap
*tdb_sc
;
253 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_save_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_store_session_key_tdb(tdb_sc
, tmpctx
, creds
);
269 /********************************************************************
270 Validate an incoming authenticator against the credentials for the
271 remote machine stored in the schannel database.
273 The credentials are (re)read and from the schannel database, and
274 written back after the caclulations are performed.
276 If the creds_out parameter is not NULL returns the credentials.
277 ********************************************************************/
279 NTSTATUS
schannel_check_creds_state(TALLOC_CTX
*mem_ctx
,
280 const char *db_priv_dir
,
281 const char *computer_name
,
282 struct netr_Authenticator
*received_authenticator
,
283 struct netr_Authenticator
*return_authenticator
,
284 struct netlogon_creds_CredentialState
**creds_out
)
287 struct tdb_wrap
*tdb_sc
;
288 struct netlogon_creds_CredentialState
*creds
;
292 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_check_creds_state");
294 return NT_STATUS_NO_MEMORY
;
297 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
299 status
= NT_STATUS_ACCESS_DENIED
;
303 ret
= tdb_transaction_start(tdb_sc
->tdb
);
305 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
309 /* Because this is a shared structure (even across
310 * disconnects) we must update the database every time we
311 * update the structure */
313 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
,
314 computer_name
, &creds
);
315 if (!NT_STATUS_IS_OK(status
)) {
316 tdb_transaction_cancel(tdb_sc
->tdb
);
320 status
= netlogon_creds_server_step_check(creds
,
321 received_authenticator
,
322 return_authenticator
);
323 if (!NT_STATUS_IS_OK(status
)) {
324 tdb_transaction_cancel(tdb_sc
->tdb
);
328 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, creds
);
329 if (!NT_STATUS_IS_OK(status
)) {
330 tdb_transaction_cancel(tdb_sc
->tdb
);
334 tdb_transaction_commit(tdb_sc
->tdb
);
337 *creds_out
= talloc_steal(mem_ctx
, creds
);
339 status
= NT_STATUS_NO_MEMORY
;
344 status
= NT_STATUS_OK
;