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"
26 #include "../lib/tdb/include/tdb.h"
27 #include "../lib/util/util_tdb.h"
28 #include "../lib/param/param.h"
29 #include "../libcli/auth/schannel.h"
30 #include "../librpc/gen_ndr/ndr_schannel.h"
31 #include "lib/tdb_wrap/tdb_wrap.h"
33 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
35 /******************************************************************************
36 Open or create the schannel session store tdb. Non-static so it can
37 be called from parent processes to corectly handle TDB_CLEAR_IF_FIRST
38 *******************************************************************************/
40 struct tdb_wrap
*open_schannel_session_store(TALLOC_CTX
*mem_ctx
,
41 struct loadparm_context
*lp_ctx
)
43 struct tdb_wrap
*tdb_sc
= NULL
;
44 char *fname
= lpcfg_private_path(mem_ctx
, lp_ctx
, "schannel_store.tdb");
50 tdb_sc
= tdb_wrap_open(mem_ctx
, fname
, 0, TDB_CLEAR_IF_FIRST
|TDB_NOSYNC
, O_RDWR
|O_CREAT
, 0600, lp_ctx
);
53 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
54 fname
, strerror(errno
)));
64 /********************************************************************
65 ********************************************************************/
68 NTSTATUS
schannel_store_session_key_tdb(struct tdb_wrap
*tdb_sc
,
70 struct netlogon_creds_CredentialState
*creds
)
72 enum ndr_err_code ndr_err
;
79 name_upper
= strupper_talloc(mem_ctx
, creds
->computer_name
);
81 return NT_STATUS_NO_MEMORY
;
84 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
85 SECRETS_SCHANNEL_STATE
, name_upper
);
86 TALLOC_FREE(name_upper
);
88 return NT_STATUS_NO_MEMORY
;
91 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, creds
,
92 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
93 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
95 return ndr_map_error2ntstatus(ndr_err
);
98 value
.dptr
= blob
.data
;
99 value
.dsize
= blob
.length
;
101 ret
= tdb_store_bystring(tdb_sc
->tdb
, keystr
, value
, TDB_REPLACE
);
102 if (ret
!= TDB_SUCCESS
) {
103 DEBUG(0,("Unable to add %s to session key db - %s\n",
104 keystr
, tdb_errorstr(tdb_sc
->tdb
)));
106 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
109 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
112 if (DEBUGLEVEL
>= 10) {
113 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
121 /********************************************************************
122 ********************************************************************/
125 NTSTATUS
schannel_fetch_session_key_tdb(struct tdb_wrap
*tdb_sc
,
127 const char *computer_name
,
128 struct netlogon_creds_CredentialState
**pcreds
)
132 enum ndr_err_code ndr_err
;
134 struct netlogon_creds_CredentialState
*creds
= NULL
;
140 name_upper
= strupper_talloc(mem_ctx
, computer_name
);
142 return NT_STATUS_NO_MEMORY
;
145 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
146 SECRETS_SCHANNEL_STATE
, name_upper
);
147 TALLOC_FREE(name_upper
);
149 return NT_STATUS_NO_MEMORY
;
152 value
= tdb_fetch_bystring(tdb_sc
->tdb
, keystr
);
154 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
156 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
160 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
162 status
= NT_STATUS_NO_MEMORY
;
166 blob
= data_blob_const(value
.dptr
, value
.dsize
);
168 ndr_err
= ndr_pull_struct_blob(&blob
, creds
, creds
,
169 (ndr_pull_flags_fn_t
)ndr_pull_netlogon_creds_CredentialState
);
170 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
171 status
= ndr_map_error2ntstatus(ndr_err
);
175 if (DEBUGLEVEL
>= 10) {
176 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
179 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
182 status
= NT_STATUS_OK
;
187 SAFE_FREE(value
.dptr
);
189 if (!NT_STATUS_IS_OK(status
)) {
199 /******************************************************************************
200 Wrapper around schannel_fetch_session_key_tdb()
201 Note we must be root here.
202 *******************************************************************************/
204 NTSTATUS
schannel_get_creds_state(TALLOC_CTX
*mem_ctx
,
205 struct loadparm_context
*lp_ctx
,
206 const char *computer_name
,
207 struct netlogon_creds_CredentialState
**_creds
)
210 struct tdb_wrap
*tdb_sc
;
211 struct netlogon_creds_CredentialState
*creds
;
214 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_get_creds_state");
216 return NT_STATUS_NO_MEMORY
;
219 tdb_sc
= open_schannel_session_store(tmpctx
, lp_ctx
);
221 return NT_STATUS_ACCESS_DENIED
;
224 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
,
225 computer_name
, &creds
);
226 if (NT_STATUS_IS_OK(status
)) {
227 *_creds
= talloc_steal(mem_ctx
, creds
);
229 status
= NT_STATUS_NO_MEMORY
;
237 /******************************************************************************
238 Wrapper around schannel_store_session_key_tdb()
239 Note we must be root here.
240 *******************************************************************************/
242 NTSTATUS
schannel_save_creds_state(TALLOC_CTX
*mem_ctx
,
243 struct loadparm_context
*lp_ctx
,
244 struct netlogon_creds_CredentialState
*creds
)
247 struct tdb_wrap
*tdb_sc
;
250 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_save_creds_state");
252 return NT_STATUS_NO_MEMORY
;
255 tdb_sc
= open_schannel_session_store(tmpctx
, lp_ctx
);
257 return NT_STATUS_ACCESS_DENIED
;
260 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, creds
);
266 /********************************************************************
267 Validate an incoming authenticator against the credentials for the
268 remote machine stored in the schannel database.
270 The credentials are (re)read and from the schannel database, and
271 written back after the caclulations are performed.
273 If the creds_out parameter is not NULL returns the credentials.
274 ********************************************************************/
276 NTSTATUS
schannel_check_creds_state(TALLOC_CTX
*mem_ctx
,
277 struct loadparm_context
*lp_ctx
,
278 const char *computer_name
,
279 struct netr_Authenticator
*received_authenticator
,
280 struct netr_Authenticator
*return_authenticator
,
281 struct netlogon_creds_CredentialState
**creds_out
)
284 struct tdb_wrap
*tdb_sc
;
285 struct netlogon_creds_CredentialState
*creds
;
289 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_check_creds_state");
291 return NT_STATUS_NO_MEMORY
;
294 tdb_sc
= open_schannel_session_store(tmpctx
, lp_ctx
);
296 status
= NT_STATUS_ACCESS_DENIED
;
300 ret
= tdb_transaction_start(tdb_sc
->tdb
);
302 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
306 /* Because this is a shared structure (even across
307 * disconnects) we must update the database every time we
308 * update the structure */
310 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
,
311 computer_name
, &creds
);
312 if (!NT_STATUS_IS_OK(status
)) {
313 tdb_transaction_cancel(tdb_sc
->tdb
);
317 status
= netlogon_creds_server_step_check(creds
,
318 received_authenticator
,
319 return_authenticator
);
320 if (!NT_STATUS_IS_OK(status
)) {
321 tdb_transaction_cancel(tdb_sc
->tdb
);
325 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, creds
);
326 if (!NT_STATUS_IS_OK(status
)) {
327 tdb_transaction_cancel(tdb_sc
->tdb
);
331 tdb_transaction_commit(tdb_sc
->tdb
);
334 *creds_out
= talloc_steal(mem_ctx
, creds
);
336 status
= NT_STATUS_NO_MEMORY
;
341 status
= NT_STATUS_OK
;