schannel_tdb: make code compilable in both trees
[Samba/ekacnet.git] / libcli / auth / schannel_state_tdb.c
blobfd61b0a38a8350e73ae0cdaae9875fa6b6bd57a9
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\n", fname));
61 TALLOC_FREE(fname);
62 return NULL;
65 again:
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;
71 vers.dsize = 4;
72 tdb_store_bystring(tdb_sc->tdb, "SCHANNEL_STORE_VERSION", vers, TDB_REPLACE);
73 vers.dptr = NULL;
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",
78 (int)ver, fname ));
79 tdb_wipe_all(tdb_sc->tdb);
80 goto again;
82 if (ver != SCHANNEL_STORE_VERSION_CURRENT) {
83 DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n",
84 (int)ver, fname ));
85 TALLOC_FREE(tdb_sc);
87 } else {
88 TALLOC_FREE(tdb_sc);
89 DEBUG(0,("open_schannel_session_store: wrong version number size %d in %s\n",
90 (int)vers.dsize, fname ));
93 SAFE_FREE(vers.dptr);
94 TALLOC_FREE(fname);
96 return tdb_sc;
99 /********************************************************************
100 ********************************************************************/
102 static
103 NTSTATUS schannel_store_session_key_tdb(struct tdb_wrap *tdb_sc,
104 TALLOC_CTX *mem_ctx,
105 struct smb_iconv_convenience *ic,
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, ic, 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 struct smb_iconv_convenience *ic,
164 const char *computer_name,
165 struct netlogon_creds_CredentialState **pcreds)
167 NTSTATUS status;
168 TDB_DATA value;
169 enum ndr_err_code ndr_err;
170 DATA_BLOB blob;
171 struct netlogon_creds_CredentialState *creds = NULL;
172 char *keystr = NULL;
173 char *name_upper;
175 *pcreds = NULL;
177 name_upper = strupper_talloc(mem_ctx, computer_name);
178 if (!name_upper) {
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);
185 if (!keystr) {
186 status = NT_STATUS_NO_MEMORY;
187 goto done;
190 value = tdb_fetch_bystring(tdb_sc->tdb, keystr);
191 if (!value.dptr) {
192 DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
193 keystr ));
194 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
195 goto done;
198 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
199 if (!creds) {
200 status = NT_STATUS_NO_MEMORY;
201 goto done;
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);
210 goto done;
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",
218 keystr));
220 status = NT_STATUS_OK;
222 done:
224 talloc_free(keystr);
226 if (!NT_STATUS_IS_OK(status)) {
227 talloc_free(creds);
228 return status;
231 *pcreds = creds;
233 return NT_STATUS_OK;
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)
247 TALLOC_CTX *tmpctx;
248 struct tdb_wrap *tdb_sc;
249 struct netlogon_creds_CredentialState *creds;
250 NTSTATUS status;
252 tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
253 if (!tmpctx) {
254 return NT_STATUS_NO_MEMORY;
257 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
258 if (!tdb_sc) {
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);
266 if (!*_creds) {
267 status = NT_STATUS_NO_MEMORY;
271 talloc_free(tmpctx);
272 return status;
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)
285 TALLOC_CTX *tmpctx;
286 struct tdb_wrap *tdb_sc;
287 NTSTATUS status;
289 tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
290 if (!tmpctx) {
291 return NT_STATUS_NO_MEMORY;
294 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
295 if (!tdb_sc) {
296 return NT_STATUS_ACCESS_DENIED;
299 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, ic, creds);
301 talloc_free(tmpctx);
302 return status;
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)
323 TALLOC_CTX *tmpctx;
324 struct tdb_wrap *tdb_sc;
325 struct netlogon_creds_CredentialState *creds;
326 NTSTATUS status;
327 int ret;
329 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
330 if (!tmpctx) {
331 return NT_STATUS_NO_MEMORY;
334 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
335 if (!tdb_sc) {
336 status = NT_STATUS_ACCESS_DENIED;
337 goto done;
340 ret = tdb_transaction_start(tdb_sc->tdb);
341 if (ret != 0) {
342 return NT_STATUS_INTERNAL_DB_CORRUPTION;
343 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
344 goto done;
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);
355 goto done;
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);
363 goto done;
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);
369 goto done;
372 tdb_transaction_commit(tdb_sc->tdb);
374 if (creds_out) {
375 *creds_out = talloc_steal(mem_ctx, creds);
376 if (!*creds_out) {
377 status = NT_STATUS_NO_MEMORY;
378 goto done;
382 status = NT_STATUS_OK;
384 done:
385 talloc_free(tmpctx);
386 return status;