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_db_path(mem_ctx
, lp_ctx
, "schannel_store");
50 db_sc
= dbwrap_local_open(mem_ctx
, lp_ctx
, fname
, 0,
51 TDB_CLEAR_IF_FIRST
|TDB_NOSYNC
, O_RDWR
|O_CREAT
,
52 0600, DBWRAP_LOCK_ORDER_NONE
,
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 db_context
*db_sc
,
73 struct netlogon_creds_CredentialState
*creds
)
75 enum ndr_err_code ndr_err
;
82 if (strlen(creds
->computer_name
) > 15) {
84 * We may want to check for a completely
87 return STATUS_BUFFER_OVERFLOW
;
90 name_upper
= strupper_talloc(mem_ctx
, creds
->computer_name
);
92 return NT_STATUS_NO_MEMORY
;
95 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
96 SECRETS_SCHANNEL_STATE
, name_upper
);
97 TALLOC_FREE(name_upper
);
99 return NT_STATUS_NO_MEMORY
;
102 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, creds
,
103 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
104 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
106 return ndr_map_error2ntstatus(ndr_err
);
109 value
.dptr
= blob
.data
;
110 value
.dsize
= blob
.length
;
112 status
= dbwrap_store_bystring(db_sc
, keystr
, value
, TDB_REPLACE
);
113 if (!NT_STATUS_IS_OK(status
)) {
114 DEBUG(0,("Unable to add %s to session key db - %s\n",
115 keystr
, nt_errstr(status
)));
120 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
123 if (DEBUGLEVEL
>= 10) {
124 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
132 /********************************************************************
133 ********************************************************************/
136 NTSTATUS
schannel_fetch_session_key_tdb(struct db_context
*db_sc
,
138 const char *computer_name
,
139 struct netlogon_creds_CredentialState
**pcreds
)
143 enum ndr_err_code ndr_err
;
145 struct netlogon_creds_CredentialState
*creds
= NULL
;
151 name_upper
= strupper_talloc(mem_ctx
, computer_name
);
153 return NT_STATUS_NO_MEMORY
;
156 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
157 SECRETS_SCHANNEL_STATE
, name_upper
);
158 TALLOC_FREE(name_upper
);
160 return NT_STATUS_NO_MEMORY
;
163 status
= dbwrap_fetch_bystring(db_sc
, keystr
, keystr
, &value
);
164 if (!NT_STATUS_IS_OK(status
)) {
165 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
170 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
172 status
= NT_STATUS_NO_MEMORY
;
176 blob
= data_blob_const(value
.dptr
, value
.dsize
);
178 ndr_err
= ndr_pull_struct_blob(&blob
, creds
, creds
,
179 (ndr_pull_flags_fn_t
)ndr_pull_netlogon_creds_CredentialState
);
180 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
181 status
= ndr_map_error2ntstatus(ndr_err
);
185 if (DEBUGLEVEL
>= 10) {
186 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
189 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
192 status
= NT_STATUS_OK
;
198 if (!NT_STATUS_IS_OK(status
)) {
208 /******************************************************************************
209 Wrapper around schannel_fetch_session_key_tdb()
210 Note we must be root here.
211 *******************************************************************************/
213 NTSTATUS
schannel_get_creds_state(TALLOC_CTX
*mem_ctx
,
214 struct loadparm_context
*lp_ctx
,
215 const char *computer_name
,
216 struct netlogon_creds_CredentialState
**_creds
)
219 struct db_context
*db_sc
;
220 struct netlogon_creds_CredentialState
*creds
;
223 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_get_creds_state");
225 return NT_STATUS_NO_MEMORY
;
228 db_sc
= open_schannel_session_store(tmpctx
, lp_ctx
);
230 return NT_STATUS_ACCESS_DENIED
;
233 status
= schannel_fetch_session_key_tdb(db_sc
, tmpctx
,
234 computer_name
, &creds
);
235 if (NT_STATUS_IS_OK(status
)) {
236 *_creds
= talloc_steal(mem_ctx
, creds
);
238 status
= NT_STATUS_NO_MEMORY
;
246 /******************************************************************************
247 Wrapper around schannel_store_session_key_tdb()
248 Note we must be root here.
249 *******************************************************************************/
251 NTSTATUS
schannel_save_creds_state(TALLOC_CTX
*mem_ctx
,
252 struct loadparm_context
*lp_ctx
,
253 struct netlogon_creds_CredentialState
*creds
)
256 struct db_context
*db_sc
;
259 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_save_creds_state");
261 return NT_STATUS_NO_MEMORY
;
264 db_sc
= open_schannel_session_store(tmpctx
, lp_ctx
);
266 return NT_STATUS_ACCESS_DENIED
;
269 status
= schannel_store_session_key_tdb(db_sc
, tmpctx
, creds
);
275 /********************************************************************
276 Validate an incoming authenticator against the credentials for the
277 remote machine stored in the schannel database.
279 The credentials are (re)read and from the schannel database, and
280 written back after the caclulations are performed.
282 If the creds_out parameter is not NULL returns the credentials.
283 ********************************************************************/
285 NTSTATUS
schannel_check_creds_state(TALLOC_CTX
*mem_ctx
,
286 struct loadparm_context
*lp_ctx
,
287 const char *computer_name
,
288 struct netr_Authenticator
*received_authenticator
,
289 struct netr_Authenticator
*return_authenticator
,
290 struct netlogon_creds_CredentialState
**creds_out
)
293 struct db_context
*db_sc
;
294 struct netlogon_creds_CredentialState
*creds
;
296 char *name_upper
= NULL
;
298 struct db_record
*record
;
301 if (creds_out
!= NULL
) {
305 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_check_creds_state");
307 return NT_STATUS_NO_MEMORY
;
310 name_upper
= strupper_talloc(tmpctx
, computer_name
);
312 status
= NT_STATUS_NO_MEMORY
;
316 keystr
= talloc_asprintf(tmpctx
, "%s/%s",
317 SECRETS_SCHANNEL_STATE
, name_upper
);
319 status
= NT_STATUS_NO_MEMORY
;
323 key
= string_term_tdb_data(keystr
);
325 db_sc
= open_schannel_session_store(tmpctx
, lp_ctx
);
327 status
= NT_STATUS_ACCESS_DENIED
;
331 record
= dbwrap_fetch_locked(db_sc
, tmpctx
, key
);
333 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
337 /* Because this is a shared structure (even across
338 * disconnects) we must update the database every time we
339 * update the structure */
341 status
= schannel_fetch_session_key_tdb(db_sc
, tmpctx
,
342 computer_name
, &creds
);
343 if (!NT_STATUS_IS_OK(status
)) {
347 status
= netlogon_creds_server_step_check(creds
,
348 received_authenticator
,
349 return_authenticator
);
350 if (!NT_STATUS_IS_OK(status
)) {
354 status
= schannel_store_session_key_tdb(db_sc
, tmpctx
, creds
);
355 if (!NT_STATUS_IS_OK(status
)) {
360 *creds_out
= talloc_steal(mem_ctx
, creds
);
362 status
= NT_STATUS_NO_MEMORY
;
367 status
= NT_STATUS_OK
;