schannel: Fix an unused variable
[metze/samba/wip.git] / libcli / auth / schannel_state_tdb.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    module to store/fetch session keys for the schannel server
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2009
8    Copyright (C) Guenther Deschner 2009
9
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.
14
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.
19
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/>.
22 */
23
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"
32
33 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
34
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 *******************************************************************************/
39
40 struct db_context *open_schannel_session_store(TALLOC_CTX *mem_ctx,
41                                                struct loadparm_context *lp_ctx)
42 {
43         struct db_context *db_sc = NULL;
44         char *fname = lpcfg_private_db_path(mem_ctx, lp_ctx, "schannel_store");
45
46         if (!fname) {
47                 return NULL;
48         }
49
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);
53
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;
59         }
60
61         TALLOC_FREE(fname);
62
63         return db_sc;
64 }
65
66 /********************************************************************
67  ********************************************************************/
68
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)
73 {
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;
80
81         name_upper = strupper_talloc(mem_ctx, creds->computer_name);
82         if (!name_upper) {
83                 return NT_STATUS_NO_MEMORY;
84         }
85
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;
91         }
92
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);
98         }
99
100         value.dptr = blob.data;
101         value.dsize = blob.length;
102
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;
109         }
110
111         DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
112                 keystr));
113
114         if (DEBUGLEVEL >= 10) {
115                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
116         }
117
118         talloc_free(keystr);
119
120         return NT_STATUS_OK;
121 }
122
123 /********************************************************************
124  ********************************************************************/
125
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)
131 {
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;
139
140         *pcreds = NULL;
141
142         name_upper = strupper_talloc(mem_ctx, computer_name);
143         if (!name_upper) {
144                 return NT_STATUS_NO_MEMORY;
145         }
146
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;
152         }
153
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;
159         }
160
161         creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
162         if (!creds) {
163                 status = NT_STATUS_NO_MEMORY;
164                 goto done;
165         }
166
167         blob = data_blob_const(value.dptr, value.dsize);
168
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;
174         }
175
176         if (DEBUGLEVEL >= 10) {
177                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
178         }
179
180         DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
181                 keystr));
182
183         status = NT_STATUS_OK;
184
185  done:
186
187         talloc_free(keystr);
188
189         if (!NT_STATUS_IS_OK(status)) {
190                 talloc_free(creds);
191                 return status;
192         }
193
194         *pcreds = creds;
195
196         return NT_STATUS_OK;
197 }
198
199 /******************************************************************************
200  Wrapper around schannel_fetch_session_key_tdb()
201  Note we must be root here.
202 *******************************************************************************/
203
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)
208 {
209         TALLOC_CTX *tmpctx;
210         struct db_context *db_sc;
211         struct netlogon_creds_CredentialState *creds;
212         NTSTATUS status;
213
214         tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
215         if (!tmpctx) {
216                 return NT_STATUS_NO_MEMORY;
217         }
218
219         db_sc = open_schannel_session_store(tmpctx, lp_ctx);
220         if (!db_sc) {
221                 return NT_STATUS_ACCESS_DENIED;
222         }
223
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;
230                 }
231         }
232
233         talloc_free(tmpctx);
234         return status;
235 }
236
237 /******************************************************************************
238  Wrapper around schannel_store_session_key_tdb()
239  Note we must be root here.
240 *******************************************************************************/
241
242 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
243                                    struct loadparm_context *lp_ctx,
244                                    struct netlogon_creds_CredentialState *creds)
245 {
246         TALLOC_CTX *tmpctx;
247         struct db_context *db_sc;
248         NTSTATUS status;
249
250         tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
251         if (!tmpctx) {
252                 return NT_STATUS_NO_MEMORY;
253         }
254
255         db_sc = open_schannel_session_store(tmpctx, lp_ctx);
256         if (!db_sc) {
257                 return NT_STATUS_ACCESS_DENIED;
258         }
259
260         status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
261
262         talloc_free(tmpctx);
263         return status;
264 }
265
266 /********************************************************************
267  Validate an incoming authenticator against the credentials for the
268  remote machine stored in the schannel database.
269
270  The credentials are (re)read and from the schannel database, and
271  written back after the caclulations are performed.
272
273  If the creds_out parameter is not NULL returns the credentials.
274  ********************************************************************/
275
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)
282 {
283         TALLOC_CTX *tmpctx;
284         struct db_context *db_sc;
285         struct netlogon_creds_CredentialState *creds;
286         NTSTATUS status;
287         char *name_upper = NULL;
288         char *keystr = NULL;
289         struct db_record *record;
290         TDB_DATA key;
291
292         if (creds_out != NULL) {
293                 *creds_out = NULL;
294         }
295
296         tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
297         if (!tmpctx) {
298                 return NT_STATUS_NO_MEMORY;
299         }
300
301         name_upper = strupper_talloc(tmpctx, computer_name);
302         if (!name_upper) {
303                 status = NT_STATUS_NO_MEMORY;
304                 goto done;
305         }
306
307         keystr = talloc_asprintf(tmpctx, "%s/%s",
308                                  SECRETS_SCHANNEL_STATE, name_upper);
309         if (!keystr) {
310                 status = NT_STATUS_NO_MEMORY;
311                 goto done;
312         }
313
314         key = string_term_tdb_data(keystr);
315
316         db_sc = open_schannel_session_store(tmpctx, lp_ctx);
317         if (!db_sc) {
318                 status = NT_STATUS_ACCESS_DENIED;
319                 goto done;
320         }
321
322         record = dbwrap_fetch_locked(db_sc, tmpctx, key);
323         if (!record) {
324                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
325                 goto done;
326         }
327
328         /* Because this is a shared structure (even across
329          * disconnects) we must update the database every time we
330          * update the structure */
331
332         status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
333                                                 computer_name, &creds);
334         if (!NT_STATUS_IS_OK(status)) {
335                 goto done;
336         }
337
338         status = netlogon_creds_server_step_check(creds,
339                                                   received_authenticator,
340                                                   return_authenticator);
341         if (!NT_STATUS_IS_OK(status)) {
342                 goto done;
343         }
344
345         status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
346         if (!NT_STATUS_IS_OK(status)) {
347                 goto done;
348         }
349
350         if (creds_out) {
351                 *creds_out = talloc_steal(mem_ctx, creds);
352                 if (!*creds_out) {
353                         status = NT_STATUS_NO_MEMORY;
354                         goto done;
355                 }
356         }
357
358         status = NT_STATUS_OK;
359
360 done:
361         talloc_free(tmpctx);
362         return status;
363 }
364