Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Stefan Metzmacher 2014
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "system/filesys.h"
22 : #include <tevent.h>
23 : #include "lib/util/server_id.h"
24 : #include "smbd/smbd.h"
25 : #include "smbd/globals.h"
26 : #include "dbwrap/dbwrap.h"
27 : #include "dbwrap/dbwrap_rbt.h"
28 : #include "dbwrap/dbwrap_open.h"
29 : #include "dbwrap/dbwrap_watch.h"
30 : #include "session.h"
31 : #include "auth.h"
32 : #include "auth/gensec/gensec.h"
33 : #include "../lib/tsocket/tsocket.h"
34 : #include "../libcli/security/security.h"
35 : #include "messages.h"
36 : #include "lib/util/util_tdb.h"
37 : #include "librpc/gen_ndr/ndr_smbXsrv.h"
38 : #include "serverid.h"
39 : #include "lib/util/tevent_ntstatus.h"
40 : #include "lib/util/iov_buf.h"
41 : #include "lib/global_contexts.h"
42 :
43 : struct smbXsrv_client_table {
44 : struct {
45 : uint32_t max_clients;
46 : uint32_t num_clients;
47 : } local;
48 : struct {
49 : struct db_context *db_ctx;
50 : } global;
51 : };
52 :
53 : static struct db_context *smbXsrv_client_global_db_ctx = NULL;
54 :
55 27326 : NTSTATUS smbXsrv_client_global_init(void)
56 : {
57 27326 : const char *global_path = NULL;
58 27326 : struct db_context *backend = NULL;
59 27326 : struct db_context *db_ctx = NULL;
60 :
61 27326 : if (smbXsrv_client_global_db_ctx != NULL) {
62 27263 : return NT_STATUS_OK;
63 : }
64 :
65 : /*
66 : * This contains secret information like client keys!
67 : */
68 63 : global_path = lock_path(talloc_tos(), "smbXsrv_client_global.tdb");
69 63 : if (global_path == NULL) {
70 0 : return NT_STATUS_NO_MEMORY;
71 : }
72 :
73 63 : backend = db_open(NULL, global_path,
74 : 0, /* hash_size */
75 : TDB_DEFAULT |
76 : TDB_CLEAR_IF_FIRST |
77 : TDB_INCOMPATIBLE_HASH,
78 : O_RDWR | O_CREAT, 0600,
79 : DBWRAP_LOCK_ORDER_1,
80 : DBWRAP_FLAG_NONE);
81 63 : if (backend == NULL) {
82 : NTSTATUS status;
83 :
84 0 : status = map_nt_error_from_unix_common(errno);
85 :
86 0 : return status;
87 : }
88 :
89 63 : db_ctx = db_open_watched(NULL, &backend, global_messaging_context());
90 63 : if (db_ctx == NULL) {
91 0 : TALLOC_FREE(backend);
92 0 : return NT_STATUS_NO_MEMORY;
93 : }
94 :
95 63 : smbXsrv_client_global_db_ctx = db_ctx;
96 :
97 63 : return NT_STATUS_OK;
98 : }
99 :
100 : /*
101 : * NOTE:
102 : * We need to store the keys in big endian so that dbwrap_rbt's memcmp
103 : * has the same result as integer comparison between the uint32_t
104 : * values.
105 : *
106 : * TODO: implement string based key
107 : */
108 :
109 : #define SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE 16
110 :
111 42474 : static TDB_DATA smbXsrv_client_global_id_to_key(const struct GUID *client_guid,
112 : uint8_t *key_buf)
113 : {
114 42474 : TDB_DATA key = { .dsize = 0, };
115 : NTSTATUS status;
116 42474 : struct GUID_ndr_buf buf = { .buf = {0}, };
117 :
118 42474 : status = GUID_to_ndr_buf(client_guid, &buf);
119 42474 : if (!NT_STATUS_IS_OK(status)) {
120 0 : return key;
121 : }
122 42474 : memcpy(key_buf, buf.buf, SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE);
123 :
124 42474 : key = make_tdb_data(key_buf, SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE);
125 :
126 42474 : return key;
127 : }
128 :
129 42474 : static struct db_record *smbXsrv_client_global_fetch_locked(
130 : struct db_context *db,
131 : const struct GUID *client_guid,
132 : TALLOC_CTX *mem_ctx)
133 : {
134 : TDB_DATA key;
135 : uint8_t key_buf[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE];
136 42474 : struct db_record *rec = NULL;
137 :
138 42474 : key = smbXsrv_client_global_id_to_key(client_guid, key_buf);
139 :
140 42474 : rec = dbwrap_fetch_locked(db, mem_ctx, key);
141 :
142 42474 : if (rec == NULL) {
143 : struct GUID_txt_buf buf;
144 0 : DBG_DEBUG("Failed to lock guid [%s], key '%s'\n",
145 : GUID_buf_string(client_guid, &buf),
146 : hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
147 : }
148 :
149 42474 : return rec;
150 : }
151 :
152 27263 : static NTSTATUS smbXsrv_client_table_create(TALLOC_CTX *mem_ctx,
153 : struct messaging_context *msg_ctx,
154 : uint32_t max_clients,
155 : struct smbXsrv_client_table **_table)
156 : {
157 : struct smbXsrv_client_table *table;
158 : NTSTATUS status;
159 :
160 27263 : if (max_clients > 1) {
161 0 : return NT_STATUS_INTERNAL_ERROR;
162 : }
163 :
164 27263 : table = talloc_zero(mem_ctx, struct smbXsrv_client_table);
165 27263 : if (table == NULL) {
166 0 : return NT_STATUS_NO_MEMORY;
167 : }
168 :
169 27263 : table->local.max_clients = max_clients;
170 :
171 27263 : status = smbXsrv_client_global_init();
172 27263 : if (!NT_STATUS_IS_OK(status)) {
173 0 : TALLOC_FREE(table);
174 0 : return status;
175 : }
176 :
177 27263 : table->global.db_ctx = smbXsrv_client_global_db_ctx;
178 :
179 27263 : *_table = table;
180 27263 : return NT_STATUS_OK;
181 : }
182 :
183 27249 : static int smbXsrv_client_global_destructor(struct smbXsrv_client_global0 *global)
184 : {
185 27249 : return 0;
186 : }
187 :
188 21734 : static void smbXsrv_client_global_verify_record(struct db_record *db_rec,
189 : bool *is_free,
190 : bool *was_free,
191 : TALLOC_CTX *mem_ctx,
192 : struct smbXsrv_client_global0 **_g)
193 : {
194 : TDB_DATA key;
195 : TDB_DATA val;
196 : DATA_BLOB blob;
197 : struct smbXsrv_client_globalB global_blob;
198 : enum ndr_err_code ndr_err;
199 21734 : struct smbXsrv_client_global0 *global = NULL;
200 : bool exists;
201 21734 : TALLOC_CTX *frame = talloc_stackframe();
202 :
203 21734 : *is_free = false;
204 :
205 21734 : if (was_free) {
206 0 : *was_free = false;
207 : }
208 21734 : if (_g) {
209 21734 : *_g = NULL;
210 : }
211 :
212 21734 : key = dbwrap_record_get_key(db_rec);
213 :
214 21734 : val = dbwrap_record_get_value(db_rec);
215 21734 : if (val.dsize == 0) {
216 20742 : TALLOC_FREE(frame);
217 20742 : *is_free = true;
218 20742 : if (was_free) {
219 0 : *was_free = true;
220 : }
221 38115 : return;
222 : }
223 :
224 992 : blob = data_blob_const(val.dptr, val.dsize);
225 :
226 992 : ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
227 : (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_client_globalB);
228 992 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
229 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
230 0 : DBG_WARNING("smbXsrv_client_global_verify_record: "
231 : "key '%s' ndr_pull_struct_blob - %s\n",
232 : hex_encode_talloc(frame, key.dptr, key.dsize),
233 : nt_errstr(status));
234 0 : TALLOC_FREE(frame);
235 0 : return;
236 : }
237 :
238 992 : DBG_DEBUG("client_global:\n");
239 992 : if (DEBUGLVL(DBGLVL_DEBUG)) {
240 0 : NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
241 : }
242 :
243 992 : if (global_blob.version != SMBXSRV_VERSION_0) {
244 0 : DBG_ERR("key '%s' use unsupported version %u\n",
245 : hex_encode_talloc(frame, key.dptr, key.dsize),
246 : global_blob.version);
247 0 : NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
248 0 : TALLOC_FREE(frame);
249 0 : return;
250 : }
251 :
252 992 : global = global_blob.info.info0;
253 :
254 992 : exists = serverid_exists(&global->server_id);
255 992 : if (!exists) {
256 : struct server_id_buf tmp;
257 :
258 0 : DBG_NOTICE("key '%s' server_id %s does not exist.\n",
259 : hex_encode_talloc(frame, key.dptr, key.dsize),
260 : server_id_str_buf(global->server_id, &tmp));
261 0 : if (DEBUGLVL(DBGLVL_NOTICE)) {
262 0 : NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
263 : }
264 0 : TALLOC_FREE(frame);
265 0 : dbwrap_record_delete(db_rec);
266 0 : *is_free = true;
267 0 : return;
268 : }
269 :
270 992 : if (_g) {
271 992 : *_g = talloc_move(mem_ctx, &global);
272 : }
273 992 : TALLOC_FREE(frame);
274 : }
275 :
276 992 : static NTSTATUS smb2srv_client_connection_pass(struct smbd_smb2_request *smb2req,
277 : struct smbXsrv_client_global0 *global)
278 : {
279 : DATA_BLOB blob;
280 : enum ndr_err_code ndr_err;
281 : NTSTATUS status;
282 : struct smbXsrv_connection_pass0 pass_info0;
283 : struct smbXsrv_connection_passB pass_blob;
284 : ssize_t reqlen;
285 : struct iovec iov;
286 :
287 992 : pass_info0 = (struct smbXsrv_connection_pass0) {
288 992 : .client_guid = global->client_guid,
289 992 : .src_server_id = smb2req->xconn->client->global->server_id,
290 992 : .xconn_connect_time = smb2req->xconn->client->global->initial_connect_time,
291 992 : .dst_server_id = global->server_id,
292 992 : .client_connect_time = global->initial_connect_time,
293 : };
294 :
295 992 : reqlen = iov_buflen(smb2req->in.vector, smb2req->in.vector_count);
296 992 : if (reqlen == -1) {
297 0 : return NT_STATUS_INVALID_BUFFER_SIZE;
298 : }
299 :
300 992 : pass_info0.negotiate_request.length = reqlen;
301 992 : pass_info0.negotiate_request.data = talloc_array(talloc_tos(), uint8_t,
302 : reqlen);
303 992 : if (pass_info0.negotiate_request.data == NULL) {
304 0 : return NT_STATUS_NO_MEMORY;
305 : }
306 992 : iov_buf(smb2req->in.vector, smb2req->in.vector_count,
307 : pass_info0.negotiate_request.data,
308 : pass_info0.negotiate_request.length);
309 :
310 992 : ZERO_STRUCT(pass_blob);
311 992 : pass_blob.version = smbXsrv_version_global_current();
312 992 : pass_blob.info.info0 = &pass_info0;
313 :
314 992 : if (DEBUGLVL(DBGLVL_DEBUG)) {
315 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
316 : }
317 :
318 992 : ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &pass_blob,
319 : (ndr_push_flags_fn_t)ndr_push_smbXsrv_connection_passB);
320 992 : data_blob_free(&pass_info0.negotiate_request);
321 992 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
322 0 : status = ndr_map_error2ntstatus(ndr_err);
323 0 : return status;
324 : }
325 :
326 992 : iov.iov_base = blob.data;
327 992 : iov.iov_len = blob.length;
328 :
329 992 : status = messaging_send_iov(smb2req->xconn->client->msg_ctx,
330 : global->server_id,
331 : MSG_SMBXSRV_CONNECTION_PASS,
332 : &iov, 1,
333 992 : &smb2req->xconn->transport.sock, 1);
334 992 : data_blob_free(&blob);
335 992 : if (!NT_STATUS_IS_OK(status)) {
336 0 : return status;
337 : }
338 :
339 992 : return NT_STATUS_OK;
340 : }
341 :
342 20742 : static NTSTATUS smbXsrv_client_global_store(struct smbXsrv_client_global0 *global)
343 : {
344 : struct smbXsrv_client_globalB global_blob;
345 20742 : DATA_BLOB blob = data_blob_null;
346 : TDB_DATA key;
347 : TDB_DATA val;
348 : NTSTATUS status;
349 : enum ndr_err_code ndr_err;
350 20742 : bool saved_stored = global->stored;
351 :
352 : /*
353 : * TODO: if we use other versions than '0'
354 : * we would add glue code here, that would be able to
355 : * store the information in the old format.
356 : */
357 :
358 20742 : SMB_ASSERT(global->local_address != NULL);
359 20742 : SMB_ASSERT(global->remote_address != NULL);
360 20742 : SMB_ASSERT(global->remote_name != NULL);
361 :
362 20742 : if (global->db_rec == NULL) {
363 0 : return NT_STATUS_INTERNAL_ERROR;
364 : }
365 :
366 20742 : key = dbwrap_record_get_key(global->db_rec);
367 20742 : val = dbwrap_record_get_value(global->db_rec);
368 :
369 20742 : ZERO_STRUCT(global_blob);
370 20742 : global_blob.version = smbXsrv_version_global_current();
371 20742 : if (val.dsize >= 8) {
372 0 : global_blob.seqnum = IVAL(val.dptr, 4);
373 : }
374 20742 : global_blob.seqnum += 1;
375 20742 : global_blob.info.info0 = global;
376 :
377 20742 : global->stored = true;
378 20742 : ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
379 : (ndr_push_flags_fn_t)ndr_push_smbXsrv_client_globalB);
380 20742 : global->stored = saved_stored;
381 20742 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
382 0 : status = ndr_map_error2ntstatus(ndr_err);
383 0 : DBG_WARNING("key '%s' ndr_push - %s\n",
384 : hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
385 : nt_errstr(status));
386 0 : TALLOC_FREE(global->db_rec);
387 0 : return status;
388 : }
389 :
390 20742 : val = make_tdb_data(blob.data, blob.length);
391 20742 : status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
392 20742 : if (!NT_STATUS_IS_OK(status)) {
393 0 : DBG_WARNING("key '%s' store - %s\n",
394 : hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
395 : nt_errstr(status));
396 0 : TALLOC_FREE(global->db_rec);
397 0 : return status;
398 : }
399 :
400 20742 : global->stored = true;
401 :
402 20742 : if (DEBUGLVL(DBGLVL_DEBUG)) {
403 0 : DBG_DEBUG("key '%s' stored\n",
404 : hex_encode_talloc(global->db_rec, key.dptr, key.dsize));
405 0 : NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
406 : }
407 :
408 20742 : TALLOC_FREE(global->db_rec);
409 :
410 20742 : return NT_STATUS_OK;
411 : }
412 :
413 : struct smb2srv_client_mc_negprot_state {
414 : struct tevent_context *ev;
415 : struct smbd_smb2_request *smb2req;
416 : struct db_record *db_rec;
417 : };
418 :
419 43468 : static void smb2srv_client_mc_negprot_cleanup(struct tevent_req *req,
420 : enum tevent_req_state req_state)
421 : {
422 37038 : struct smb2srv_client_mc_negprot_state *state =
423 43468 : tevent_req_data(req,
424 : struct smb2srv_client_mc_negprot_state);
425 :
426 43468 : TALLOC_FREE(state->db_rec);
427 43468 : }
428 :
429 : static void smb2srv_client_mc_negprot_next(struct tevent_req *req);
430 : static bool smb2srv_client_mc_negprot_filter(struct messaging_rec *rec, void *private_data);
431 : static void smb2srv_client_mc_negprot_done(struct tevent_req *subreq);
432 : static void smb2srv_client_mc_negprot_watched(struct tevent_req *subreq);
433 :
434 21734 : struct tevent_req *smb2srv_client_mc_negprot_send(TALLOC_CTX *mem_ctx,
435 : struct tevent_context *ev,
436 : struct smbd_smb2_request *smb2req)
437 : {
438 21734 : struct tevent_req *req = NULL;
439 21734 : struct smb2srv_client_mc_negprot_state *state = NULL;
440 :
441 21734 : req = tevent_req_create(mem_ctx, &state,
442 : struct smb2srv_client_mc_negprot_state);
443 21734 : if (req == NULL) {
444 0 : return NULL;
445 : }
446 21734 : state->ev = ev;
447 21734 : state->smb2req = smb2req;
448 :
449 21734 : tevent_req_set_cleanup_fn(req, smb2srv_client_mc_negprot_cleanup);
450 :
451 21734 : smb2srv_client_mc_negprot_next(req);
452 :
453 21734 : if (!tevent_req_is_in_progress(req)) {
454 20742 : return tevent_req_post(req, ev);
455 : }
456 :
457 992 : return req;
458 : }
459 :
460 21734 : static void smb2srv_client_mc_negprot_next(struct tevent_req *req)
461 : {
462 18519 : struct smb2srv_client_mc_negprot_state *state =
463 21734 : tevent_req_data(req,
464 : struct smb2srv_client_mc_negprot_state);
465 21734 : struct smbXsrv_connection *xconn = state->smb2req->xconn;
466 21734 : struct smbXsrv_client *client = xconn->client;
467 21734 : struct smbXsrv_client_table *table = client->table;
468 21734 : struct GUID client_guid = xconn->smb2.client.guid;
469 21734 : struct smbXsrv_client_global0 *global = NULL;
470 21734 : bool is_free = false;
471 21734 : struct tevent_req *subreq = NULL;
472 : NTSTATUS status;
473 :
474 21734 : SMB_ASSERT(state->db_rec == NULL);
475 21734 : state->db_rec = smbXsrv_client_global_fetch_locked(table->global.db_ctx,
476 : &client_guid,
477 : state);
478 21734 : if (state->db_rec == NULL) {
479 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_DB_ERROR);
480 0 : return;
481 : }
482 :
483 21734 : smbXsrv_client_global_verify_record(state->db_rec,
484 : &is_free,
485 : NULL,
486 : state,
487 : &global);
488 21734 : if (is_free) {
489 : /*
490 : * This stores the new client information in
491 : * smbXsrv_client_global.tdb
492 : */
493 20742 : client->global->client_guid = xconn->smb2.client.guid;
494 :
495 20742 : client->global->db_rec = state->db_rec;
496 20742 : state->db_rec = NULL;
497 20742 : status = smbXsrv_client_global_store(client->global);
498 20742 : SMB_ASSERT(client->global->db_rec == NULL);
499 20742 : if (!NT_STATUS_IS_OK(status)) {
500 : struct GUID_txt_buf buf;
501 0 : DBG_ERR("client_guid[%s] store failed - %s\n",
502 : GUID_buf_string(&client->global->client_guid,
503 : &buf),
504 : nt_errstr(status));
505 0 : tevent_req_nterror(req, status);
506 0 : return;
507 : }
508 :
509 20742 : if (DEBUGLVL(DBGLVL_DEBUG)) {
510 0 : struct smbXsrv_clientB client_blob = {
511 : .version = SMBXSRV_VERSION_0,
512 : .info.info0 = client,
513 : };
514 : struct GUID_txt_buf buf;
515 :
516 0 : DBG_DEBUG("client_guid[%s] stored\n",
517 : GUID_buf_string(&client->global->client_guid,
518 : &buf));
519 0 : NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob);
520 : }
521 :
522 20742 : xconn->smb2.client.guid_verified = true;
523 20742 : tevent_req_done(req);
524 20742 : return;
525 : }
526 :
527 992 : if (global == NULL) {
528 : /*
529 : * most likely ndr_pull_struct_blob() failed
530 : */
531 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_DB_CORRUPTION);
532 0 : return;
533 : }
534 :
535 992 : subreq = messaging_filtered_read_send(state,
536 : state->ev,
537 : client->msg_ctx,
538 : smb2srv_client_mc_negprot_filter,
539 : NULL);
540 992 : if (tevent_req_nomem(subreq, req)) {
541 0 : return;
542 : }
543 992 : tevent_req_set_callback(subreq, smb2srv_client_mc_negprot_done, req);
544 :
545 992 : subreq = dbwrap_watched_watch_send(state,
546 : state->ev,
547 : state->db_rec,
548 992 : global->server_id);
549 992 : if (tevent_req_nomem(subreq, req)) {
550 0 : return;
551 : }
552 992 : tevent_req_set_callback(subreq, smb2srv_client_mc_negprot_watched, req);
553 :
554 992 : status = smb2srv_client_connection_pass(state->smb2req,
555 : global);
556 992 : TALLOC_FREE(global);
557 992 : if (tevent_req_nterror(req, status)) {
558 0 : return;
559 : }
560 :
561 992 : TALLOC_FREE(state->db_rec);
562 992 : return;
563 : }
564 :
565 992 : static bool smb2srv_client_mc_negprot_filter(struct messaging_rec *rec, void *private_data)
566 : {
567 992 : if (rec->msg_type != MSG_SMBXSRV_CONNECTION_PASSED) {
568 0 : return false;
569 : }
570 :
571 992 : if (rec->num_fds != 0) {
572 0 : return false;
573 : }
574 :
575 992 : if (rec->buf.length < SMB2_HDR_BODY) {
576 0 : return false;
577 : }
578 :
579 992 : return true;
580 : }
581 :
582 992 : static void smb2srv_client_mc_negprot_done(struct tevent_req *subreq)
583 : {
584 756 : struct tevent_req *req =
585 992 : tevent_req_callback_data(subreq,
586 : struct tevent_req);
587 756 : struct smb2srv_client_mc_negprot_state *state =
588 992 : tevent_req_data(req,
589 : struct smb2srv_client_mc_negprot_state);
590 992 : struct smbXsrv_connection *xconn = state->smb2req->xconn;
591 992 : struct smbXsrv_client *client = xconn->client;
592 992 : struct messaging_rec *rec = NULL;
593 : struct smbXsrv_connection_passB passed_blob;
594 : enum ndr_err_code ndr_err;
595 992 : struct smbXsrv_connection_pass0 *passed_info0 = NULL;
596 : NTSTATUS status;
597 : int ret;
598 :
599 992 : ret = messaging_filtered_read_recv(subreq, state, &rec);
600 992 : TALLOC_FREE(subreq);
601 992 : if (ret != 0) {
602 0 : status = map_nt_error_from_unix_common(ret);
603 0 : DBG_ERR("messaging_filtered_read_recv() - %s\n",
604 : nt_errstr(status));
605 0 : tevent_req_nterror(req, status);
606 0 : return;
607 : }
608 :
609 992 : DBG_DEBUG("MSG_SMBXSRV_CONNECTION_PASSED: received...\n");
610 :
611 992 : ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &passed_blob,
612 : (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_connection_passB);
613 992 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
614 0 : status = ndr_map_error2ntstatus(ndr_err);
615 0 : DBG_ERR("ndr_pull_struct_blob - %s\n", nt_errstr(status));
616 0 : tevent_req_nterror(req, status);
617 0 : return;
618 : }
619 :
620 992 : if (DEBUGLVL(DBGLVL_DEBUG)) {
621 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
622 : }
623 :
624 992 : if (passed_blob.version != SMBXSRV_VERSION_0) {
625 0 : DBG_ERR("ignore invalid version %u\n", passed_blob.version);
626 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
627 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
628 0 : return;
629 : }
630 :
631 992 : passed_info0 = passed_blob.info.info0;
632 992 : if (passed_info0 == NULL) {
633 0 : DBG_ERR("ignore NULL info %u\n", passed_blob.version);
634 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
635 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
636 0 : return;
637 : }
638 :
639 992 : if (!GUID_equal(&xconn->smb2.client.guid, &passed_info0->client_guid)) {
640 : struct GUID_txt_buf buf1, buf2;
641 :
642 0 : DBG_ERR("client's client_guid [%s] != passed guid [%s]\n",
643 : GUID_buf_string(&xconn->smb2.client.guid,
644 : &buf1),
645 : GUID_buf_string(&passed_info0->client_guid,
646 : &buf2));
647 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
648 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
649 0 : return;
650 : }
651 :
652 1748 : if (client->global->initial_connect_time !=
653 992 : passed_info0->xconn_connect_time)
654 : {
655 0 : DBG_ERR("client's initial connect time [%s] (%llu) != "
656 : "passed xconn connect time [%s] (%llu)\n",
657 : nt_time_string(talloc_tos(),
658 : client->global->initial_connect_time),
659 : (unsigned long long)client->global->initial_connect_time,
660 : nt_time_string(talloc_tos(),
661 : passed_info0->xconn_connect_time),
662 : (unsigned long long)passed_info0->xconn_connect_time);
663 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
664 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
665 0 : return;
666 : }
667 :
668 992 : tevent_req_nterror(req, NT_STATUS_MESSAGE_RETRIEVED);
669 : }
670 :
671 0 : static void smb2srv_client_mc_negprot_watched(struct tevent_req *subreq)
672 : {
673 0 : struct tevent_req *req =
674 0 : tevent_req_callback_data(subreq,
675 : struct tevent_req);
676 : NTSTATUS status;
677 :
678 0 : status = dbwrap_watched_watch_recv(subreq, NULL, NULL);
679 0 : TALLOC_FREE(subreq);
680 0 : if (tevent_req_nterror(req, status)) {
681 0 : return;
682 : }
683 :
684 0 : smb2srv_client_mc_negprot_next(req);
685 : }
686 :
687 21734 : NTSTATUS smb2srv_client_mc_negprot_recv(struct tevent_req *req)
688 : {
689 21734 : return tevent_req_simple_recv_ntstatus(req);
690 : }
691 :
692 20740 : static NTSTATUS smbXsrv_client_global_remove(struct smbXsrv_client_global0 *global)
693 : {
694 : TDB_DATA key;
695 : NTSTATUS status;
696 :
697 : /*
698 : * TODO: if we use other versions than '0'
699 : * we would add glue code here, that would be able to
700 : * store the information in the old format.
701 : */
702 :
703 20740 : if (global->db_rec == NULL) {
704 0 : return NT_STATUS_INTERNAL_ERROR;
705 : }
706 :
707 20740 : key = dbwrap_record_get_key(global->db_rec);
708 :
709 20740 : status = dbwrap_record_delete(global->db_rec);
710 20740 : if (!NT_STATUS_IS_OK(status)) {
711 0 : DBG_WARNING("key '%s' delete - %s\n",
712 : hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
713 : nt_errstr(status));
714 0 : TALLOC_FREE(global->db_rec);
715 0 : return status;
716 : }
717 20740 : global->stored = false;
718 20740 : DBG_DEBUG("key '%s' delete\n",
719 : hex_encode_talloc(global->db_rec, key.dptr, key.dsize));
720 :
721 20740 : TALLOC_FREE(global->db_rec);
722 :
723 20740 : return NT_STATUS_OK;
724 : }
725 :
726 27249 : static int smbXsrv_client_destructor(struct smbXsrv_client *client)
727 : {
728 : NTSTATUS status;
729 :
730 27249 : status = smbXsrv_client_remove(client);
731 27249 : if (!NT_STATUS_IS_OK(status)) {
732 0 : DBG_ERR("smbXsrv_client_remove() failed: %s\n",
733 : nt_errstr(status));
734 : }
735 :
736 27249 : TALLOC_FREE(client->global);
737 :
738 27249 : return 0;
739 : }
740 :
741 : static bool smbXsrv_client_connection_pass_filter(struct messaging_rec *rec, void *private_data);
742 : static void smbXsrv_client_connection_pass_loop(struct tevent_req *subreq);
743 :
744 27263 : NTSTATUS smbXsrv_client_create(TALLOC_CTX *mem_ctx,
745 : struct tevent_context *ev_ctx,
746 : struct messaging_context *msg_ctx,
747 : NTTIME now,
748 : struct smbXsrv_client **_client)
749 : {
750 : struct smbXsrv_client_table *table;
751 27263 : struct smbXsrv_client *client = NULL;
752 27263 : struct smbXsrv_client_global0 *global = NULL;
753 : NTSTATUS status;
754 27263 : struct tevent_req *subreq = NULL;
755 :
756 27263 : status = smbXsrv_client_table_create(mem_ctx,
757 : msg_ctx,
758 : 1, /* max_clients */
759 : &table);
760 27263 : if (!NT_STATUS_IS_OK(status)) {
761 0 : return status;
762 : }
763 :
764 27263 : if (table->local.num_clients >= table->local.max_clients) {
765 0 : TALLOC_FREE(table);
766 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
767 : }
768 :
769 27263 : client = talloc_zero(mem_ctx, struct smbXsrv_client);
770 27263 : if (client == NULL) {
771 0 : TALLOC_FREE(table);
772 0 : return NT_STATUS_NO_MEMORY;
773 : }
774 27263 : client->raw_ev_ctx = ev_ctx;
775 27263 : client->msg_ctx = msg_ctx;
776 :
777 27263 : client->server_multi_channel_enabled =
778 27263 : smbXsrv_server_multi_channel_enabled();
779 27263 : if (client->server_multi_channel_enabled) {
780 27263 : client->next_channel_id = 1;
781 : }
782 27263 : client->table = talloc_move(client, &table);
783 27263 : table = client->table;
784 :
785 27263 : global = talloc_zero(client, struct smbXsrv_client_global0);
786 27263 : if (global == NULL) {
787 0 : TALLOC_FREE(client);
788 0 : return NT_STATUS_NO_MEMORY;
789 : }
790 27263 : talloc_set_destructor(global, smbXsrv_client_global_destructor);
791 27263 : client->global = global;
792 :
793 27263 : global->initial_connect_time = now;
794 :
795 27263 : global->server_id = messaging_server_id(client->msg_ctx);
796 :
797 27263 : table->local.num_clients += 1;
798 :
799 27263 : talloc_set_destructor(client, smbXsrv_client_destructor);
800 :
801 27263 : if (DEBUGLVL(DBGLVL_DEBUG)) {
802 0 : struct smbXsrv_clientB client_blob = {
803 : .version = SMBXSRV_VERSION_0,
804 : .info.info0 = client,
805 : };
806 : struct GUID_txt_buf buf;
807 :
808 0 : DBG_DEBUG("client_guid[%s] created\n",
809 : GUID_buf_string(&global->client_guid, &buf));
810 0 : NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob);
811 : }
812 :
813 27263 : subreq = messaging_filtered_read_send(client,
814 : client->raw_ev_ctx,
815 : client->msg_ctx,
816 : smbXsrv_client_connection_pass_filter,
817 : client);
818 27263 : if (subreq == NULL) {
819 0 : TALLOC_FREE(client);
820 0 : return NT_STATUS_NO_MEMORY;
821 : }
822 27263 : tevent_req_set_callback(subreq, smbXsrv_client_connection_pass_loop, client);
823 27263 : client->connection_pass_subreq = subreq;
824 :
825 27263 : *_client = client;
826 27263 : return NT_STATUS_OK;
827 : }
828 :
829 930 : static NTSTATUS smb2srv_client_connection_passed(struct smbXsrv_client *client,
830 : const struct smbXsrv_connection_pass0 *recv_info0)
831 : {
832 : DATA_BLOB blob;
833 : enum ndr_err_code ndr_err;
834 : NTSTATUS status;
835 : struct smbXsrv_connection_pass0 passed_info0;
836 : struct smbXsrv_connection_passB passed_blob;
837 : struct iovec iov;
838 :
839 : /*
840 : * We echo back the message with a cleared negotiate_request
841 : */
842 930 : passed_info0 = *recv_info0;
843 930 : passed_info0.negotiate_request = data_blob_null;
844 :
845 930 : ZERO_STRUCT(passed_blob);
846 930 : passed_blob.version = smbXsrv_version_global_current();
847 930 : passed_blob.info.info0 = &passed_info0;
848 :
849 930 : if (DEBUGLVL(DBGLVL_DEBUG)) {
850 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
851 : }
852 :
853 930 : ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &passed_blob,
854 : (ndr_push_flags_fn_t)ndr_push_smbXsrv_connection_passB);
855 930 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
856 0 : status = ndr_map_error2ntstatus(ndr_err);
857 0 : return status;
858 : }
859 :
860 930 : iov.iov_base = blob.data;
861 930 : iov.iov_len = blob.length;
862 :
863 930 : status = messaging_send_iov(client->msg_ctx,
864 : recv_info0->src_server_id,
865 : MSG_SMBXSRV_CONNECTION_PASSED,
866 : &iov, 1,
867 : NULL, 0);
868 930 : data_blob_free(&blob);
869 930 : if (!NT_STATUS_IS_OK(status)) {
870 0 : return status;
871 : }
872 :
873 930 : return NT_STATUS_OK;
874 : }
875 :
876 45005 : static bool smbXsrv_client_connection_pass_filter(struct messaging_rec *rec, void *private_data)
877 : {
878 45005 : if (rec->msg_type != MSG_SMBXSRV_CONNECTION_PASS) {
879 44073 : return false;
880 : }
881 :
882 930 : if (rec->num_fds != 1) {
883 0 : return false;
884 : }
885 :
886 930 : if (rec->buf.length < SMB2_HDR_BODY) {
887 0 : return false;
888 : }
889 :
890 : /* TODO: verify client_guid...? */
891 :
892 930 : return true;
893 : }
894 :
895 930 : static void smbXsrv_client_connection_pass_loop(struct tevent_req *subreq)
896 : {
897 694 : struct smbXsrv_client *client =
898 930 : tevent_req_callback_data(subreq,
899 : struct smbXsrv_client);
900 930 : struct smbXsrv_connection *xconn = NULL;
901 : int ret;
902 930 : struct messaging_rec *rec = NULL;
903 : struct smbXsrv_connection_passB pass_blob;
904 : enum ndr_err_code ndr_err;
905 930 : struct smbXsrv_connection_pass0 *pass_info0 = NULL;
906 : NTSTATUS status;
907 930 : int sock_fd = -1;
908 : uint64_t seq_low;
909 :
910 930 : client->connection_pass_subreq = NULL;
911 :
912 930 : ret = messaging_filtered_read_recv(subreq, talloc_tos(), &rec);
913 930 : TALLOC_FREE(subreq);
914 930 : if (ret != 0) {
915 0 : goto next;
916 : }
917 :
918 930 : if (rec->num_fds != 1) {
919 0 : DBG_ERR("MSG_SMBXSRV_CONNECTION_PASS: num_fds[%u]\n",
920 : rec->num_fds);
921 0 : goto next;
922 : }
923 :
924 930 : sock_fd = rec->fds[0];
925 930 : DBG_DEBUG("MSG_SMBXSRV_CONNECTION_PASS: got sock_fd[%d]\n", sock_fd);
926 :
927 930 : ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &pass_blob,
928 : (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_connection_passB);
929 930 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
930 0 : status = ndr_map_error2ntstatus(ndr_err);
931 0 : DBG_WARNING("ndr_pull_struct_blob - %s\n", nt_errstr(status));
932 0 : goto next;
933 : }
934 :
935 930 : if (DEBUGLVL(DBGLVL_DEBUG)) {
936 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
937 : }
938 :
939 930 : if (pass_blob.version != SMBXSRV_VERSION_0) {
940 0 : DBG_ERR("ignore invalid version %u\n", pass_blob.version);
941 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
942 0 : goto next;
943 : }
944 :
945 930 : pass_info0 = pass_blob.info.info0;
946 930 : if (pass_info0 == NULL) {
947 0 : DBG_ERR("ignore NULL info %u\n", pass_blob.version);
948 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
949 0 : goto next;
950 : }
951 :
952 930 : if (!GUID_equal(&client->global->client_guid, &pass_info0->client_guid))
953 : {
954 : struct GUID_txt_buf buf1, buf2;
955 :
956 0 : DBG_WARNING("client's client_guid [%s] != passed guid [%s]\n",
957 : GUID_buf_string(&client->global->client_guid,
958 : &buf1),
959 : GUID_buf_string(&pass_info0->client_guid,
960 : &buf2));
961 0 : if (DEBUGLVL(DBGLVL_WARNING)) {
962 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
963 : }
964 0 : goto next;
965 : }
966 :
967 1624 : if (client->global->initial_connect_time !=
968 930 : pass_info0->client_connect_time)
969 : {
970 0 : DBG_WARNING("client's initial connect time [%s] (%llu) != "
971 : "passed initial connect time [%s] (%llu)\n",
972 : nt_time_string(talloc_tos(),
973 : client->global->initial_connect_time),
974 : (unsigned long long)client->global->initial_connect_time,
975 : nt_time_string(talloc_tos(),
976 : pass_info0->client_connect_time),
977 : (unsigned long long)pass_info0->client_connect_time);
978 0 : if (DEBUGLVL(DBGLVL_WARNING)) {
979 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
980 : }
981 0 : goto next;
982 : }
983 :
984 930 : status = smb2srv_client_connection_passed(client, pass_info0);
985 930 : if (!NT_STATUS_IS_OK(status)) {
986 0 : const char *r = "smb2srv_client_connection_passed() failed";
987 0 : DBG_ERR("%s => %s\n", r, nt_errstr(status));
988 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
989 0 : exit_server_cleanly(r);
990 : return;
991 : }
992 :
993 930 : status = smbd_add_connection(client,
994 : sock_fd,
995 : pass_info0->xconn_connect_time,
996 : &xconn);
997 930 : if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
998 0 : rec->num_fds = 0;
999 0 : smbd_server_connection_terminate(xconn, nt_errstr(status));
1000 : }
1001 930 : if (!NT_STATUS_IS_OK(status)) {
1002 0 : DBG_ERR("smbd_add_connection => %s\n", nt_errstr(status));
1003 0 : NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
1004 0 : goto next;
1005 : }
1006 930 : rec->num_fds = 0;
1007 :
1008 : /*
1009 : * Set seq_low to mid received in negprot
1010 : */
1011 930 : seq_low = BVAL(pass_info0->negotiate_request.data,
1012 : SMB2_HDR_MESSAGE_ID);
1013 :
1014 930 : xconn->smb2.client.guid_verified = true;
1015 1624 : smbd_smb2_process_negprot(xconn, seq_low,
1016 930 : pass_info0->negotiate_request.data,
1017 : pass_info0->negotiate_request.length);
1018 :
1019 930 : next:
1020 930 : if (rec != NULL) {
1021 : uint8_t fd_idx;
1022 :
1023 930 : for (fd_idx = 0; fd_idx < rec->num_fds; fd_idx++) {
1024 0 : sock_fd = rec->fds[fd_idx];
1025 0 : close(sock_fd);
1026 : }
1027 930 : rec->num_fds = 0;
1028 :
1029 930 : TALLOC_FREE(rec);
1030 : }
1031 :
1032 930 : subreq = messaging_filtered_read_send(client,
1033 : client->raw_ev_ctx,
1034 : client->msg_ctx,
1035 : smbXsrv_client_connection_pass_filter,
1036 : client);
1037 930 : if (subreq == NULL) {
1038 : const char *r;
1039 0 : r = "messaging_read_send(MSG_SMBXSRV_CONNECTION_PASS failed";
1040 0 : exit_server_cleanly(r);
1041 : return;
1042 : }
1043 930 : tevent_req_set_callback(subreq, smbXsrv_client_connection_pass_loop, client);
1044 930 : client->connection_pass_subreq = subreq;
1045 694 : }
1046 :
1047 54498 : NTSTATUS smbXsrv_client_remove(struct smbXsrv_client *client)
1048 : {
1049 54498 : struct smbXsrv_client_table *table = client->table;
1050 : NTSTATUS status;
1051 :
1052 54498 : if (client->global->db_rec != NULL) {
1053 : struct GUID_txt_buf buf;
1054 0 : DBG_ERR("client_guid[%s]: Called with db_rec != NULL'\n",
1055 : GUID_buf_string(&client->global->client_guid,
1056 : &buf));
1057 0 : return NT_STATUS_INTERNAL_ERROR;
1058 : }
1059 :
1060 54498 : if (!client->global->stored) {
1061 33758 : return NT_STATUS_OK;
1062 : }
1063 :
1064 20740 : TALLOC_FREE(client->connection_pass_subreq);
1065 :
1066 23719 : client->global->db_rec = smbXsrv_client_global_fetch_locked(
1067 : table->global.db_ctx,
1068 20740 : &client->global->client_guid,
1069 20740 : client->global /* TALLOC_CTX */);
1070 20740 : if (client->global->db_rec == NULL) {
1071 0 : return NT_STATUS_INTERNAL_DB_ERROR;
1072 : }
1073 :
1074 20740 : status = smbXsrv_client_global_remove(client->global);
1075 20740 : if (!NT_STATUS_IS_OK(status)) {
1076 : struct GUID_txt_buf buf;
1077 0 : DBG_ERR("client_guid[%s] store failed - %s\n",
1078 : GUID_buf_string(&client->global->client_guid, &buf),
1079 : nt_errstr(status));
1080 0 : return status;
1081 : }
1082 :
1083 20740 : if (DEBUGLVL(DBGLVL_DEBUG)) {
1084 0 : struct smbXsrv_clientB client_blob = {
1085 : .version = SMBXSRV_VERSION_0,
1086 : .info.info0 = client,
1087 : };
1088 : struct GUID_txt_buf buf;
1089 :
1090 0 : DBG_DEBUG("client_guid[%s] stored\n",
1091 : GUID_buf_string(&client->global->client_guid, &buf));
1092 0 : NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob);
1093 : }
1094 :
1095 20740 : return NT_STATUS_OK;
1096 : }
|