libcli: Fixed a build warning for a missing prototype.
[Samba/gbeck.git] / libcli / auth / schannel_state_tdb.c
blob4b83a33c0d6b14253307c0d50f42663306c11519
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 "../libcli/auth/schannel_proto.h"
31 #include "../librpc/gen_ndr/ndr_schannel.h"
32 #if _SAMBA_BUILD_ == 4
33 #include "tdb_wrap.h"
34 #endif
36 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
38 /******************************************************************************
39 Open or create the schannel session store tdb. Non-static so it can
40 be called from parent processes to corectly handle TDB_CLEAR_IF_FIRST
41 *******************************************************************************/
43 struct tdb_wrap *open_schannel_session_store(TALLOC_CTX *mem_ctx,
44 const char *private_dir)
46 struct tdb_wrap *tdb_sc = NULL;
47 char *fname = talloc_asprintf(mem_ctx, "%s/schannel_store.tdb", private_dir);
49 if (!fname) {
50 return NULL;
53 tdb_sc = tdb_wrap_open(mem_ctx, fname, 0, TDB_CLEAR_IF_FIRST|TDB_NOSYNC, O_RDWR|O_CREAT, 0600);
55 if (!tdb_sc) {
56 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
57 fname, strerror(errno)));
58 TALLOC_FREE(fname);
59 return NULL;
62 TALLOC_FREE(fname);
64 return tdb_sc;
67 /********************************************************************
68 ********************************************************************/
70 static
71 NTSTATUS schannel_store_session_key_tdb(struct tdb_wrap *tdb_sc,
72 TALLOC_CTX *mem_ctx,
73 struct netlogon_creds_CredentialState *creds)
75 enum ndr_err_code ndr_err;
76 DATA_BLOB blob;
77 TDB_DATA value;
78 int ret;
79 char *keystr;
80 char *name_upper;
82 name_upper = strupper_talloc(mem_ctx, creds->computer_name);
83 if (!name_upper) {
84 return NT_STATUS_NO_MEMORY;
87 keystr = talloc_asprintf(mem_ctx, "%s/%s",
88 SECRETS_SCHANNEL_STATE, name_upper);
89 TALLOC_FREE(name_upper);
90 if (!keystr) {
91 return NT_STATUS_NO_MEMORY;
94 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
95 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
96 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
97 talloc_free(keystr);
98 return ndr_map_error2ntstatus(ndr_err);
101 value.dptr = blob.data;
102 value.dsize = blob.length;
104 ret = tdb_store_bystring(tdb_sc->tdb, keystr, value, TDB_REPLACE);
105 if (ret != TDB_SUCCESS) {
106 DEBUG(0,("Unable to add %s to session key db - %s\n",
107 keystr, tdb_errorstr(tdb_sc->tdb)));
108 talloc_free(keystr);
109 return NT_STATUS_INTERNAL_DB_CORRUPTION;
112 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
113 keystr));
115 if (DEBUGLEVEL >= 10) {
116 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
119 talloc_free(keystr);
121 return NT_STATUS_OK;
124 /********************************************************************
125 ********************************************************************/
127 static
128 NTSTATUS schannel_fetch_session_key_tdb(struct tdb_wrap *tdb_sc,
129 TALLOC_CTX *mem_ctx,
130 const char *computer_name,
131 struct netlogon_creds_CredentialState **pcreds)
133 NTSTATUS status;
134 TDB_DATA value;
135 enum ndr_err_code ndr_err;
136 DATA_BLOB blob;
137 struct netlogon_creds_CredentialState *creds = NULL;
138 char *keystr = NULL;
139 char *name_upper;
141 *pcreds = NULL;
143 name_upper = strupper_talloc(mem_ctx, computer_name);
144 if (!name_upper) {
145 return NT_STATUS_NO_MEMORY;
148 keystr = talloc_asprintf(mem_ctx, "%s/%s",
149 SECRETS_SCHANNEL_STATE, name_upper);
150 TALLOC_FREE(name_upper);
151 if (!keystr) {
152 return NT_STATUS_NO_MEMORY;
155 value = tdb_fetch_bystring(tdb_sc->tdb, keystr);
156 if (!value.dptr) {
157 DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
158 keystr ));
159 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
160 goto done;
163 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
164 if (!creds) {
165 status = NT_STATUS_NO_MEMORY;
166 goto done;
169 blob = data_blob_const(value.dptr, value.dsize);
171 ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
172 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
173 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
174 status = ndr_map_error2ntstatus(ndr_err);
175 goto done;
178 if (DEBUGLEVEL >= 10) {
179 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
182 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
183 keystr));
185 status = NT_STATUS_OK;
187 done:
189 talloc_free(keystr);
190 SAFE_FREE(value.dptr);
192 if (!NT_STATUS_IS_OK(status)) {
193 talloc_free(creds);
194 return status;
197 *pcreds = creds;
199 return NT_STATUS_OK;
202 /******************************************************************************
203 Wrapper around schannel_fetch_session_key_tdb()
204 Note we must be root here.
205 *******************************************************************************/
207 NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
208 const char *db_priv_dir,
209 const char *computer_name,
210 struct netlogon_creds_CredentialState **_creds)
212 TALLOC_CTX *tmpctx;
213 struct tdb_wrap *tdb_sc;
214 struct netlogon_creds_CredentialState *creds;
215 NTSTATUS status;
217 tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
218 if (!tmpctx) {
219 return NT_STATUS_NO_MEMORY;
222 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
223 if (!tdb_sc) {
224 return NT_STATUS_ACCESS_DENIED;
227 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx,
228 computer_name, &creds);
229 if (NT_STATUS_IS_OK(status)) {
230 *_creds = talloc_steal(mem_ctx, creds);
231 if (!*_creds) {
232 status = NT_STATUS_NO_MEMORY;
236 talloc_free(tmpctx);
237 return status;
240 /******************************************************************************
241 Wrapper around schannel_store_session_key_tdb()
242 Note we must be root here.
243 *******************************************************************************/
245 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
246 const char *db_priv_dir,
247 struct netlogon_creds_CredentialState *creds)
249 TALLOC_CTX *tmpctx;
250 struct tdb_wrap *tdb_sc;
251 NTSTATUS status;
253 tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
254 if (!tmpctx) {
255 return NT_STATUS_NO_MEMORY;
258 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
259 if (!tdb_sc) {
260 return NT_STATUS_ACCESS_DENIED;
263 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
265 talloc_free(tmpctx);
266 return status;
269 /********************************************************************
270 Validate an incoming authenticator against the credentials for the
271 remote machine stored in the schannel database.
273 The credentials are (re)read and from the schannel database, and
274 written back after the caclulations are performed.
276 If the creds_out parameter is not NULL returns the credentials.
277 ********************************************************************/
279 NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
280 const char *db_priv_dir,
281 const char *computer_name,
282 struct netr_Authenticator *received_authenticator,
283 struct netr_Authenticator *return_authenticator,
284 struct netlogon_creds_CredentialState **creds_out)
286 TALLOC_CTX *tmpctx;
287 struct tdb_wrap *tdb_sc;
288 struct netlogon_creds_CredentialState *creds;
289 NTSTATUS status;
290 int ret;
292 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
293 if (!tmpctx) {
294 return NT_STATUS_NO_MEMORY;
297 tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
298 if (!tdb_sc) {
299 status = NT_STATUS_ACCESS_DENIED;
300 goto done;
303 ret = tdb_transaction_start(tdb_sc->tdb);
304 if (ret != 0) {
305 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
306 goto done;
309 /* Because this is a shared structure (even across
310 * disconnects) we must update the database every time we
311 * update the structure */
313 status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx,
314 computer_name, &creds);
315 if (!NT_STATUS_IS_OK(status)) {
316 tdb_transaction_cancel(tdb_sc->tdb);
317 goto done;
320 status = netlogon_creds_server_step_check(creds,
321 received_authenticator,
322 return_authenticator);
323 if (!NT_STATUS_IS_OK(status)) {
324 tdb_transaction_cancel(tdb_sc->tdb);
325 goto done;
328 status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
329 if (!NT_STATUS_IS_OK(status)) {
330 tdb_transaction_cancel(tdb_sc->tdb);
331 goto done;
334 tdb_transaction_commit(tdb_sc->tdb);
336 if (creds_out) {
337 *creds_out = talloc_steal(mem_ctx, creds);
338 if (!*creds_out) {
339 status = NT_STATUS_NO_MEMORY;
340 goto done;
344 status = NT_STATUS_OK;
346 done:
347 talloc_free(tmpctx);
348 return status;