libcli/auth: reject computer_name longer than 15 chars
[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         if (strlen(creds->computer_name) > 15) {
82                 /*
83                  * We may want to check for a completely
84                  * valid netbios name.
85                  */
86                 return STATUS_BUFFER_OVERFLOW;
87         }
88
89         name_upper = strupper_talloc(mem_ctx, creds->computer_name);
90         if (!name_upper) {
91                 return NT_STATUS_NO_MEMORY;
92         }
93
94         keystr = talloc_asprintf(mem_ctx, "%s/%s",
95                                  SECRETS_SCHANNEL_STATE, name_upper);
96         TALLOC_FREE(name_upper);
97         if (!keystr) {
98                 return NT_STATUS_NO_MEMORY;
99         }
100
101         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
102                         (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
103         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
104                 talloc_free(keystr);
105                 return ndr_map_error2ntstatus(ndr_err);
106         }
107
108         value.dptr = blob.data;
109         value.dsize = blob.length;
110
111         status = dbwrap_store_bystring(db_sc, keystr, value, TDB_REPLACE);
112         if (!NT_STATUS_IS_OK(status)) {
113                 DEBUG(0,("Unable to add %s to session key db - %s\n",
114                          keystr, nt_errstr(status)));
115                 talloc_free(keystr);
116                 return status;
117         }
118
119         DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
120                 keystr));
121
122         if (DEBUGLEVEL >= 10) {
123                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
124         }
125
126         talloc_free(keystr);
127
128         return NT_STATUS_OK;
129 }
130
131 /********************************************************************
132  ********************************************************************/
133
134 static
135 NTSTATUS schannel_fetch_session_key_tdb(struct db_context *db_sc,
136                                         TALLOC_CTX *mem_ctx,
137                                         const char *computer_name,
138                                         struct netlogon_creds_CredentialState **pcreds)
139 {
140         NTSTATUS status;
141         TDB_DATA value;
142         enum ndr_err_code ndr_err;
143         DATA_BLOB blob;
144         struct netlogon_creds_CredentialState *creds = NULL;
145         char *keystr = NULL;
146         char *name_upper;
147
148         *pcreds = NULL;
149
150         name_upper = strupper_talloc(mem_ctx, computer_name);
151         if (!name_upper) {
152                 return NT_STATUS_NO_MEMORY;
153         }
154
155         keystr = talloc_asprintf(mem_ctx, "%s/%s",
156                                  SECRETS_SCHANNEL_STATE, name_upper);
157         TALLOC_FREE(name_upper);
158         if (!keystr) {
159                 return NT_STATUS_NO_MEMORY;
160         }
161
162         status = dbwrap_fetch_bystring(db_sc, keystr, keystr, &value);
163         if (!NT_STATUS_IS_OK(status)) {
164                 DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
165                         keystr ));
166                 goto done;
167         }
168
169         creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
170         if (!creds) {
171                 status = NT_STATUS_NO_MEMORY;
172                 goto done;
173         }
174
175         blob = data_blob_const(value.dptr, value.dsize);
176
177         ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
178                         (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
179         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
180                 status = ndr_map_error2ntstatus(ndr_err);
181                 goto done;
182         }
183
184         if (DEBUGLEVEL >= 10) {
185                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
186         }
187
188         DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
189                 keystr));
190
191         status = NT_STATUS_OK;
192
193  done:
194
195         talloc_free(keystr);
196
197         if (!NT_STATUS_IS_OK(status)) {
198                 talloc_free(creds);
199                 return status;
200         }
201
202         *pcreds = creds;
203
204         return NT_STATUS_OK;
205 }
206
207 /******************************************************************************
208  Wrapper around schannel_fetch_session_key_tdb()
209  Note we must be root here.
210 *******************************************************************************/
211
212 NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
213                                   struct loadparm_context *lp_ctx,
214                                   const char *computer_name,
215                                   struct netlogon_creds_CredentialState **_creds)
216 {
217         TALLOC_CTX *tmpctx;
218         struct db_context *db_sc;
219         struct netlogon_creds_CredentialState *creds;
220         NTSTATUS status;
221
222         tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
223         if (!tmpctx) {
224                 return NT_STATUS_NO_MEMORY;
225         }
226
227         db_sc = open_schannel_session_store(tmpctx, lp_ctx);
228         if (!db_sc) {
229                 return NT_STATUS_ACCESS_DENIED;
230         }
231
232         status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
233                                                 computer_name, &creds);
234         if (NT_STATUS_IS_OK(status)) {
235                 *_creds = talloc_steal(mem_ctx, creds);
236                 if (!*_creds) {
237                         status = NT_STATUS_NO_MEMORY;
238                 }
239         }
240
241         talloc_free(tmpctx);
242         return status;
243 }
244
245 /******************************************************************************
246  Wrapper around schannel_store_session_key_tdb()
247  Note we must be root here.
248 *******************************************************************************/
249
250 NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
251                                    struct loadparm_context *lp_ctx,
252                                    struct netlogon_creds_CredentialState *creds)
253 {
254         TALLOC_CTX *tmpctx;
255         struct db_context *db_sc;
256         NTSTATUS status;
257
258         tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
259         if (!tmpctx) {
260                 return NT_STATUS_NO_MEMORY;
261         }
262
263         db_sc = open_schannel_session_store(tmpctx, lp_ctx);
264         if (!db_sc) {
265                 return NT_STATUS_ACCESS_DENIED;
266         }
267
268         status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
269
270         talloc_free(tmpctx);
271         return status;
272 }
273
274 /********************************************************************
275  Validate an incoming authenticator against the credentials for the
276  remote machine stored in the schannel database.
277
278  The credentials are (re)read and from the schannel database, and
279  written back after the caclulations are performed.
280
281  If the creds_out parameter is not NULL returns the credentials.
282  ********************************************************************/
283
284 NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
285                                     struct loadparm_context *lp_ctx,
286                                     const char *computer_name,
287                                     struct netr_Authenticator *received_authenticator,
288                                     struct netr_Authenticator *return_authenticator,
289                                     struct netlogon_creds_CredentialState **creds_out)
290 {
291         TALLOC_CTX *tmpctx;
292         struct db_context *db_sc;
293         struct netlogon_creds_CredentialState *creds;
294         NTSTATUS status;
295         char *name_upper = NULL;
296         char *keystr = NULL;
297         struct db_record *record;
298         TDB_DATA key;
299
300         if (creds_out != NULL) {
301                 *creds_out = NULL;
302         }
303
304         tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
305         if (!tmpctx) {
306                 return NT_STATUS_NO_MEMORY;
307         }
308
309         name_upper = strupper_talloc(tmpctx, computer_name);
310         if (!name_upper) {
311                 status = NT_STATUS_NO_MEMORY;
312                 goto done;
313         }
314
315         keystr = talloc_asprintf(tmpctx, "%s/%s",
316                                  SECRETS_SCHANNEL_STATE, name_upper);
317         if (!keystr) {
318                 status = NT_STATUS_NO_MEMORY;
319                 goto done;
320         }
321
322         key = string_term_tdb_data(keystr);
323
324         db_sc = open_schannel_session_store(tmpctx, lp_ctx);
325         if (!db_sc) {
326                 status = NT_STATUS_ACCESS_DENIED;
327                 goto done;
328         }
329
330         record = dbwrap_fetch_locked(db_sc, tmpctx, key);
331         if (!record) {
332                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
333                 goto done;
334         }
335
336         /* Because this is a shared structure (even across
337          * disconnects) we must update the database every time we
338          * update the structure */
339
340         status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
341                                                 computer_name, &creds);
342         if (!NT_STATUS_IS_OK(status)) {
343                 goto done;
344         }
345
346         status = netlogon_creds_server_step_check(creds,
347                                                   received_authenticator,
348                                                   return_authenticator);
349         if (!NT_STATUS_IS_OK(status)) {
350                 goto done;
351         }
352
353         status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
354         if (!NT_STATUS_IS_OK(status)) {
355                 goto done;
356         }
357
358         if (creds_out) {
359                 *creds_out = talloc_steal(mem_ctx, creds);
360                 if (!*creds_out) {
361                         status = NT_STATUS_NO_MEMORY;
362                         goto done;
363                 }
364         }
365
366         status = NT_STATUS_OK;
367
368 done:
369         talloc_free(tmpctx);
370         return status;
371 }
372