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/dbwrap/dbwrap.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 db_context
*open_schannel_session_store(TALLOC_CTX
*mem_ctx
,
41 struct loadparm_context
*lp_ctx
)
43 struct db_context
*db_sc
= NULL
;
44 char *fname
= lpcfg_private_path(mem_ctx
, lp_ctx
, "schannel_store.tdb");
50 db_sc
= dbwrap_local_open(mem_ctx
, lp_ctx
, fname
, 0,
51 TDB_CLEAR_IF_FIRST
|TDB_NOSYNC
, O_RDWR
|O_CREAT
,
55 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
56 fname
, strerror(errno
)));
66 /********************************************************************
67 ********************************************************************/
70 NTSTATUS
schannel_store_session_key_tdb(struct db_context
*db_sc
,
72 struct netlogon_creds_CredentialState
*creds
)
74 enum ndr_err_code ndr_err
;
81 name_upper
= strupper_talloc(mem_ctx
, creds
->computer_name
);
83 return NT_STATUS_NO_MEMORY
;
86 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
87 SECRETS_SCHANNEL_STATE
, name_upper
);
88 TALLOC_FREE(name_upper
);
90 return NT_STATUS_NO_MEMORY
;
93 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, creds
,
94 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
95 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
97 return ndr_map_error2ntstatus(ndr_err
);
100 value
.dptr
= blob
.data
;
101 value
.dsize
= blob
.length
;
103 status
= dbwrap_store_bystring(db_sc
, keystr
, value
, TDB_REPLACE
);
104 if (!NT_STATUS_IS_OK(status
)) {
105 DEBUG(0,("Unable to add %s to session key db - %s\n",
106 keystr
, nt_errstr(status
)));
111 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
114 if (DEBUGLEVEL
>= 10) {
115 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
123 /********************************************************************
124 ********************************************************************/
127 NTSTATUS
schannel_fetch_session_key_tdb(struct db_context
*db_sc
,
129 const char *computer_name
,
130 struct netlogon_creds_CredentialState
**pcreds
)
134 enum ndr_err_code ndr_err
;
136 struct netlogon_creds_CredentialState
*creds
= NULL
;
142 name_upper
= strupper_talloc(mem_ctx
, computer_name
);
144 return NT_STATUS_NO_MEMORY
;
147 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
148 SECRETS_SCHANNEL_STATE
, name_upper
);
149 TALLOC_FREE(name_upper
);
151 return NT_STATUS_NO_MEMORY
;
154 status
= dbwrap_fetch_bystring(db_sc
, keystr
, keystr
, &value
);
155 if (!NT_STATUS_IS_OK(status
)) {
156 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
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
;
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 db_context
*db_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 db_sc
= open_schannel_session_store(tmpctx
, lp_ctx
);
221 return NT_STATUS_ACCESS_DENIED
;
224 status
= schannel_fetch_session_key_tdb(db_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 db_context
*db_sc
;
250 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_save_creds_state");
252 return NT_STATUS_NO_MEMORY
;
255 db_sc
= open_schannel_session_store(tmpctx
, lp_ctx
);
257 return NT_STATUS_ACCESS_DENIED
;
260 status
= schannel_store_session_key_tdb(db_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 db_context
*db_sc
;
285 struct netlogon_creds_CredentialState
*creds
;
288 char *name_upper
= NULL
;
290 struct db_record
*record
;
293 if (creds_out
!= NULL
) {
297 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_check_creds_state");
299 return NT_STATUS_NO_MEMORY
;
302 name_upper
= strupper_talloc(tmpctx
, computer_name
);
304 status
= NT_STATUS_NO_MEMORY
;
308 keystr
= talloc_asprintf(tmpctx
, "%s/%s",
309 SECRETS_SCHANNEL_STATE
, name_upper
);
311 status
= NT_STATUS_NO_MEMORY
;
315 key
= string_term_tdb_data(keystr
);
317 db_sc
= open_schannel_session_store(tmpctx
, lp_ctx
);
319 status
= NT_STATUS_ACCESS_DENIED
;
323 record
= dbwrap_fetch_locked(db_sc
, tmpctx
, key
);
325 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
329 /* Because this is a shared structure (even across
330 * disconnects) we must update the database every time we
331 * update the structure */
333 status
= schannel_fetch_session_key_tdb(db_sc
, tmpctx
,
334 computer_name
, &creds
);
335 if (!NT_STATUS_IS_OK(status
)) {
339 status
= netlogon_creds_server_step_check(creds
,
340 received_authenticator
,
341 return_authenticator
);
342 if (!NT_STATUS_IS_OK(status
)) {
346 status
= schannel_store_session_key_tdb(db_sc
, tmpctx
, creds
);
347 if (!NT_STATUS_IS_OK(status
)) {
352 *creds_out
= talloc_steal(mem_ctx
, creds
);
354 status
= NT_STATUS_NO_MEMORY
;
359 status
= NT_STATUS_OK
;