libcli/auth: convert to dbwrap.
[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_path(mem_ctx, lp_ctx, "schannel_store.tdb");
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         int ret;
288         char *name_upper = NULL;
289         char *keystr = NULL;
290         struct db_record *record;
291         TDB_DATA key;
292
293         if (creds_out != NULL) {
294                 *creds_out = NULL;
295         }
296
297         tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
298         if (!tmpctx) {
299                 return NT_STATUS_NO_MEMORY;
300         }
301
302         name_upper = strupper_talloc(tmpctx, computer_name);
303         if (!name_upper) {
304                 status = NT_STATUS_NO_MEMORY;
305                 goto done;
306         }
307
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;
313         }
314
315         key = string_term_tdb_data(keystr);
316
317         db_sc = open_schannel_session_store(tmpctx, lp_ctx);
318         if (!db_sc) {
319                 status = NT_STATUS_ACCESS_DENIED;
320                 goto done;
321         }
322
323         record = dbwrap_fetch_locked(db_sc, tmpctx, key);
324         if (!record) {
325                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
326                 goto done;
327         }
328
329         /* Because this is a shared structure (even across
330          * disconnects) we must update the database every time we
331          * update the structure */
332
333         status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
334                                                 computer_name, &creds);
335         if (!NT_STATUS_IS_OK(status)) {
336                 goto done;
337         }
338
339         status = netlogon_creds_server_step_check(creds,
340                                                   received_authenticator,
341                                                   return_authenticator);
342         if (!NT_STATUS_IS_OK(status)) {
343                 goto done;
344         }
345
346         status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
347         if (!NT_STATUS_IS_OK(status)) {
348                 goto done;
349         }
350
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;
356                 }
357         }
358
359         status = NT_STATUS_OK;
360
361 done:
362         talloc_free(tmpctx);
363         return status;
364 }
365