s3:vfs_commit: fix build
[Samba.git] / libcli / auth / schannel_state_tdb.c
blobca35a11abe09f6420eec33c73447caa6b3b78e9e
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/schannel.h"
29 #include "../librpc/gen_ndr/ndr_schannel.h"
30 #include "lib/util/tdb_wrap.h"
32 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
34 /******************************************************************************
35 Open or create the schannel session store tdb. Non-static so it can
36 be called from parent processes to corectly handle TDB_CLEAR_IF_FIRST
37 *******************************************************************************/
39 struct tdb_wrap *open_schannel_session_store(TALLOC_CTX *mem_ctx,
40 const char *private_dir)
42 struct tdb_wrap *tdb_sc = NULL;
43 char *fname = talloc_asprintf(mem_ctx, "%s/schannel_store.tdb", private_dir);
45 if (!fname) {
46 return NULL;
49 tdb_sc = tdb_wrap_open(mem_ctx, fname, 0, TDB_CLEAR_IF_FIRST|TDB_NOSYNC, O_RDWR|O_CREAT, 0600);
51 if (!tdb_sc) {
52 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
53 fname, strerror(errno)));
54 TALLOC_FREE(fname);
55 return NULL;
58 TALLOC_FREE(fname);
60 return tdb_sc;
63 /********************************************************************
64 ********************************************************************/
66 static
67 NTSTATUS schannel_store_session_key_tdb(struct tdb_wrap *tdb_sc,
68 TALLOC_CTX *mem_ctx,
69 struct netlogon_creds_CredentialState *creds)
71 enum ndr_err_code ndr_err;
72 DATA_BLOB blob;
73 TDB_DATA value;
74 int ret;
75 char *keystr;
76 char *name_upper;
78 name_upper = strupper_talloc(mem_ctx, creds->computer_name);
79 if (!name_upper) {
80 return NT_STATUS_NO_MEMORY;
83 keystr = talloc_asprintf(mem_ctx, "%s/%s",
84 SECRETS_SCHANNEL_STATE, name_upper);
85 TALLOC_FREE(name_upper);
86 if (!keystr) {
87 return NT_STATUS_NO_MEMORY;
90 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
91 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
92 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
93 talloc_free(keystr);
94 return ndr_map_error2ntstatus(ndr_err);
97 value.dptr = blob.data;
98 value.dsize = blob.length;
100 ret = tdb_store_bystring(tdb_sc->tdb, keystr, value, TDB_REPLACE);
101 if (ret != TDB_SUCCESS) {
102 DEBUG(0,("Unable to add %s to session key db - %s\n",
103 keystr, tdb_errorstr(tdb_sc->tdb)));
104 talloc_free(keystr);
105 return NT_STATUS_INTERNAL_DB_CORRUPTION;
108 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
109 keystr));
111 if (DEBUGLEVEL >= 10) {
112 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
115 talloc_free(keystr);
117 return NT_STATUS_OK;
120 /********************************************************************
121 ********************************************************************/
123 static
124 NTSTATUS schannel_fetch_session_key_tdb(struct tdb_wrap *tdb_sc,
125 TALLOC_CTX *mem_ctx,
126 const char *computer_name,
127 struct netlogon_creds_CredentialState **pcreds)
129 NTSTATUS status;
130 TDB_DATA value;
131 enum ndr_err_code ndr_err;
132 DATA_BLOB blob;
133 struct netlogon_creds_CredentialState *creds = NULL;
134 char *keystr = NULL;
135 char *name_upper;
137 *pcreds = NULL;
139 name_upper = strupper_talloc(mem_ctx, computer_name);
140 if (!name_upper) {
141 return NT_STATUS_NO_MEMORY;
144 keystr = talloc_asprintf(mem_ctx, "%s/%s",
145 SECRETS_SCHANNEL_STATE, name_upper);
146 TALLOC_FREE(name_upper);
147 if (!keystr) {
148 return NT_STATUS_NO_MEMORY;
151 value = tdb_fetch_bystring(tdb_sc->tdb, keystr);
152 if (!value.dptr) {
153 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
154 keystr ));
155 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
156 goto done;
159 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
160 if (!creds) {
161 status = NT_STATUS_NO_MEMORY;
162 goto done;
165 blob = data_blob_const(value.dptr, value.dsize);
167 ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
168 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
169 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
170 status = ndr_map_error2ntstatus(ndr_err);
171 goto done;
174 if (DEBUGLEVEL >= 10) {
175 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
178 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
179 keystr));
181 status = NT_STATUS_OK;
183 done:
185 talloc_free(keystr);
186 SAFE_FREE(value.dptr);
188 if (!NT_STATUS_IS_OK(status)) {
189 talloc_free(creds);
190 return status;
193 *pcreds = creds;
195 return NT_STATUS_OK;
198 /******************************************************************************
199 Wrapper around schannel_fetch_session_key_tdb()
200 Note we must be root here.
201 *******************************************************************************/
203 NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
204 const char *db_priv_dir,
205 const char *computer_name,
206 struct netlogon_creds_CredentialState **_creds)
208 TALLOC_CTX *tmpctx;
209 struct tdb_wrap *tdb_sc;
210 struct netlogon_creds_CredentialState *creds;
211 NTSTATUS status;
213 tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
214 if (!tmpctx) {
215 return NT_STATUS_NO_MEMORY;
218 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
219 if (!tdb_sc) {
220 return NT_STATUS_ACCESS_DENIED;
223 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx,
224 computer_name, &creds);
225 if (NT_STATUS_IS_OK(status)) {
226 *_creds = talloc_steal(mem_ctx, creds);
227 if (!*_creds) {
228 status = NT_STATUS_NO_MEMORY;
232 talloc_free(tmpctx);
233 return status;
236 /******************************************************************************
237 Wrapper around schannel_store_session_key_tdb()
238 Note we must be root here.
239 *******************************************************************************/
241 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
242 const char *db_priv_dir,
243 struct netlogon_creds_CredentialState *creds)
245 TALLOC_CTX *tmpctx;
246 struct tdb_wrap *tdb_sc;
247 NTSTATUS status;
249 tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
250 if (!tmpctx) {
251 return NT_STATUS_NO_MEMORY;
254 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
255 if (!tdb_sc) {
256 return NT_STATUS_ACCESS_DENIED;
259 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
261 talloc_free(tmpctx);
262 return status;
265 /********************************************************************
266 Validate an incoming authenticator against the credentials for the
267 remote machine stored in the schannel database.
269 The credentials are (re)read and from the schannel database, and
270 written back after the caclulations are performed.
272 If the creds_out parameter is not NULL returns the credentials.
273 ********************************************************************/
275 NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
276 const char *db_priv_dir,
277 const char *computer_name,
278 struct netr_Authenticator *received_authenticator,
279 struct netr_Authenticator *return_authenticator,
280 struct netlogon_creds_CredentialState **creds_out)
282 TALLOC_CTX *tmpctx;
283 struct tdb_wrap *tdb_sc;
284 struct netlogon_creds_CredentialState *creds;
285 NTSTATUS status;
286 int ret;
288 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
289 if (!tmpctx) {
290 return NT_STATUS_NO_MEMORY;
293 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
294 if (!tdb_sc) {
295 status = NT_STATUS_ACCESS_DENIED;
296 goto done;
299 ret = tdb_transaction_start(tdb_sc->tdb);
300 if (ret != 0) {
301 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
302 goto done;
305 /* Because this is a shared structure (even across
306 * disconnects) we must update the database every time we
307 * update the structure */
309 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx,
310 computer_name, &creds);
311 if (!NT_STATUS_IS_OK(status)) {
312 tdb_transaction_cancel(tdb_sc->tdb);
313 goto done;
316 status = netlogon_creds_server_step_check(creds,
317 received_authenticator,
318 return_authenticator);
319 if (!NT_STATUS_IS_OK(status)) {
320 tdb_transaction_cancel(tdb_sc->tdb);
321 goto done;
324 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
325 if (!NT_STATUS_IS_OK(status)) {
326 tdb_transaction_cancel(tdb_sc->tdb);
327 goto done;
330 tdb_transaction_commit(tdb_sc->tdb);
332 if (creds_out) {
333 *creds_out = talloc_steal(mem_ctx, creds);
334 if (!*creds_out) {
335 status = NT_STATUS_NO_MEMORY;
336 goto done;
340 status = NT_STATUS_OK;
342 done:
343 talloc_free(tmpctx);
344 return status;