librpc: Shorten dcerpc_binding_handle_call a bit
[Samba/gebeck_regimport.git] / libcli / auth / schannel_state_tdb.c
blob8f9c1f0687a1edd19142f493328578a3000245a1
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/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");
46 if (!fname) {
47 return NULL;
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, 0);
54 if (!db_sc) {
55 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
56 fname, strerror(errno)));
57 TALLOC_FREE(fname);
58 return NULL;
61 TALLOC_FREE(fname);
63 return db_sc;
66 /********************************************************************
67 ********************************************************************/
69 static
70 NTSTATUS schannel_store_session_key_tdb(struct db_context *db_sc,
71 TALLOC_CTX *mem_ctx,
72 struct netlogon_creds_CredentialState *creds)
74 enum ndr_err_code ndr_err;
75 DATA_BLOB blob;
76 TDB_DATA value;
77 char *keystr;
78 char *name_upper;
79 NTSTATUS status;
81 name_upper = strupper_talloc(mem_ctx, creds->computer_name);
82 if (!name_upper) {
83 return NT_STATUS_NO_MEMORY;
86 keystr = talloc_asprintf(mem_ctx, "%s/%s",
87 SECRETS_SCHANNEL_STATE, name_upper);
88 TALLOC_FREE(name_upper);
89 if (!keystr) {
90 return NT_STATUS_NO_MEMORY;
93 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
94 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
95 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
96 talloc_free(keystr);
97 return ndr_map_error2ntstatus(ndr_err);
100 value.dptr = blob.data;
101 value.dsize = blob.length;
103 status = dbwrap_store_bystring(db_sc, keystr, value, TDB_REPLACE);
104 if (!NT_STATUS_IS_OK(status)) {
105 DEBUG(0,("Unable to add %s to session key db - %s\n",
106 keystr, nt_errstr(status)));
107 talloc_free(keystr);
108 return status;
111 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
112 keystr));
114 if (DEBUGLEVEL >= 10) {
115 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
118 talloc_free(keystr);
120 return NT_STATUS_OK;
123 /********************************************************************
124 ********************************************************************/
126 static
127 NTSTATUS schannel_fetch_session_key_tdb(struct db_context *db_sc,
128 TALLOC_CTX *mem_ctx,
129 const char *computer_name,
130 struct netlogon_creds_CredentialState **pcreds)
132 NTSTATUS status;
133 TDB_DATA value;
134 enum ndr_err_code ndr_err;
135 DATA_BLOB blob;
136 struct netlogon_creds_CredentialState *creds = NULL;
137 char *keystr = NULL;
138 char *name_upper;
140 *pcreds = NULL;
142 name_upper = strupper_talloc(mem_ctx, computer_name);
143 if (!name_upper) {
144 return NT_STATUS_NO_MEMORY;
147 keystr = talloc_asprintf(mem_ctx, "%s/%s",
148 SECRETS_SCHANNEL_STATE, name_upper);
149 TALLOC_FREE(name_upper);
150 if (!keystr) {
151 return NT_STATUS_NO_MEMORY;
154 status = dbwrap_fetch_bystring(db_sc, keystr, keystr, &value);
155 if (!NT_STATUS_IS_OK(status)) {
156 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
157 keystr ));
158 goto done;
161 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
162 if (!creds) {
163 status = NT_STATUS_NO_MEMORY;
164 goto done;
167 blob = data_blob_const(value.dptr, value.dsize);
169 ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
170 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
171 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
172 status = ndr_map_error2ntstatus(ndr_err);
173 goto done;
176 if (DEBUGLEVEL >= 10) {
177 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
180 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
181 keystr));
183 status = NT_STATUS_OK;
185 done:
187 talloc_free(keystr);
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 db_context *db_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 db_sc = open_schannel_session_store(tmpctx, lp_ctx);
220 if (!db_sc) {
221 return NT_STATUS_ACCESS_DENIED;
224 status = schannel_fetch_session_key_tdb(db_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 db_context *db_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 db_sc = open_schannel_session_store(tmpctx, lp_ctx);
256 if (!db_sc) {
257 return NT_STATUS_ACCESS_DENIED;
260 status = schannel_store_session_key_tdb(db_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 db_context *db_sc;
285 struct netlogon_creds_CredentialState *creds;
286 NTSTATUS status;
287 int ret;
288 char *name_upper = NULL;
289 char *keystr = NULL;
290 struct db_record *record;
291 TDB_DATA key;
293 if (creds_out != NULL) {
294 *creds_out = NULL;
297 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
298 if (!tmpctx) {
299 return NT_STATUS_NO_MEMORY;
302 name_upper = strupper_talloc(tmpctx, computer_name);
303 if (!name_upper) {
304 status = NT_STATUS_NO_MEMORY;
305 goto done;
308 keystr = talloc_asprintf(tmpctx, "%s/%s",
309 SECRETS_SCHANNEL_STATE, name_upper);
310 if (!keystr) {
311 status = NT_STATUS_NO_MEMORY;
312 goto done;
315 key = string_term_tdb_data(keystr);
317 db_sc = open_schannel_session_store(tmpctx, lp_ctx);
318 if (!db_sc) {
319 status = NT_STATUS_ACCESS_DENIED;
320 goto done;
323 record = dbwrap_fetch_locked(db_sc, tmpctx, key);
324 if (!record) {
325 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
326 goto done;
329 /* Because this is a shared structure (even across
330 * disconnects) we must update the database every time we
331 * update the structure */
333 status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
334 computer_name, &creds);
335 if (!NT_STATUS_IS_OK(status)) {
336 goto done;
339 status = netlogon_creds_server_step_check(creds,
340 received_authenticator,
341 return_authenticator);
342 if (!NT_STATUS_IS_OK(status)) {
343 goto done;
346 status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
347 if (!NT_STATUS_IS_OK(status)) {
348 goto done;
351 if (creds_out) {
352 *creds_out = talloc_steal(mem_ctx, creds);
353 if (!*creds_out) {
354 status = NT_STATUS_NO_MEMORY;
355 goto done;
359 status = NT_STATUS_OK;
361 done:
362 talloc_free(tmpctx);
363 return status;