s3-waf: enable nss_winbind in make test for nss_wrapper.
[amitay/samba.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 <tdb.h>
27 #include "../lib/util/util_tdb.h"
28 #include "../libcli/auth/schannel.h"
29 #include "../librpc/gen_ndr/ndr_schannel.h"
30 #if _SAMBA_BUILD_ == 4
31 #include "tdb_wrap.h"
32 #endif
33
34 #define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
35
36 /******************************************************************************
37  Open or create the schannel session store tdb.  Non-static so it can
38  be called from parent processes to corectly handle TDB_CLEAR_IF_FIRST
39 *******************************************************************************/
40
41 struct tdb_wrap *open_schannel_session_store(TALLOC_CTX *mem_ctx,
42                                              const char *private_dir)
43 {
44         struct tdb_wrap *tdb_sc = NULL;
45         char *fname = talloc_asprintf(mem_ctx, "%s/schannel_store.tdb", private_dir);
46
47         if (!fname) {
48                 return NULL;
49         }
50
51         tdb_sc = tdb_wrap_open(mem_ctx, fname, 0, TDB_CLEAR_IF_FIRST|TDB_NOSYNC, O_RDWR|O_CREAT, 0600);
52
53         if (!tdb_sc) {
54                 DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
55                          fname, strerror(errno)));
56                 TALLOC_FREE(fname);
57                 return NULL;
58         }
59
60         TALLOC_FREE(fname);
61
62         return tdb_sc;
63 }
64
65 /********************************************************************
66  ********************************************************************/
67
68 static
69 NTSTATUS schannel_store_session_key_tdb(struct tdb_wrap *tdb_sc,
70                                         TALLOC_CTX *mem_ctx,
71                                         struct netlogon_creds_CredentialState *creds)
72 {
73         enum ndr_err_code ndr_err;
74         DATA_BLOB blob;
75         TDB_DATA value;
76         int ret;
77         char *keystr;
78         char *name_upper;
79
80         name_upper = strupper_talloc(mem_ctx, creds->computer_name);
81         if (!name_upper) {
82                 return NT_STATUS_NO_MEMORY;
83         }
84
85         keystr = talloc_asprintf(mem_ctx, "%s/%s",
86                                  SECRETS_SCHANNEL_STATE, name_upper);
87         TALLOC_FREE(name_upper);
88         if (!keystr) {
89                 return NT_STATUS_NO_MEMORY;
90         }
91
92         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
93                         (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
94         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
95                 talloc_free(keystr);
96                 return ndr_map_error2ntstatus(ndr_err);
97         }
98
99         value.dptr = blob.data;
100         value.dsize = blob.length;
101
102         ret = tdb_store_bystring(tdb_sc->tdb, keystr, value, TDB_REPLACE);
103         if (ret != TDB_SUCCESS) {
104                 DEBUG(0,("Unable to add %s to session key db - %s\n",
105                          keystr, tdb_errorstr(tdb_sc->tdb)));
106                 talloc_free(keystr);
107                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
108         }
109
110         DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
111                 keystr));
112
113         if (DEBUGLEVEL >= 10) {
114                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
115         }
116
117         talloc_free(keystr);
118
119         return NT_STATUS_OK;
120 }
121
122 /********************************************************************
123  ********************************************************************/
124
125 static
126 NTSTATUS schannel_fetch_session_key_tdb(struct tdb_wrap *tdb_sc,
127                                         TALLOC_CTX *mem_ctx,
128                                         const char *computer_name,
129                                         struct netlogon_creds_CredentialState **pcreds)
130 {
131         NTSTATUS status;
132         TDB_DATA value;
133         enum ndr_err_code ndr_err;
134         DATA_BLOB blob;
135         struct netlogon_creds_CredentialState *creds = NULL;
136         char *keystr = NULL;
137         char *name_upper;
138
139         *pcreds = NULL;
140
141         name_upper = strupper_talloc(mem_ctx, computer_name);
142         if (!name_upper) {
143                 return NT_STATUS_NO_MEMORY;
144         }
145
146         keystr = talloc_asprintf(mem_ctx, "%s/%s",
147                                  SECRETS_SCHANNEL_STATE, name_upper);
148         TALLOC_FREE(name_upper);
149         if (!keystr) {
150                 return NT_STATUS_NO_MEMORY;
151         }
152
153         value = tdb_fetch_bystring(tdb_sc->tdb, keystr);
154         if (!value.dptr) {
155                 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
156                         keystr ));
157                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
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         SAFE_FREE(value.dptr);
189
190         if (!NT_STATUS_IS_OK(status)) {
191                 talloc_free(creds);
192                 return status;
193         }
194
195         *pcreds = creds;
196
197         return NT_STATUS_OK;
198 }
199
200 /******************************************************************************
201  Wrapper around schannel_fetch_session_key_tdb()
202  Note we must be root here.
203 *******************************************************************************/
204
205 NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
206                                   const char *db_priv_dir,
207                                   const char *computer_name,
208                                   struct netlogon_creds_CredentialState **_creds)
209 {
210         TALLOC_CTX *tmpctx;
211         struct tdb_wrap *tdb_sc;
212         struct netlogon_creds_CredentialState *creds;
213         NTSTATUS status;
214
215         tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
216         if (!tmpctx) {
217                 return NT_STATUS_NO_MEMORY;
218         }
219
220         tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
221         if (!tdb_sc) {
222                 return NT_STATUS_ACCESS_DENIED;
223         }
224
225         status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx, 
226                                                 computer_name, &creds);
227         if (NT_STATUS_IS_OK(status)) {
228                 *_creds = talloc_steal(mem_ctx, creds);
229                 if (!*_creds) {
230                         status = NT_STATUS_NO_MEMORY;
231                 }
232         }
233
234         talloc_free(tmpctx);
235         return status;
236 }
237
238 /******************************************************************************
239  Wrapper around schannel_store_session_key_tdb()
240  Note we must be root here.
241 *******************************************************************************/
242
243 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
244                                    const char *db_priv_dir,
245                                    struct netlogon_creds_CredentialState *creds)
246 {
247         TALLOC_CTX *tmpctx;
248         struct tdb_wrap *tdb_sc;
249         NTSTATUS status;
250
251         tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
252         if (!tmpctx) {
253                 return NT_STATUS_NO_MEMORY;
254         }
255
256         tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
257         if (!tdb_sc) {
258                 return NT_STATUS_ACCESS_DENIED;
259         }
260
261         status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
262
263         talloc_free(tmpctx);
264         return status;
265 }
266
267 /********************************************************************
268  Validate an incoming authenticator against the credentials for the
269  remote machine stored in the schannel database.
270
271  The credentials are (re)read and from the schannel database, and
272  written back after the caclulations are performed.
273
274  If the creds_out parameter is not NULL returns the credentials.
275  ********************************************************************/
276
277 NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
278                                     const char *db_priv_dir,
279                                     const char *computer_name,
280                                     struct netr_Authenticator *received_authenticator,
281                                     struct netr_Authenticator *return_authenticator,
282                                     struct netlogon_creds_CredentialState **creds_out)
283 {
284         TALLOC_CTX *tmpctx;
285         struct tdb_wrap *tdb_sc;
286         struct netlogon_creds_CredentialState *creds;
287         NTSTATUS status;
288         int ret;
289
290         tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
291         if (!tmpctx) {
292                 return NT_STATUS_NO_MEMORY;
293         }
294
295         tdb_sc = open_schannel_session_store(tmpctx, db_priv_dir);
296         if (!tdb_sc) {
297                 status = NT_STATUS_ACCESS_DENIED;
298                 goto done;
299         }
300
301         ret = tdb_transaction_start(tdb_sc->tdb);
302         if (ret != 0) {
303                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
304                 goto done;
305         }
306
307         /* Because this is a shared structure (even across
308          * disconnects) we must update the database every time we
309          * update the structure */
310
311         status = schannel_fetch_session_key_tdb(tdb_sc, tmpctx, 
312                                                 computer_name, &creds);
313         if (!NT_STATUS_IS_OK(status)) {
314                 tdb_transaction_cancel(tdb_sc->tdb);
315                 goto done;
316         }
317
318         status = netlogon_creds_server_step_check(creds,
319                                                   received_authenticator,
320                                                   return_authenticator);
321         if (!NT_STATUS_IS_OK(status)) {
322                 tdb_transaction_cancel(tdb_sc->tdb);
323                 goto done;
324         }
325
326         status = schannel_store_session_key_tdb(tdb_sc, tmpctx, creds);
327         if (!NT_STATUS_IS_OK(status)) {
328                 tdb_transaction_cancel(tdb_sc->tdb);
329                 goto done;
330         }
331
332         tdb_transaction_commit(tdb_sc->tdb);
333
334         if (creds_out) {
335                 *creds_out = talloc_steal(mem_ctx, creds);
336                 if (!*creds_out) {
337                         status = NT_STATUS_NO_MEMORY;
338                         goto done;
339                 }
340         }
341
342         status = NT_STATUS_OK;
343
344 done:
345         talloc_free(tmpctx);
346         return status;
347 }
348