VERSION: Move on to beta9
[Samba/bb.git] / libcli / auth / schannel_state_tdb.c
blob6abb69b2e128b41b60c28010150ce2f0d4507d7f
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 "../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/tdb_wrap/tdb_wrap.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 tdb_wrap *open_schannel_session_store(TALLOC_CTX *mem_ctx,
41 struct loadparm_context *lp_ctx)
43 struct tdb_wrap *tdb_sc = NULL;
44 char *fname = lpcfg_private_path(mem_ctx, lp_ctx, "schannel_store.tdb");
46 if (!fname) {
47 return NULL;
50 tdb_sc = tdb_wrap_open(mem_ctx, fname, 0, TDB_CLEAR_IF_FIRST|TDB_NOSYNC, O_RDWR|O_CREAT, 0600, lp_ctx);
52 if (!tdb_sc) {
53 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
54 fname, strerror(errno)));
55 TALLOC_FREE(fname);
56 return NULL;
59 TALLOC_FREE(fname);
61 return tdb_sc;
64 /********************************************************************
65 ********************************************************************/
67 static
68 NTSTATUS schannel_store_session_key_tdb(struct tdb_wrap *tdb_sc,
69 TALLOC_CTX *mem_ctx,
70 struct netlogon_creds_CredentialState *creds)
72 enum ndr_err_code ndr_err;
73 DATA_BLOB blob;
74 TDB_DATA value;
75 int ret;
76 char *keystr;
77 char *name_upper;
79 name_upper = strupper_talloc(mem_ctx, creds->computer_name);
80 if (!name_upper) {
81 return NT_STATUS_NO_MEMORY;
84 keystr = talloc_asprintf(mem_ctx, "%s/%s",
85 SECRETS_SCHANNEL_STATE, name_upper);
86 TALLOC_FREE(name_upper);
87 if (!keystr) {
88 return NT_STATUS_NO_MEMORY;
91 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
92 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
93 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
94 talloc_free(keystr);
95 return ndr_map_error2ntstatus(ndr_err);
98 value.dptr = blob.data;
99 value.dsize = blob.length;
101 ret = tdb_store_bystring(tdb_sc->tdb, keystr, value, TDB_REPLACE);
102 if (ret != TDB_SUCCESS) {
103 DEBUG(0,("Unable to add %s to session key db - %s\n",
104 keystr, tdb_errorstr(tdb_sc->tdb)));
105 talloc_free(keystr);
106 return NT_STATUS_INTERNAL_DB_CORRUPTION;
109 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
110 keystr));
112 if (DEBUGLEVEL >= 10) {
113 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
116 talloc_free(keystr);
118 return NT_STATUS_OK;
121 /********************************************************************
122 ********************************************************************/
124 static
125 NTSTATUS schannel_fetch_session_key_tdb(struct tdb_wrap *tdb_sc,
126 TALLOC_CTX *mem_ctx,
127 const char *computer_name,
128 struct netlogon_creds_CredentialState **pcreds)
130 NTSTATUS status;
131 TDB_DATA value;
132 enum ndr_err_code ndr_err;
133 DATA_BLOB blob;
134 struct netlogon_creds_CredentialState *creds = NULL;
135 char *keystr = NULL;
136 char *name_upper;
138 *pcreds = NULL;
140 name_upper = strupper_talloc(mem_ctx, computer_name);
141 if (!name_upper) {
142 return NT_STATUS_NO_MEMORY;
145 keystr = talloc_asprintf(mem_ctx, "%s/%s",
146 SECRETS_SCHANNEL_STATE, name_upper);
147 TALLOC_FREE(name_upper);
148 if (!keystr) {
149 return NT_STATUS_NO_MEMORY;
152 value = tdb_fetch_bystring(tdb_sc->tdb, keystr);
153 if (!value.dptr) {
154 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
155 keystr ));
156 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
157 goto done;
160 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
161 if (!creds) {
162 status = NT_STATUS_NO_MEMORY;
163 goto done;
166 blob = data_blob_const(value.dptr, value.dsize);
168 ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
169 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
170 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
171 status = ndr_map_error2ntstatus(ndr_err);
172 goto done;
175 if (DEBUGLEVEL >= 10) {
176 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
179 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
180 keystr));
182 status = NT_STATUS_OK;
184 done:
186 talloc_free(keystr);
187 SAFE_FREE(value.dptr);
189 if (!NT_STATUS_IS_OK(status)) {
190 talloc_free(creds);
191 return status;
194 *pcreds = creds;
196 return NT_STATUS_OK;
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)
209 TALLOC_CTX *tmpctx;
210 struct tdb_wrap *tdb_sc;
211 struct netlogon_creds_CredentialState *creds;
212 NTSTATUS status;
214 tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
215 if (!tmpctx) {
216 return NT_STATUS_NO_MEMORY;
219 tdb_sc = open_schannel_session_store(tmpctx, lp_ctx);
220 if (!tdb_sc) {
221 return NT_STATUS_ACCESS_DENIED;
224 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx,
225 computer_name, &creds);
226 if (NT_STATUS_IS_OK(status)) {
227 *_creds = talloc_steal(mem_ctx, creds);
228 if (!*_creds) {
229 status = NT_STATUS_NO_MEMORY;
233 talloc_free(tmpctx);
234 return status;
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)
246 TALLOC_CTX *tmpctx;
247 struct tdb_wrap *tdb_sc;
248 NTSTATUS status;
250 tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
251 if (!tmpctx) {
252 return NT_STATUS_NO_MEMORY;
255 tdb_sc = open_schannel_session_store(tmpctx, lp_ctx);
256 if (!tdb_sc) {
257 return NT_STATUS_ACCESS_DENIED;
260 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
262 talloc_free(tmpctx);
263 return status;
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)
283 TALLOC_CTX *tmpctx;
284 struct tdb_wrap *tdb_sc;
285 struct netlogon_creds_CredentialState *creds;
286 NTSTATUS status;
287 int ret;
289 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
290 if (!tmpctx) {
291 return NT_STATUS_NO_MEMORY;
294 tdb_sc = open_schannel_session_store(tmpctx, lp_ctx);
295 if (!tdb_sc) {
296 status = NT_STATUS_ACCESS_DENIED;
297 goto done;
300 ret = tdb_transaction_start(tdb_sc->tdb);
301 if (ret != 0) {
302 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
303 goto done;
306 /* Because this is a shared structure (even across
307 * disconnects) we must update the database every time we
308 * update the structure */
310 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx,
311 computer_name, &creds);
312 if (!NT_STATUS_IS_OK(status)) {
313 tdb_transaction_cancel(tdb_sc->tdb);
314 goto done;
317 status = netlogon_creds_server_step_check(creds,
318 received_authenticator,
319 return_authenticator);
320 if (!NT_STATUS_IS_OK(status)) {
321 tdb_transaction_cancel(tdb_sc->tdb);
322 goto done;
325 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
326 if (!NT_STATUS_IS_OK(status)) {
327 tdb_transaction_cancel(tdb_sc->tdb);
328 goto done;
331 tdb_transaction_commit(tdb_sc->tdb);
333 if (creds_out) {
334 *creds_out = talloc_steal(mem_ctx, creds);
335 if (!*creds_out) {
336 status = NT_STATUS_NO_MEMORY;
337 goto done;
341 status = NT_STATUS_OK;
343 done:
344 talloc_free(tmpctx);
345 return status;