vfs: update a bit-rotten comment
[Samba.git] / libcli / auth / schannel_state_tdb.c
blob2d3481d66f847305af5fad04c236961448ae21c9
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, DBWRAP_LOCK_ORDER_NONE,
53 DBWRAP_FLAG_NONE);
55 if (!db_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 db_sc;
67 /********************************************************************
68 ********************************************************************/
70 static
71 NTSTATUS schannel_store_session_key_tdb(struct db_context *db_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 char *keystr;
79 char *name_upper;
80 NTSTATUS status;
82 if (strlen(creds->computer_name) > 15) {
84 * We may want to check for a completely
85 * valid netbios name.
87 return STATUS_BUFFER_OVERFLOW;
90 name_upper = strupper_talloc(mem_ctx, creds->computer_name);
91 if (!name_upper) {
92 return NT_STATUS_NO_MEMORY;
95 keystr = talloc_asprintf(mem_ctx, "%s/%s",
96 SECRETS_SCHANNEL_STATE, name_upper);
97 TALLOC_FREE(name_upper);
98 if (!keystr) {
99 return NT_STATUS_NO_MEMORY;
102 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
103 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
104 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
105 talloc_free(keystr);
106 return ndr_map_error2ntstatus(ndr_err);
109 value.dptr = blob.data;
110 value.dsize = blob.length;
112 status = dbwrap_store_bystring(db_sc, keystr, value, TDB_REPLACE);
113 if (!NT_STATUS_IS_OK(status)) {
114 DEBUG(0,("Unable to add %s to session key db - %s\n",
115 keystr, nt_errstr(status)));
116 talloc_free(keystr);
117 return status;
120 DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
121 keystr));
123 if (DEBUGLEVEL >= 10) {
124 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
127 talloc_free(keystr);
129 return NT_STATUS_OK;
132 /********************************************************************
133 ********************************************************************/
135 static
136 NTSTATUS schannel_fetch_session_key_tdb(struct db_context *db_sc,
137 TALLOC_CTX *mem_ctx,
138 const char *computer_name,
139 struct netlogon_creds_CredentialState **pcreds)
141 NTSTATUS status;
142 TDB_DATA value;
143 enum ndr_err_code ndr_err;
144 DATA_BLOB blob;
145 struct netlogon_creds_CredentialState *creds = NULL;
146 char *keystr = NULL;
147 char *name_upper;
149 *pcreds = NULL;
151 name_upper = strupper_talloc(mem_ctx, computer_name);
152 if (!name_upper) {
153 return NT_STATUS_NO_MEMORY;
156 keystr = talloc_asprintf(mem_ctx, "%s/%s",
157 SECRETS_SCHANNEL_STATE, name_upper);
158 TALLOC_FREE(name_upper);
159 if (!keystr) {
160 return NT_STATUS_NO_MEMORY;
163 status = dbwrap_fetch_bystring(db_sc, keystr, keystr, &value);
164 if (!NT_STATUS_IS_OK(status)) {
165 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
166 keystr ));
167 goto done;
170 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
171 if (!creds) {
172 status = NT_STATUS_NO_MEMORY;
173 goto done;
176 blob = data_blob_const(value.dptr, value.dsize);
178 ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
179 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
180 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
181 status = ndr_map_error2ntstatus(ndr_err);
182 goto done;
185 if (DEBUGLEVEL >= 10) {
186 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
189 DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
190 keystr));
192 status = NT_STATUS_OK;
194 done:
196 talloc_free(keystr);
198 if (!NT_STATUS_IS_OK(status)) {
199 talloc_free(creds);
200 return status;
203 *pcreds = creds;
205 return NT_STATUS_OK;
208 /******************************************************************************
209 Wrapper around schannel_fetch_session_key_tdb()
210 Note we must be root here.
211 *******************************************************************************/
213 NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
214 struct loadparm_context *lp_ctx,
215 const char *computer_name,
216 struct netlogon_creds_CredentialState **_creds)
218 TALLOC_CTX *tmpctx;
219 struct db_context *db_sc;
220 struct netlogon_creds_CredentialState *creds;
221 NTSTATUS status;
223 tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
224 if (!tmpctx) {
225 return NT_STATUS_NO_MEMORY;
228 db_sc = open_schannel_session_store(tmpctx, lp_ctx);
229 if (!db_sc) {
230 return NT_STATUS_ACCESS_DENIED;
233 status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
234 computer_name, &creds);
235 if (NT_STATUS_IS_OK(status)) {
236 *_creds = talloc_steal(mem_ctx, creds);
237 if (!*_creds) {
238 status = NT_STATUS_NO_MEMORY;
242 talloc_free(tmpctx);
243 return status;
246 /******************************************************************************
247 Wrapper around schannel_store_session_key_tdb()
248 Note we must be root here.
249 *******************************************************************************/
251 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
252 struct loadparm_context *lp_ctx,
253 struct netlogon_creds_CredentialState *creds)
255 TALLOC_CTX *tmpctx;
256 struct db_context *db_sc;
257 NTSTATUS status;
259 tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
260 if (!tmpctx) {
261 return NT_STATUS_NO_MEMORY;
264 db_sc = open_schannel_session_store(tmpctx, lp_ctx);
265 if (!db_sc) {
266 return NT_STATUS_ACCESS_DENIED;
269 status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
271 talloc_free(tmpctx);
272 return status;
275 /********************************************************************
276 Validate an incoming authenticator against the credentials for the
277 remote machine stored in the schannel database.
279 The credentials are (re)read and from the schannel database, and
280 written back after the caclulations are performed.
282 If the creds_out parameter is not NULL returns the credentials.
283 ********************************************************************/
285 NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
286 struct loadparm_context *lp_ctx,
287 const char *computer_name,
288 struct netr_Authenticator *received_authenticator,
289 struct netr_Authenticator *return_authenticator,
290 struct netlogon_creds_CredentialState **creds_out)
292 TALLOC_CTX *tmpctx;
293 struct db_context *db_sc;
294 struct netlogon_creds_CredentialState *creds;
295 NTSTATUS status;
296 char *name_upper = NULL;
297 char *keystr = NULL;
298 struct db_record *record;
299 TDB_DATA key;
301 if (creds_out != NULL) {
302 *creds_out = NULL;
305 tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
306 if (!tmpctx) {
307 return NT_STATUS_NO_MEMORY;
310 name_upper = strupper_talloc(tmpctx, computer_name);
311 if (!name_upper) {
312 status = NT_STATUS_NO_MEMORY;
313 goto done;
316 keystr = talloc_asprintf(tmpctx, "%s/%s",
317 SECRETS_SCHANNEL_STATE, name_upper);
318 if (!keystr) {
319 status = NT_STATUS_NO_MEMORY;
320 goto done;
323 key = string_term_tdb_data(keystr);
325 db_sc = open_schannel_session_store(tmpctx, lp_ctx);
326 if (!db_sc) {
327 status = NT_STATUS_ACCESS_DENIED;
328 goto done;
331 record = dbwrap_fetch_locked(db_sc, tmpctx, key);
332 if (!record) {
333 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
334 goto done;
337 /* Because this is a shared structure (even across
338 * disconnects) we must update the database every time we
339 * update the structure */
341 status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
342 computer_name, &creds);
343 if (!NT_STATUS_IS_OK(status)) {
344 goto done;
347 status = netlogon_creds_server_step_check(creds,
348 received_authenticator,
349 return_authenticator);
350 if (!NT_STATUS_IS_OK(status)) {
351 goto done;
354 status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
355 if (!NT_STATUS_IS_OK(status)) {
356 goto done;
359 if (creds_out) {
360 *creds_out = talloc_steal(mem_ctx, creds);
361 if (!*creds_out) {
362 status = NT_STATUS_NO_MEMORY;
363 goto done;
367 status = NT_STATUS_OK;
369 done:
370 talloc_free(tmpctx);
371 return status;