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 "../librpc/gen_ndr/ndr_schannel.h"
31 #if _SAMBA_BUILD_ == 4
35 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
37 /******************************************************************************
38 Open or create the schannel session store tdb.
39 *******************************************************************************/
41 #define SCHANNEL_STORE_VERSION_1 1
42 #define SCHANNEL_STORE_VERSION_2 2 /* should not be used */
43 #define SCHANNEL_STORE_VERSION_CURRENT SCHANNEL_STORE_VERSION_1
45 static struct tdb_wrap
*open_schannel_session_store(TALLOC_CTX
*mem_ctx
,
46 const char *private_dir
)
50 struct tdb_wrap
*tdb_sc
= NULL
;
51 char *fname
= talloc_asprintf(mem_ctx
, "%s/schannel_store.tdb", private_dir
);
57 tdb_sc
= tdb_wrap_open(mem_ctx
, fname
, 0, TDB_DEFAULT
, O_RDWR
|O_CREAT
, 0600);
60 DEBUG(0,("open_schannel_session_store: Failed to open %s\n", fname
));
66 vers
= tdb_fetch_bystring(tdb_sc
->tdb
, "SCHANNEL_STORE_VERSION");
67 if (vers
.dptr
== NULL
) {
68 /* First opener, no version. */
69 SIVAL(&ver
,0,SCHANNEL_STORE_VERSION_CURRENT
);
70 vers
.dptr
= (uint8_t *)&ver
;
72 tdb_store_bystring(tdb_sc
->tdb
, "SCHANNEL_STORE_VERSION", vers
, TDB_REPLACE
);
74 } else if (vers
.dsize
== 4) {
75 ver
= IVAL(vers
.dptr
,0);
76 if (ver
== SCHANNEL_STORE_VERSION_2
) {
77 DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n",
79 tdb_wipe_all(tdb_sc
->tdb
);
82 if (ver
!= SCHANNEL_STORE_VERSION_CURRENT
) {
83 DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n",
89 DEBUG(0,("open_schannel_session_store: wrong version number size %d in %s\n",
90 (int)vers
.dsize
, fname
));
99 /********************************************************************
100 ********************************************************************/
103 NTSTATUS
schannel_store_session_key_tdb(struct tdb_wrap
*tdb_sc
,
105 struct smb_iconv_convenience
*ic
,
106 struct netlogon_creds_CredentialState
*creds
)
108 enum ndr_err_code ndr_err
;
115 name_upper
= strupper_talloc(mem_ctx
, creds
->computer_name
);
117 return NT_STATUS_NO_MEMORY
;
120 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
121 SECRETS_SCHANNEL_STATE
, name_upper
);
122 TALLOC_FREE(name_upper
);
124 return NT_STATUS_NO_MEMORY
;
127 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, ic
, creds
,
128 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
129 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
131 return ndr_map_error2ntstatus(ndr_err
);
134 value
.dptr
= blob
.data
;
135 value
.dsize
= blob
.length
;
137 ret
= tdb_store_bystring(tdb_sc
->tdb
, keystr
, value
, TDB_REPLACE
);
138 if (ret
!= TDB_SUCCESS
) {
139 DEBUG(0,("Unable to add %s to session key db - %s\n",
140 keystr
, tdb_errorstr(tdb_sc
->tdb
)));
142 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
145 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
148 if (DEBUGLEVEL
>= 10) {
149 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
157 /********************************************************************
158 ********************************************************************/
161 NTSTATUS
schannel_fetch_session_key_tdb(struct tdb_wrap
*tdb_sc
,
163 struct smb_iconv_convenience
*ic
,
164 const char *computer_name
,
165 struct netlogon_creds_CredentialState
**pcreds
)
169 enum ndr_err_code ndr_err
;
171 struct netlogon_creds_CredentialState
*creds
= NULL
;
177 name_upper
= strupper_talloc(mem_ctx
, computer_name
);
179 return NT_STATUS_NO_MEMORY
;
182 keystr
= talloc_asprintf(mem_ctx
, "%s/%s",
183 SECRETS_SCHANNEL_STATE
, name_upper
);
184 TALLOC_FREE(name_upper
);
186 status
= NT_STATUS_NO_MEMORY
;
190 value
= tdb_fetch_bystring(tdb_sc
->tdb
, keystr
);
192 DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
194 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
198 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
200 status
= NT_STATUS_NO_MEMORY
;
204 blob
= data_blob_const(value
.dptr
, value
.dsize
);
206 ndr_err
= ndr_pull_struct_blob(&blob
, creds
, ic
, creds
,
207 (ndr_pull_flags_fn_t
)ndr_pull_netlogon_creds_CredentialState
);
208 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
209 status
= ndr_map_error2ntstatus(ndr_err
);
213 if (DEBUGLEVEL
>= 10) {
214 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
217 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
220 status
= NT_STATUS_OK
;
226 if (!NT_STATUS_IS_OK(status
)) {
236 /******************************************************************************
237 Wrapper around schannel_fetch_session_key_tdb()
238 Note we must be root here.
239 *******************************************************************************/
241 NTSTATUS
schannel_get_creds_state(TALLOC_CTX
*mem_ctx
,
242 struct smb_iconv_convenience
*ic
,
243 const char *db_priv_dir
,
244 const char *computer_name
,
245 struct netlogon_creds_CredentialState
**_creds
)
248 struct tdb_wrap
*tdb_sc
;
249 struct netlogon_creds_CredentialState
*creds
;
252 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_get_creds_state");
254 return NT_STATUS_NO_MEMORY
;
257 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
259 return NT_STATUS_ACCESS_DENIED
;
262 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
, ic
,
263 computer_name
, &creds
);
264 if (NT_STATUS_IS_OK(status
)) {
265 *_creds
= talloc_steal(mem_ctx
, creds
);
267 status
= NT_STATUS_NO_MEMORY
;
275 /******************************************************************************
276 Wrapper around schannel_store_session_key_tdb()
277 Note we must be root here.
278 *******************************************************************************/
280 NTSTATUS
schannel_save_creds_state(TALLOC_CTX
*mem_ctx
,
281 struct smb_iconv_convenience
*ic
,
282 const char *db_priv_dir
,
283 struct netlogon_creds_CredentialState
*creds
)
286 struct tdb_wrap
*tdb_sc
;
289 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_save_creds_state");
291 return NT_STATUS_NO_MEMORY
;
294 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
296 return NT_STATUS_ACCESS_DENIED
;
299 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, ic
, creds
);
305 /********************************************************************
306 Validate an incoming authenticator against the credentials for the
307 remote machine stored in the schannel database.
309 The credentials are (re)read and from the schannel database, and
310 written back after the caclulations are performed.
312 If the creds_out parameter is not NULL returns the credentials.
313 ********************************************************************/
315 NTSTATUS
schannel_check_creds_state(TALLOC_CTX
*mem_ctx
,
316 struct smb_iconv_convenience
*ic
,
317 const char *db_priv_dir
,
318 const char *computer_name
,
319 struct netr_Authenticator
*received_authenticator
,
320 struct netr_Authenticator
*return_authenticator
,
321 struct netlogon_creds_CredentialState
**creds_out
)
324 struct tdb_wrap
*tdb_sc
;
325 struct netlogon_creds_CredentialState
*creds
;
329 tmpctx
= talloc_named(mem_ctx
, 0, "schannel_check_creds_state");
331 return NT_STATUS_NO_MEMORY
;
334 tdb_sc
= open_schannel_session_store(tmpctx
, db_priv_dir
);
336 status
= NT_STATUS_ACCESS_DENIED
;
340 ret
= tdb_transaction_start(tdb_sc
->tdb
);
342 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
343 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
347 /* Because this is a shared structure (even across
348 * disconnects) we must update the database every time we
349 * update the structure */
351 status
= schannel_fetch_session_key_tdb(tdb_sc
, tmpctx
, ic
,
352 computer_name
, &creds
);
353 if (!NT_STATUS_IS_OK(status
)) {
354 tdb_transaction_cancel(tdb_sc
->tdb
);
358 status
= netlogon_creds_server_step_check(creds
,
359 received_authenticator
,
360 return_authenticator
);
361 if (!NT_STATUS_IS_OK(status
)) {
362 tdb_transaction_cancel(tdb_sc
->tdb
);
366 status
= schannel_store_session_key_tdb(tdb_sc
, tmpctx
, ic
, creds
);
367 if (!NT_STATUS_IS_OK(status
)) {
368 tdb_transaction_cancel(tdb_sc
->tdb
);
372 tdb_transaction_commit(tdb_sc
->tdb
);
375 *creds_out
= talloc_steal(mem_ctx
, creds
);
377 status
= NT_STATUS_NO_MEMORY
;
382 status
= NT_STATUS_OK
;