Allow us to cope correctly with NT_STATUS_MORE_PROCESSING_REQUIRED when downgrading...
[Samba/ekacnet.git] / libcli / auth / schannel_state_tdb.c
blob9e767810a18de7102b46798bd706b1b56e622e71
1 /*
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/>.
24 #include "includes.h"
25 #include "system/filesys.h"
26 #include <tdb.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
32 #include "tdb_wrap.h"
33 #endif
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)
48 TDB_DATA vers;
49 uint32_t ver;
50 struct tdb_wrap *tdb_sc = NULL;
51 char *fname = talloc_asprintf(mem_ctx, "%s/schannel_store.tdb", private_dir);
53 if (!fname) {
54 return NULL;
57 tdb_sc = tdb_wrap_open(mem_ctx, fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
59 if (!tdb_sc) {
60 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
61 fname, strerror(errno)));
62 TALLOC_FREE(fname);
63 return NULL;
66 again:
67 vers = tdb_fetch_bystring(tdb_sc->tdb, "SCHANNEL_STORE_VERSION");
68 if (vers.dptr == NULL) {
69 /* First opener, no version. */
70 SIVAL(&ver,0,SCHANNEL_STORE_VERSION_CURRENT);
71 vers.dptr = (uint8_t *)&ver;
72 vers.dsize = 4;
73 tdb_store_bystring(tdb_sc->tdb, "SCHANNEL_STORE_VERSION", vers, TDB_REPLACE);
74 vers.dptr = NULL;
75 } else if (vers.dsize == 4) {
76 ver = IVAL(vers.dptr,0);
77 if (ver == SCHANNEL_STORE_VERSION_2) {
78 DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n",
79 (int)ver, fname ));
80 tdb_wipe_all(tdb_sc->tdb);
81 goto again;
83 if (ver != SCHANNEL_STORE_VERSION_CURRENT) {
84 DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n",
85 (int)ver, fname ));
86 TALLOC_FREE(tdb_sc);
88 } else {
89 TALLOC_FREE(tdb_sc);
90 DEBUG(0,("open_schannel_session_store: wrong version number size %d in %s\n",
91 (int)vers.dsize, fname ));
94 SAFE_FREE(vers.dptr);
95 TALLOC_FREE(fname);
97 return tdb_sc;
100 /********************************************************************
101 ********************************************************************/
103 static
104 NTSTATUS schannel_store_session_key_tdb(struct tdb_wrap *tdb_sc,
105 TALLOC_CTX *mem_ctx,
106 struct netlogon_creds_CredentialState *creds)
108 enum ndr_err_code ndr_err;
109 DATA_BLOB blob;
110 TDB_DATA value;
111 int ret;
112 char *keystr;
113 char *name_upper;
115 name_upper = strupper_talloc(mem_ctx, creds->computer_name);
116 if (!name_upper) {
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);
123 if (!keystr) {
124 return NT_STATUS_NO_MEMORY;
127 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
128 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
129 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
130 talloc_free(keystr);
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)));
141 talloc_free(keystr);
142 return NT_STATUS_INTERNAL_DB_CORRUPTION;
145 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
146 keystr));
148 if (DEBUGLEVEL >= 10) {
149 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
152 talloc_free(keystr);
154 return NT_STATUS_OK;
157 /********************************************************************
158 ********************************************************************/
160 static
161 NTSTATUS schannel_fetch_session_key_tdb(struct tdb_wrap *tdb_sc,
162 TALLOC_CTX *mem_ctx,
163 const char *computer_name,
164 struct netlogon_creds_CredentialState **pcreds)
166 NTSTATUS status;
167 TDB_DATA value;
168 enum ndr_err_code ndr_err;
169 DATA_BLOB blob;
170 struct netlogon_creds_CredentialState *creds = NULL;
171 char *keystr = NULL;
172 char *name_upper;
174 *pcreds = NULL;
176 name_upper = strupper_talloc(mem_ctx, computer_name);
177 if (!name_upper) {
178 return NT_STATUS_NO_MEMORY;
181 keystr = talloc_asprintf(mem_ctx, "%s/%s",
182 SECRETS_SCHANNEL_STATE, name_upper);
183 TALLOC_FREE(name_upper);
184 if (!keystr) {
185 return NT_STATUS_NO_MEMORY;
188 value = tdb_fetch_bystring(tdb_sc->tdb, keystr);
189 if (!value.dptr) {
190 DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
191 keystr ));
192 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
193 goto done;
196 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
197 if (!creds) {
198 status = NT_STATUS_NO_MEMORY;
199 goto done;
202 blob = data_blob_const(value.dptr, value.dsize);
204 ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
205 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
206 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
207 status = ndr_map_error2ntstatus(ndr_err);
208 goto done;
211 if (DEBUGLEVEL >= 10) {
212 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
215 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
216 keystr));
218 status = NT_STATUS_OK;
220 done:
222 talloc_free(keystr);
223 SAFE_FREE(value.dptr);
225 if (!NT_STATUS_IS_OK(status)) {
226 talloc_free(creds);
227 return status;
230 *pcreds = creds;
232 return NT_STATUS_OK;
235 /******************************************************************************
236 Wrapper around schannel_fetch_session_key_tdb()
237 Note we must be root here.
238 *******************************************************************************/
240 NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
241 const char *db_priv_dir,
242 const char *computer_name,
243 struct netlogon_creds_CredentialState **_creds)
245 TALLOC_CTX *tmpctx;
246 struct tdb_wrap *tdb_sc;
247 struct netlogon_creds_CredentialState *creds;
248 NTSTATUS status;
250 tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
251 if (!tmpctx) {
252 return NT_STATUS_NO_MEMORY;
255 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
256 if (!tdb_sc) {
257 return NT_STATUS_ACCESS_DENIED;
260 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx,
261 computer_name, &creds);
262 if (NT_STATUS_IS_OK(status)) {
263 *_creds = talloc_steal(mem_ctx, creds);
264 if (!*_creds) {
265 status = NT_STATUS_NO_MEMORY;
269 talloc_free(tmpctx);
270 return status;
273 /******************************************************************************
274 Wrapper around schannel_store_session_key_tdb()
275 Note we must be root here.
276 *******************************************************************************/
278 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
279 const char *db_priv_dir,
280 struct netlogon_creds_CredentialState *creds)
282 TALLOC_CTX *tmpctx;
283 struct tdb_wrap *tdb_sc;
284 NTSTATUS status;
286 tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
287 if (!tmpctx) {
288 return NT_STATUS_NO_MEMORY;
291 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
292 if (!tdb_sc) {
293 return NT_STATUS_ACCESS_DENIED;
296 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
298 talloc_free(tmpctx);
299 return status;
302 /********************************************************************
303 Validate an incoming authenticator against the credentials for the
304 remote machine stored in the schannel database.
306 The credentials are (re)read and from the schannel database, and
307 written back after the caclulations are performed.
309 If the creds_out parameter is not NULL returns the credentials.
310 ********************************************************************/
312 NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
313 const char *db_priv_dir,
314 const char *computer_name,
315 struct netr_Authenticator *received_authenticator,
316 struct netr_Authenticator *return_authenticator,
317 struct netlogon_creds_CredentialState **creds_out)
319 TALLOC_CTX *tmpctx;
320 struct tdb_wrap *tdb_sc;
321 struct netlogon_creds_CredentialState *creds;
322 NTSTATUS status;
323 int ret;
325 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
326 if (!tmpctx) {
327 return NT_STATUS_NO_MEMORY;
330 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
331 if (!tdb_sc) {
332 status = NT_STATUS_ACCESS_DENIED;
333 goto done;
336 ret = tdb_transaction_start(tdb_sc->tdb);
337 if (ret != 0) {
338 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
339 goto done;
342 /* Because this is a shared structure (even across
343 * disconnects) we must update the database every time we
344 * update the structure */
346 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx,
347 computer_name, &creds);
348 if (!NT_STATUS_IS_OK(status)) {
349 tdb_transaction_cancel(tdb_sc->tdb);
350 goto done;
353 status = netlogon_creds_server_step_check(creds,
354 received_authenticator,
355 return_authenticator);
356 if (!NT_STATUS_IS_OK(status)) {
357 tdb_transaction_cancel(tdb_sc->tdb);
358 goto done;
361 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
362 if (!NT_STATUS_IS_OK(status)) {
363 tdb_transaction_cancel(tdb_sc->tdb);
364 goto done;
367 tdb_transaction_commit(tdb_sc->tdb);
369 if (creds_out) {
370 *creds_out = talloc_steal(mem_ctx, creds);
371 if (!*creds_out) {
372 status = NT_STATUS_NO_MEMORY;
373 goto done;
377 status = NT_STATUS_OK;
379 done:
380 talloc_free(tmpctx);
381 return status;