Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : process incoming packets - main loop
4 : Copyright (C) Andrew Tridgell 1992-1998
5 : Copyright (C) Volker Lendecke 2005-2007
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "../lib/tsocket/tsocket.h"
23 : #include "system/filesys.h"
24 : #include "smbd/smbd.h"
25 : #include "smbd/globals.h"
26 : #include "smbd/smbXsrv_open.h"
27 : #include "librpc/gen_ndr/netlogon.h"
28 : #include "../lib/async_req/async_sock.h"
29 : #include "ctdbd_conn.h"
30 : #include "../lib/util/select.h"
31 : #include "printing/queue_process.h"
32 : #include "system/select.h"
33 : #include "passdb.h"
34 : #include "auth.h"
35 : #include "messages.h"
36 : #include "lib/messages_ctdb.h"
37 : #include "smbprofile.h"
38 : #include "rpc_server/spoolss/srv_spoolss_nt.h"
39 : #include "../lib/util/tevent_ntstatus.h"
40 : #include "../libcli/security/dom_sid.h"
41 : #include "../libcli/security/security_token.h"
42 : #include "lib/id_cache.h"
43 : #include "lib/util/sys_rw_data.h"
44 : #include "system/threads.h"
45 : #include "lib/pthreadpool/pthreadpool_tevent.h"
46 : #include "util_event.h"
47 : #include "libcli/smb/smbXcli_base.h"
48 : #include "lib/util/time_basic.h"
49 : #include "source3/lib/substitute.h"
50 : #include "lib/util/util_process.h"
51 :
52 : /* Internal message queue for deferred opens. */
53 : struct pending_message_list {
54 : struct pending_message_list *next, *prev;
55 : struct timeval request_time; /* When was this first issued? */
56 : struct smbd_server_connection *sconn;
57 : struct smbXsrv_connection *xconn;
58 : struct tevent_timer *te;
59 : uint32_t seqnum;
60 : bool encrypted;
61 : bool processed;
62 : DATA_BLOB buf;
63 : struct deferred_open_record *open_rec;
64 : };
65 :
66 : static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf);
67 :
68 32185 : void smbd_echo_init(struct smbXsrv_connection *xconn)
69 : {
70 32185 : xconn->smb1.echo_handler.trusted_fd = -1;
71 32185 : xconn->smb1.echo_handler.socket_lock_fd = -1;
72 : #ifdef HAVE_ROBUST_MUTEXES
73 32185 : xconn->smb1.echo_handler.socket_mutex = NULL;
74 : #endif
75 32185 : }
76 :
77 1306898 : static bool smbd_echo_active(struct smbXsrv_connection *xconn)
78 : {
79 1306898 : if (xconn->smb1.echo_handler.socket_lock_fd != -1) {
80 0 : return true;
81 : }
82 :
83 : #ifdef HAVE_ROBUST_MUTEXES
84 1306898 : if (xconn->smb1.echo_handler.socket_mutex != NULL) {
85 0 : return true;
86 : }
87 : #endif
88 :
89 1291174 : return false;
90 : }
91 :
92 653449 : static bool smbd_lock_socket_internal(struct smbXsrv_connection *xconn)
93 : {
94 653449 : if (!smbd_echo_active(xconn)) {
95 645587 : return true;
96 : }
97 :
98 0 : xconn->smb1.echo_handler.ref_count++;
99 :
100 0 : if (xconn->smb1.echo_handler.ref_count > 1) {
101 0 : return true;
102 : }
103 :
104 0 : DEBUG(10,("pid[%d] wait for socket lock\n", (int)getpid()));
105 :
106 : #ifdef HAVE_ROBUST_MUTEXES
107 0 : if (xconn->smb1.echo_handler.socket_mutex != NULL) {
108 0 : int ret = EINTR;
109 :
110 0 : while (ret == EINTR) {
111 0 : ret = pthread_mutex_lock(
112 : xconn->smb1.echo_handler.socket_mutex);
113 0 : if (ret == 0) {
114 0 : break;
115 : }
116 : }
117 0 : if (ret != 0) {
118 0 : DEBUG(1, ("pthread_mutex_lock failed: %s\n",
119 : strerror(ret)));
120 0 : return false;
121 : }
122 : }
123 : #endif
124 :
125 0 : if (xconn->smb1.echo_handler.socket_lock_fd != -1) {
126 0 : bool ok;
127 :
128 0 : do {
129 0 : ok = fcntl_lock(
130 : xconn->smb1.echo_handler.socket_lock_fd,
131 : F_SETLKW, 0, 0, F_WRLCK);
132 0 : } while (!ok && (errno == EINTR));
133 :
134 0 : if (!ok) {
135 0 : DEBUG(1, ("fcntl_lock failed: %s\n", strerror(errno)));
136 0 : return false;
137 : }
138 : }
139 :
140 0 : DEBUG(10,("pid[%d] got socket lock\n", (int)getpid()));
141 :
142 0 : return true;
143 : }
144 :
145 653449 : void smbd_lock_socket(struct smbXsrv_connection *xconn)
146 : {
147 653449 : if (!smbd_lock_socket_internal(xconn)) {
148 0 : exit_server_cleanly("failed to lock socket");
149 : }
150 653449 : }
151 :
152 653449 : static bool smbd_unlock_socket_internal(struct smbXsrv_connection *xconn)
153 : {
154 653449 : if (!smbd_echo_active(xconn)) {
155 645587 : return true;
156 : }
157 :
158 0 : xconn->smb1.echo_handler.ref_count--;
159 :
160 0 : if (xconn->smb1.echo_handler.ref_count > 0) {
161 0 : return true;
162 : }
163 :
164 : #ifdef HAVE_ROBUST_MUTEXES
165 0 : if (xconn->smb1.echo_handler.socket_mutex != NULL) {
166 0 : int ret;
167 0 : ret = pthread_mutex_unlock(
168 : xconn->smb1.echo_handler.socket_mutex);
169 0 : if (ret != 0) {
170 0 : DEBUG(1, ("pthread_mutex_unlock failed: %s\n",
171 : strerror(ret)));
172 0 : return false;
173 : }
174 : }
175 : #endif
176 :
177 0 : if (xconn->smb1.echo_handler.socket_lock_fd != -1) {
178 0 : bool ok;
179 :
180 0 : do {
181 0 : ok = fcntl_lock(
182 : xconn->smb1.echo_handler.socket_lock_fd,
183 : F_SETLKW, 0, 0, F_UNLCK);
184 0 : } while (!ok && (errno == EINTR));
185 :
186 0 : if (!ok) {
187 0 : DEBUG(1, ("fcntl_lock failed: %s\n", strerror(errno)));
188 0 : return false;
189 : }
190 : }
191 :
192 0 : DEBUG(10,("pid[%d] unlocked socket\n", (int)getpid()));
193 :
194 0 : return true;
195 : }
196 :
197 653449 : void smbd_unlock_socket(struct smbXsrv_connection *xconn)
198 : {
199 653449 : if (!smbd_unlock_socket_internal(xconn)) {
200 0 : exit_server_cleanly("failed to unlock socket");
201 : }
202 653449 : }
203 :
204 : /* Accessor function for smb_read_error for smbd functions. */
205 :
206 : /****************************************************************************
207 : Send an smb to a fd.
208 : ****************************************************************************/
209 :
210 653410 : bool smb1_srv_send(struct smbXsrv_connection *xconn,
211 : char *buffer,
212 : bool do_signing,
213 : uint32_t seqnum,
214 : bool do_encrypt)
215 : {
216 653410 : size_t len = 0;
217 7859 : ssize_t ret;
218 653410 : char *buf_out = buffer;
219 :
220 653410 : if (!NT_STATUS_IS_OK(xconn->transport.status)) {
221 : /*
222 : * we're not supposed to do any io
223 : */
224 42 : return true;
225 : }
226 :
227 653368 : smbd_lock_socket(xconn);
228 :
229 653368 : if (do_signing) {
230 7851 : NTSTATUS status;
231 :
232 : /* Sign the outgoing packet if required. */
233 651715 : status = smb1_srv_calculate_sign_mac(xconn, buf_out, seqnum);
234 651715 : if (!NT_STATUS_IS_OK(status)) {
235 0 : DBG_ERR("Failed to calculate signing mac: %s\n",
236 : nt_errstr(status));
237 0 : return false;
238 : }
239 : }
240 :
241 653368 : if (do_encrypt) {
242 185842 : NTSTATUS status = srv_encrypt_buffer(xconn, buffer, &buf_out);
243 185842 : if (!NT_STATUS_IS_OK(status)) {
244 0 : DEBUG(0, ("send_smb: SMB encryption failed "
245 : "on outgoing packet! Error %s\n",
246 : nt_errstr(status) ));
247 0 : ret = -1;
248 0 : goto out;
249 : }
250 : }
251 :
252 653368 : len = smb_len_large(buf_out) + 4;
253 :
254 653368 : ret = write_data(xconn->transport.sock, buf_out, len);
255 653368 : if (ret <= 0) {
256 82 : int saved_errno = errno;
257 : /*
258 : * Try and give an error message saying what
259 : * client failed.
260 : */
261 82 : DEBUG(1,("pid[%d] Error writing %d bytes to client %s. %d. (%s)\n",
262 : (int)getpid(), (int)len,
263 : smbXsrv_connection_dbg(xconn),
264 : (int)ret, strerror(saved_errno)));
265 82 : errno = saved_errno;
266 :
267 82 : srv_free_enc_buffer(xconn, buf_out);
268 82 : goto out;
269 : }
270 :
271 653286 : srv_free_enc_buffer(xconn, buf_out);
272 653368 : out:
273 653368 : smbd_unlock_socket(xconn);
274 653368 : return (ret > 0);
275 : }
276 :
277 : /* Socket functions for smbd packet processing. */
278 :
279 653575 : static bool valid_packet_size(size_t len)
280 : {
281 : /*
282 : * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
283 : * of header. Don't print the error if this fits.... JRA.
284 : */
285 :
286 653575 : if (len > (LARGE_WRITEX_BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
287 0 : DEBUG(0,("Invalid packet length! (%lu bytes).\n",
288 : (unsigned long)len));
289 0 : return false;
290 : }
291 645716 : return true;
292 : }
293 :
294 : /****************************************************************************
295 : Attempt a zerocopy writeX read. We know here that len > smb_size-4
296 : ****************************************************************************/
297 :
298 : /*
299 : * Unfortunately, earlier versions of smbclient/libsmbclient
300 : * don't send this "standard" writeX header. I've fixed this
301 : * for 3.2 but we'll use the old method with earlier versions.
302 : * Windows and CIFSFS at least use this standard size. Not
303 : * sure about MacOSX.
304 : */
305 :
306 : #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
307 : (2*14) + /* word count (including bcc) */ \
308 : 1 /* pad byte */)
309 :
310 0 : static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
311 : const char lenbuf[4],
312 : struct smbXsrv_connection *xconn,
313 : int sock,
314 : char **buffer,
315 : unsigned int timeout,
316 : size_t *p_unread,
317 : size_t *len_ret)
318 : {
319 : /* Size of a WRITEX call (+4 byte len). */
320 0 : char writeX_header[4 + STANDARD_WRITE_AND_X_HEADER_SIZE];
321 0 : ssize_t len = smb_len_large(lenbuf); /* Could be a UNIX large writeX. */
322 0 : ssize_t toread;
323 0 : NTSTATUS status;
324 :
325 0 : memcpy(writeX_header, lenbuf, 4);
326 :
327 0 : status = read_fd_with_timeout(
328 : sock, writeX_header + 4,
329 : STANDARD_WRITE_AND_X_HEADER_SIZE,
330 : STANDARD_WRITE_AND_X_HEADER_SIZE,
331 : timeout, NULL);
332 :
333 0 : if (!NT_STATUS_IS_OK(status)) {
334 0 : DEBUG(0, ("read_fd_with_timeout failed for client %s read "
335 : "error = %s.\n",
336 : smbXsrv_connection_dbg(xconn),
337 : nt_errstr(status)));
338 0 : return status;
339 : }
340 :
341 : /*
342 : * Ok - now try and see if this is a possible
343 : * valid writeX call.
344 : */
345 :
346 0 : if (is_valid_writeX_buffer(xconn, (uint8_t *)writeX_header)) {
347 : /*
348 : * If the data offset is beyond what
349 : * we've read, drain the extra bytes.
350 : */
351 0 : uint16_t doff = SVAL(writeX_header,smb_vwv11);
352 0 : ssize_t newlen;
353 :
354 0 : if (doff > STANDARD_WRITE_AND_X_HEADER_SIZE) {
355 0 : size_t drain = doff - STANDARD_WRITE_AND_X_HEADER_SIZE;
356 0 : if (drain_socket(sock, drain) != drain) {
357 0 : smb_panic("receive_smb_raw_talloc_partial_read:"
358 : " failed to drain pending bytes");
359 : }
360 : } else {
361 0 : doff = STANDARD_WRITE_AND_X_HEADER_SIZE;
362 : }
363 :
364 : /* Spoof down the length and null out the bcc. */
365 0 : set_message_bcc(writeX_header, 0);
366 0 : newlen = smb_len(writeX_header);
367 :
368 : /* Copy the header we've written. */
369 :
370 0 : *buffer = (char *)talloc_memdup(mem_ctx,
371 : writeX_header,
372 : sizeof(writeX_header));
373 :
374 0 : if (*buffer == NULL) {
375 0 : DEBUG(0, ("Could not allocate inbuf of length %d\n",
376 : (int)sizeof(writeX_header)));
377 0 : return NT_STATUS_NO_MEMORY;
378 : }
379 :
380 : /* Work out the remaining bytes. */
381 0 : *p_unread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
382 0 : *len_ret = newlen + 4;
383 0 : return NT_STATUS_OK;
384 : }
385 :
386 0 : if (!valid_packet_size(len)) {
387 0 : return NT_STATUS_INVALID_PARAMETER;
388 : }
389 :
390 : /*
391 : * Not a valid writeX call. Just do the standard
392 : * talloc and return.
393 : */
394 :
395 0 : *buffer = talloc_array(mem_ctx, char, len+4);
396 :
397 0 : if (*buffer == NULL) {
398 0 : DEBUG(0, ("Could not allocate inbuf of length %d\n",
399 : (int)len+4));
400 0 : return NT_STATUS_NO_MEMORY;
401 : }
402 :
403 : /* Copy in what we already read. */
404 0 : memcpy(*buffer,
405 : writeX_header,
406 : 4 + STANDARD_WRITE_AND_X_HEADER_SIZE);
407 0 : toread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
408 :
409 0 : if(toread > 0) {
410 0 : status = read_packet_remainder(
411 : sock,
412 0 : (*buffer) + 4 + STANDARD_WRITE_AND_X_HEADER_SIZE,
413 : timeout, toread);
414 :
415 0 : if (!NT_STATUS_IS_OK(status)) {
416 0 : DEBUG(10, ("receive_smb_raw_talloc_partial_read: %s\n",
417 : nt_errstr(status)));
418 0 : return status;
419 : }
420 : }
421 :
422 0 : *len_ret = len + 4;
423 0 : return NT_STATUS_OK;
424 : }
425 :
426 659150 : static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx,
427 : struct smbXsrv_connection *xconn,
428 : int sock,
429 : char **buffer, unsigned int timeout,
430 : size_t *p_unread, size_t *plen)
431 : {
432 7992 : char lenbuf[4];
433 7992 : size_t len;
434 659150 : int min_recv_size = lp_min_receive_file_size();
435 7992 : NTSTATUS status;
436 :
437 659150 : *p_unread = 0;
438 :
439 659150 : status = read_smb_length_return_keepalive(sock, lenbuf, timeout,
440 : &len);
441 659150 : if (!NT_STATUS_IS_OK(status)) {
442 5575 : return status;
443 : }
444 :
445 653575 : if (CVAL(lenbuf,0) == 0 && min_recv_size &&
446 0 : (smb_len_large(lenbuf) > /* Could be a UNIX large writeX. */
447 0 : (min_recv_size + STANDARD_WRITE_AND_X_HEADER_SIZE)) &&
448 0 : !smb1_srv_is_signing_active(xconn) &&
449 0 : xconn->smb1.echo_handler.trusted_fde == NULL) {
450 :
451 0 : return receive_smb_raw_talloc_partial_read(
452 : mem_ctx, lenbuf, xconn, sock, buffer, timeout,
453 : p_unread, plen);
454 : }
455 :
456 653575 : if (!valid_packet_size(len)) {
457 0 : return NT_STATUS_INVALID_PARAMETER;
458 : }
459 :
460 : /*
461 : * The +4 here can't wrap, we've checked the length above already.
462 : */
463 :
464 653575 : *buffer = talloc_array(mem_ctx, char, len+4);
465 :
466 653575 : if (*buffer == NULL) {
467 0 : DEBUG(0, ("Could not allocate inbuf of length %d\n",
468 : (int)len+4));
469 0 : return NT_STATUS_NO_MEMORY;
470 : }
471 :
472 653575 : memcpy(*buffer, lenbuf, sizeof(lenbuf));
473 :
474 653575 : status = read_packet_remainder(sock, (*buffer)+4, timeout, len);
475 653575 : if (!NT_STATUS_IS_OK(status)) {
476 0 : return status;
477 : }
478 :
479 653575 : *plen = len + 4;
480 653575 : return NT_STATUS_OK;
481 : }
482 :
483 659150 : NTSTATUS smb1_receive_talloc(TALLOC_CTX *mem_ctx,
484 : struct smbXsrv_connection *xconn,
485 : int sock,
486 : char **buffer, unsigned int timeout,
487 : size_t *p_unread, bool *p_encrypted,
488 : size_t *p_len,
489 : uint32_t *seqnum,
490 : bool trusted_channel)
491 : {
492 659150 : size_t len = 0;
493 7992 : NTSTATUS status;
494 :
495 659150 : *p_encrypted = false;
496 :
497 659150 : status = receive_smb_raw_talloc(mem_ctx, xconn, sock, buffer, timeout,
498 : p_unread, &len);
499 659150 : if (!NT_STATUS_IS_OK(status)) {
500 5575 : DEBUG(NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)?5:1,
501 : ("receive_smb_raw_talloc failed for client %s "
502 : "read error = %s.\n",
503 : smbXsrv_connection_dbg(xconn),
504 : nt_errstr(status)) );
505 5575 : return status;
506 : }
507 :
508 653575 : if (is_encrypted_packet((uint8_t *)*buffer)) {
509 185838 : status = srv_decrypt_buffer(xconn, *buffer);
510 185838 : if (!NT_STATUS_IS_OK(status)) {
511 0 : DEBUG(0, ("receive_smb_talloc: SMB decryption failed on "
512 : "incoming packet! Error %s\n",
513 : nt_errstr(status) ));
514 0 : return status;
515 : }
516 185838 : *p_encrypted = true;
517 : }
518 :
519 : /* Check the incoming SMB signature. */
520 653575 : if (!smb1_srv_check_sign_mac(xconn, *buffer, seqnum, trusted_channel)) {
521 0 : DEBUG(0, ("receive_smb: SMB Signature verification failed on "
522 : "incoming packet!\n"));
523 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
524 : }
525 :
526 653575 : *p_len = len;
527 653575 : return NT_STATUS_OK;
528 : }
529 :
530 : /****************************************************************************
531 : Function to push a message onto the tail of a linked list of smb messages ready
532 : for processing.
533 : ****************************************************************************/
534 :
535 3994 : static bool push_queued_message(struct smb_request *req,
536 : struct timeval request_time,
537 : struct timeval end_time,
538 : struct deferred_open_record *open_rec)
539 : {
540 3994 : int msg_len = smb_len(req->inbuf) + 4;
541 17 : struct pending_message_list *msg;
542 :
543 3994 : msg = talloc_zero(NULL, struct pending_message_list);
544 :
545 3994 : if(msg == NULL) {
546 0 : DEBUG(0,("push_message: malloc fail (1)\n"));
547 0 : return False;
548 : }
549 3994 : msg->sconn = req->sconn;
550 3994 : msg->xconn = req->xconn;
551 :
552 3994 : msg->buf = data_blob_talloc(msg, req->inbuf, msg_len);
553 3994 : if(msg->buf.data == NULL) {
554 0 : DEBUG(0,("push_message: malloc fail (2)\n"));
555 0 : TALLOC_FREE(msg);
556 0 : return False;
557 : }
558 :
559 3994 : msg->request_time = request_time;
560 3994 : msg->seqnum = req->seqnum;
561 3994 : msg->encrypted = req->encrypted;
562 3994 : msg->processed = false;
563 :
564 3994 : if (open_rec) {
565 3994 : msg->open_rec = talloc_move(msg, &open_rec);
566 : }
567 :
568 : #if 0
569 : msg->te = tevent_add_timer(msg->sconn->ev_ctx,
570 : msg,
571 : end_time,
572 : smbd_deferred_open_timer,
573 : msg);
574 : if (!msg->te) {
575 : DEBUG(0,("push_message: event_add_timed failed\n"));
576 : TALLOC_FREE(msg);
577 : return false;
578 : }
579 : #endif
580 :
581 3994 : DLIST_ADD_END(req->sconn->deferred_open_queue, msg);
582 :
583 3994 : DEBUG(10,("push_message: pushed message length %u on "
584 : "deferred_open_queue\n", (unsigned int)msg_len));
585 :
586 3977 : return True;
587 : }
588 :
589 : /****************************************************************************
590 : Function to push a deferred open smb message onto a linked list of local smb
591 : messages ready for processing.
592 : ****************************************************************************/
593 :
594 3994 : bool push_deferred_open_message_smb1(struct smb_request *req,
595 : struct timeval timeout,
596 : struct file_id id,
597 : struct deferred_open_record *open_rec)
598 : {
599 17 : struct timeval_buf tvbuf;
600 17 : struct timeval end_time;
601 :
602 3994 : if (req->unread_bytes) {
603 0 : DEBUG(0,("push_deferred_open_message_smb: logic error ! "
604 : "unread_bytes = %u\n",
605 : (unsigned int)req->unread_bytes ));
606 0 : smb_panic("push_deferred_open_message_smb: "
607 : "logic error unread_bytes != 0" );
608 : }
609 :
610 3994 : end_time = timeval_sum(&req->request_time, &timeout);
611 :
612 3994 : DBG_DEBUG("pushing message len %u mid %"PRIu64" timeout time [%s]\n",
613 : (unsigned int) smb_len(req->inbuf)+4,
614 : req->mid,
615 : timeval_str_buf(&end_time, false, true, &tvbuf));
616 :
617 3994 : return push_queued_message(req, req->request_time, end_time, open_rec);
618 : }
619 :
620 : /*
621 : * Only allow 5 outstanding trans requests. We're allocating memory, so
622 : * prevent a DoS.
623 : */
624 :
625 55107 : NTSTATUS allow_new_trans(struct trans_state *list, uint64_t mid)
626 : {
627 55107 : int count = 0;
628 55107 : for (; list != NULL; list = list->next) {
629 :
630 0 : if (list->mid == mid) {
631 0 : return NT_STATUS_INVALID_PARAMETER;
632 : }
633 :
634 0 : count += 1;
635 : }
636 55107 : if (count > 5) {
637 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
638 : }
639 :
640 55107 : return NT_STATUS_OK;
641 : }
642 :
643 : /*
644 : These flags determine some of the permissions required to do an operation
645 :
646 : Note that I don't set NEED_WRITE on some write operations because they
647 : are used by some brain-dead clients when printing, and I don't want to
648 : force write permissions on print services.
649 : */
650 : #define AS_USER (1<<0)
651 : #define NEED_WRITE (1<<1) /* Must be paired with AS_USER */
652 : #define TIME_INIT (1<<2)
653 : #define CAN_IPC (1<<3) /* Must be paired with AS_USER */
654 : #define AS_GUEST (1<<5) /* Must *NOT* be paired with AS_USER */
655 : #define DO_CHDIR (1<<6)
656 :
657 : /*
658 : define a list of possible SMB messages and their corresponding
659 : functions. Any message that has a NULL function is unimplemented -
660 : please feel free to contribute implementations!
661 : */
662 : static const struct smb_message_struct {
663 : const char *name;
664 : void (*fn)(struct smb_request *req);
665 : int flags;
666 : } smb_messages[256] = {
667 :
668 : /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
669 : /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
670 : /* 0x02 */ { "SMBopen",reply_open,AS_USER },
671 : /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
672 : /* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
673 : /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
674 : /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
675 : /* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
676 : /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
677 : /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
678 : /* 0x0a */ { "SMBread",reply_read,AS_USER},
679 : /* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
680 : /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
681 : /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
682 : /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
683 : /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
684 : /* 0x10 */ { "SMBcheckpath",reply_checkpath,AS_USER},
685 : /* 0x11 */ { "SMBexit",reply_exit,DO_CHDIR},
686 : /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
687 : /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
688 : /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
689 : /* 0x15 */ { NULL, NULL, 0 },
690 : /* 0x16 */ { NULL, NULL, 0 },
691 : /* 0x17 */ { NULL, NULL, 0 },
692 : /* 0x18 */ { NULL, NULL, 0 },
693 : /* 0x19 */ { NULL, NULL, 0 },
694 : /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
695 : /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
696 : /* 0x1c */ { "SMBreadBs",reply_readbs,AS_USER },
697 : /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
698 : /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
699 : /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
700 : /* 0x20 */ { "SMBwritec", NULL,0},
701 : /* 0x21 */ { NULL, NULL, 0 },
702 : /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
703 : /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
704 : /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
705 : /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
706 : /* 0x26 */ { "SMBtranss",reply_transs,AS_USER | CAN_IPC},
707 : /* 0x27 */ { "SMBioctl",reply_ioctl,0},
708 : /* 0x28 */ { "SMBioctls", NULL,AS_USER},
709 : /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
710 : /* 0x2a */ { "SMBmove", NULL,AS_USER | NEED_WRITE },
711 : /* 0x2b */ { "SMBecho",reply_echo,0},
712 : /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
713 : /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
714 : /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
715 : /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
716 : /* 0x30 */ { NULL, NULL, 0 },
717 : /* 0x31 */ { NULL, NULL, 0 },
718 : /* 0x32 */ { "SMBtrans2",reply_trans2, AS_USER | CAN_IPC },
719 : /* 0x33 */ { "SMBtranss2",reply_transs2, AS_USER | CAN_IPC },
720 : /* 0x34 */ { "SMBfindclose",reply_findclose,AS_USER},
721 : /* 0x35 */ { "SMBfindnclose",reply_findnclose,AS_USER},
722 : /* 0x36 */ { NULL, NULL, 0 },
723 : /* 0x37 */ { NULL, NULL, 0 },
724 : /* 0x38 */ { NULL, NULL, 0 },
725 : /* 0x39 */ { NULL, NULL, 0 },
726 : /* 0x3a */ { NULL, NULL, 0 },
727 : /* 0x3b */ { NULL, NULL, 0 },
728 : /* 0x3c */ { NULL, NULL, 0 },
729 : /* 0x3d */ { NULL, NULL, 0 },
730 : /* 0x3e */ { NULL, NULL, 0 },
731 : /* 0x3f */ { NULL, NULL, 0 },
732 : /* 0x40 */ { NULL, NULL, 0 },
733 : /* 0x41 */ { NULL, NULL, 0 },
734 : /* 0x42 */ { NULL, NULL, 0 },
735 : /* 0x43 */ { NULL, NULL, 0 },
736 : /* 0x44 */ { NULL, NULL, 0 },
737 : /* 0x45 */ { NULL, NULL, 0 },
738 : /* 0x46 */ { NULL, NULL, 0 },
739 : /* 0x47 */ { NULL, NULL, 0 },
740 : /* 0x48 */ { NULL, NULL, 0 },
741 : /* 0x49 */ { NULL, NULL, 0 },
742 : /* 0x4a */ { NULL, NULL, 0 },
743 : /* 0x4b */ { NULL, NULL, 0 },
744 : /* 0x4c */ { NULL, NULL, 0 },
745 : /* 0x4d */ { NULL, NULL, 0 },
746 : /* 0x4e */ { NULL, NULL, 0 },
747 : /* 0x4f */ { NULL, NULL, 0 },
748 : /* 0x50 */ { NULL, NULL, 0 },
749 : /* 0x51 */ { NULL, NULL, 0 },
750 : /* 0x52 */ { NULL, NULL, 0 },
751 : /* 0x53 */ { NULL, NULL, 0 },
752 : /* 0x54 */ { NULL, NULL, 0 },
753 : /* 0x55 */ { NULL, NULL, 0 },
754 : /* 0x56 */ { NULL, NULL, 0 },
755 : /* 0x57 */ { NULL, NULL, 0 },
756 : /* 0x58 */ { NULL, NULL, 0 },
757 : /* 0x59 */ { NULL, NULL, 0 },
758 : /* 0x5a */ { NULL, NULL, 0 },
759 : /* 0x5b */ { NULL, NULL, 0 },
760 : /* 0x5c */ { NULL, NULL, 0 },
761 : /* 0x5d */ { NULL, NULL, 0 },
762 : /* 0x5e */ { NULL, NULL, 0 },
763 : /* 0x5f */ { NULL, NULL, 0 },
764 : /* 0x60 */ { NULL, NULL, 0 },
765 : /* 0x61 */ { NULL, NULL, 0 },
766 : /* 0x62 */ { NULL, NULL, 0 },
767 : /* 0x63 */ { NULL, NULL, 0 },
768 : /* 0x64 */ { NULL, NULL, 0 },
769 : /* 0x65 */ { NULL, NULL, 0 },
770 : /* 0x66 */ { NULL, NULL, 0 },
771 : /* 0x67 */ { NULL, NULL, 0 },
772 : /* 0x68 */ { NULL, NULL, 0 },
773 : /* 0x69 */ { NULL, NULL, 0 },
774 : /* 0x6a */ { NULL, NULL, 0 },
775 : /* 0x6b */ { NULL, NULL, 0 },
776 : /* 0x6c */ { NULL, NULL, 0 },
777 : /* 0x6d */ { NULL, NULL, 0 },
778 : /* 0x6e */ { NULL, NULL, 0 },
779 : /* 0x6f */ { NULL, NULL, 0 },
780 : /* 0x70 */ { "SMBtcon",reply_tcon,0},
781 : /* 0x71 */ { "SMBtdis",reply_tdis,DO_CHDIR},
782 : /* 0x72 */ { "SMBnegprot",reply_negprot,0},
783 : /* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0},
784 : /* 0x74 */ { "SMBulogoffX",reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
785 : /* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
786 : /* 0x76 */ { NULL, NULL, 0 },
787 : /* 0x77 */ { NULL, NULL, 0 },
788 : /* 0x78 */ { NULL, NULL, 0 },
789 : /* 0x79 */ { NULL, NULL, 0 },
790 : /* 0x7a */ { NULL, NULL, 0 },
791 : /* 0x7b */ { NULL, NULL, 0 },
792 : /* 0x7c */ { NULL, NULL, 0 },
793 : /* 0x7d */ { NULL, NULL, 0 },
794 : /* 0x7e */ { NULL, NULL, 0 },
795 : /* 0x7f */ { NULL, NULL, 0 },
796 : /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
797 : /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
798 : /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
799 : /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
800 : /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
801 : /* 0x85 */ { NULL, NULL, 0 },
802 : /* 0x86 */ { NULL, NULL, 0 },
803 : /* 0x87 */ { NULL, NULL, 0 },
804 : /* 0x88 */ { NULL, NULL, 0 },
805 : /* 0x89 */ { NULL, NULL, 0 },
806 : /* 0x8a */ { NULL, NULL, 0 },
807 : /* 0x8b */ { NULL, NULL, 0 },
808 : /* 0x8c */ { NULL, NULL, 0 },
809 : /* 0x8d */ { NULL, NULL, 0 },
810 : /* 0x8e */ { NULL, NULL, 0 },
811 : /* 0x8f */ { NULL, NULL, 0 },
812 : /* 0x90 */ { NULL, NULL, 0 },
813 : /* 0x91 */ { NULL, NULL, 0 },
814 : /* 0x92 */ { NULL, NULL, 0 },
815 : /* 0x93 */ { NULL, NULL, 0 },
816 : /* 0x94 */ { NULL, NULL, 0 },
817 : /* 0x95 */ { NULL, NULL, 0 },
818 : /* 0x96 */ { NULL, NULL, 0 },
819 : /* 0x97 */ { NULL, NULL, 0 },
820 : /* 0x98 */ { NULL, NULL, 0 },
821 : /* 0x99 */ { NULL, NULL, 0 },
822 : /* 0x9a */ { NULL, NULL, 0 },
823 : /* 0x9b */ { NULL, NULL, 0 },
824 : /* 0x9c */ { NULL, NULL, 0 },
825 : /* 0x9d */ { NULL, NULL, 0 },
826 : /* 0x9e */ { NULL, NULL, 0 },
827 : /* 0x9f */ { NULL, NULL, 0 },
828 : /* 0xa0 */ { "SMBnttrans",reply_nttrans, AS_USER | CAN_IPC },
829 : /* 0xa1 */ { "SMBnttranss",reply_nttranss, AS_USER | CAN_IPC },
830 : /* 0xa2 */ { "SMBntcreateX",reply_ntcreate_and_X, AS_USER | CAN_IPC },
831 : /* 0xa3 */ { NULL, NULL, 0 },
832 : /* 0xa4 */ { "SMBntcancel",reply_ntcancel, 0 },
833 : /* 0xa5 */ { "SMBntrename",reply_ntrename, AS_USER | NEED_WRITE },
834 : /* 0xa6 */ { NULL, NULL, 0 },
835 : /* 0xa7 */ { NULL, NULL, 0 },
836 : /* 0xa8 */ { NULL, NULL, 0 },
837 : /* 0xa9 */ { NULL, NULL, 0 },
838 : /* 0xaa */ { NULL, NULL, 0 },
839 : /* 0xab */ { NULL, NULL, 0 },
840 : /* 0xac */ { NULL, NULL, 0 },
841 : /* 0xad */ { NULL, NULL, 0 },
842 : /* 0xae */ { NULL, NULL, 0 },
843 : /* 0xaf */ { NULL, NULL, 0 },
844 : /* 0xb0 */ { NULL, NULL, 0 },
845 : /* 0xb1 */ { NULL, NULL, 0 },
846 : /* 0xb2 */ { NULL, NULL, 0 },
847 : /* 0xb3 */ { NULL, NULL, 0 },
848 : /* 0xb4 */ { NULL, NULL, 0 },
849 : /* 0xb5 */ { NULL, NULL, 0 },
850 : /* 0xb6 */ { NULL, NULL, 0 },
851 : /* 0xb7 */ { NULL, NULL, 0 },
852 : /* 0xb8 */ { NULL, NULL, 0 },
853 : /* 0xb9 */ { NULL, NULL, 0 },
854 : /* 0xba */ { NULL, NULL, 0 },
855 : /* 0xbb */ { NULL, NULL, 0 },
856 : /* 0xbc */ { NULL, NULL, 0 },
857 : /* 0xbd */ { NULL, NULL, 0 },
858 : /* 0xbe */ { NULL, NULL, 0 },
859 : /* 0xbf */ { NULL, NULL, 0 },
860 : /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER},
861 : /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
862 : /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
863 : /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
864 : /* 0xc4 */ { NULL, NULL, 0 },
865 : /* 0xc5 */ { NULL, NULL, 0 },
866 : /* 0xc6 */ { NULL, NULL, 0 },
867 : /* 0xc7 */ { NULL, NULL, 0 },
868 : /* 0xc8 */ { NULL, NULL, 0 },
869 : /* 0xc9 */ { NULL, NULL, 0 },
870 : /* 0xca */ { NULL, NULL, 0 },
871 : /* 0xcb */ { NULL, NULL, 0 },
872 : /* 0xcc */ { NULL, NULL, 0 },
873 : /* 0xcd */ { NULL, NULL, 0 },
874 : /* 0xce */ { NULL, NULL, 0 },
875 : /* 0xcf */ { NULL, NULL, 0 },
876 : /* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
877 : /* 0xd1 */ { "SMBsendb", NULL,AS_GUEST},
878 : /* 0xd2 */ { "SMBfwdname", NULL,AS_GUEST},
879 : /* 0xd3 */ { "SMBcancelf", NULL,AS_GUEST},
880 : /* 0xd4 */ { "SMBgetmac", NULL,AS_GUEST},
881 : /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
882 : /* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
883 : /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
884 : /* 0xd8 */ { NULL, NULL, 0 },
885 : /* 0xd9 */ { NULL, NULL, 0 },
886 : /* 0xda */ { NULL, NULL, 0 },
887 : /* 0xdb */ { NULL, NULL, 0 },
888 : /* 0xdc */ { NULL, NULL, 0 },
889 : /* 0xdd */ { NULL, NULL, 0 },
890 : /* 0xde */ { NULL, NULL, 0 },
891 : /* 0xdf */ { NULL, NULL, 0 },
892 : /* 0xe0 */ { NULL, NULL, 0 },
893 : /* 0xe1 */ { NULL, NULL, 0 },
894 : /* 0xe2 */ { NULL, NULL, 0 },
895 : /* 0xe3 */ { NULL, NULL, 0 },
896 : /* 0xe4 */ { NULL, NULL, 0 },
897 : /* 0xe5 */ { NULL, NULL, 0 },
898 : /* 0xe6 */ { NULL, NULL, 0 },
899 : /* 0xe7 */ { NULL, NULL, 0 },
900 : /* 0xe8 */ { NULL, NULL, 0 },
901 : /* 0xe9 */ { NULL, NULL, 0 },
902 : /* 0xea */ { NULL, NULL, 0 },
903 : /* 0xeb */ { NULL, NULL, 0 },
904 : /* 0xec */ { NULL, NULL, 0 },
905 : /* 0xed */ { NULL, NULL, 0 },
906 : /* 0xee */ { NULL, NULL, 0 },
907 : /* 0xef */ { NULL, NULL, 0 },
908 : /* 0xf0 */ { NULL, NULL, 0 },
909 : /* 0xf1 */ { NULL, NULL, 0 },
910 : /* 0xf2 */ { NULL, NULL, 0 },
911 : /* 0xf3 */ { NULL, NULL, 0 },
912 : /* 0xf4 */ { NULL, NULL, 0 },
913 : /* 0xf5 */ { NULL, NULL, 0 },
914 : /* 0xf6 */ { NULL, NULL, 0 },
915 : /* 0xf7 */ { NULL, NULL, 0 },
916 : /* 0xf8 */ { NULL, NULL, 0 },
917 : /* 0xf9 */ { NULL, NULL, 0 },
918 : /* 0xfa */ { NULL, NULL, 0 },
919 : /* 0xfb */ { NULL, NULL, 0 },
920 : /* 0xfc */ { NULL, NULL, 0 },
921 : /* 0xfd */ { NULL, NULL, 0 },
922 : /* 0xfe */ { NULL, NULL, 0 },
923 : /* 0xff */ { NULL, NULL, 0 }
924 :
925 : };
926 :
927 :
928 : /*******************************************************************
929 : Dump a packet to a file.
930 : ********************************************************************/
931 :
932 657285 : static void smb_dump(const char *name, int type, const char *data)
933 : {
934 7878 : size_t len;
935 7878 : int fd, i;
936 657285 : char *fname = NULL;
937 657285 : if (DEBUGLEVEL < 50) {
938 649407 : return;
939 : }
940 :
941 0 : len = smb_len_tcp(data)+4;
942 0 : for (i=1;i<100;i++) {
943 0 : fname = talloc_asprintf(talloc_tos(),
944 : "/tmp/%s.%d.%s",
945 : name,
946 : i,
947 : type ? "req" : "resp");
948 0 : if (fname == NULL) {
949 0 : return;
950 : }
951 0 : fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
952 0 : if (fd != -1 || errno != EEXIST) break;
953 0 : TALLOC_FREE(fname);
954 : }
955 0 : if (fd != -1) {
956 0 : ssize_t ret = write(fd, data, len);
957 0 : if (ret != len)
958 0 : DEBUG(0,("smb_dump: problem: write returned %d\n", (int)ret ));
959 0 : close(fd);
960 0 : DEBUG(0,("created %s len %lu\n", fname, (unsigned long)len));
961 : }
962 0 : TALLOC_FREE(fname);
963 : }
964 :
965 643109 : static void smb1srv_update_crypto_flags(struct smbXsrv_session *session,
966 : struct smb_request *req,
967 : uint8_t type,
968 : bool *update_session_globalp,
969 : bool *update_tcon_globalp)
970 : {
971 643109 : connection_struct *conn = req->conn;
972 643109 : struct smbXsrv_tcon *tcon = conn ? conn->tcon : NULL;
973 643109 : uint8_t encrypt_flag = SMBXSRV_PROCESSED_UNENCRYPTED_PACKET;
974 643109 : uint8_t sign_flag = SMBXSRV_PROCESSED_UNSIGNED_PACKET;
975 643109 : bool update_session = false;
976 643109 : bool update_tcon = false;
977 :
978 643109 : if (req->encrypted) {
979 185864 : encrypt_flag = SMBXSRV_PROCESSED_ENCRYPTED_PACKET;
980 : }
981 :
982 643109 : if (smb1_srv_is_signing_active(req->xconn)) {
983 68882 : sign_flag = SMBXSRV_PROCESSED_SIGNED_PACKET;
984 566625 : } else if ((type == SMBecho) || (type == SMBsesssetupX)) {
985 : /*
986 : * echo can be unsigned. Session setup except final
987 : * session setup response too
988 : */
989 6974 : sign_flag &= ~SMBXSRV_PROCESSED_UNSIGNED_PACKET;
990 : }
991 :
992 1286218 : update_session |= smbXsrv_set_crypto_flag(
993 643109 : &session->global->encryption_flags, encrypt_flag);
994 1286218 : update_session |= smbXsrv_set_crypto_flag(
995 643109 : &session->global->signing_flags, sign_flag);
996 :
997 643109 : if (tcon) {
998 1250050 : update_tcon |= smbXsrv_set_crypto_flag(
999 625025 : &tcon->global->encryption_flags, encrypt_flag);
1000 625025 : update_tcon |= smbXsrv_set_crypto_flag(
1001 625025 : &tcon->global->signing_flags, sign_flag);
1002 : }
1003 :
1004 643109 : if (update_session) {
1005 13135 : session->global->channels[0].encryption_cipher = SMB_ENCRYPTION_GSSAPI;
1006 : }
1007 :
1008 643109 : *update_session_globalp = update_session;
1009 643109 : *update_tcon_globalp = update_tcon;
1010 643109 : return;
1011 : }
1012 :
1013 355066 : static void set_current_case_sensitive(connection_struct *conn, uint16_t flags)
1014 : {
1015 7314 : int snum;
1016 7314 : enum remote_arch_types ra_type;
1017 :
1018 355066 : SMB_ASSERT(conn != NULL);
1019 355066 : SMB_ASSERT(!conn->sconn->using_smb2);
1020 :
1021 355066 : snum = SNUM(conn);
1022 :
1023 : /*
1024 : * Obey the client case sensitivity requests - only for clients that
1025 : * support it. */
1026 355066 : switch (lp_case_sensitive(snum)) {
1027 352658 : case Auto:
1028 : /*
1029 : * We need this ugliness due to DOS/Win9x clients that lie
1030 : * about case insensitivity. */
1031 352658 : ra_type = get_remote_arch();
1032 352658 : if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
1033 : /*
1034 : * Client can't support per-packet case sensitive
1035 : * pathnames. */
1036 8 : conn->case_sensitive = false;
1037 : } else {
1038 352650 : conn->case_sensitive =
1039 352650 : !(flags & FLAG_CASELESS_PATHNAMES);
1040 : }
1041 345344 : break;
1042 2408 : case True:
1043 2408 : conn->case_sensitive = true;
1044 2408 : break;
1045 0 : default:
1046 0 : conn->case_sensitive = false;
1047 0 : break;
1048 : }
1049 355066 : }
1050 :
1051 : /****************************************************************************
1052 : Prepare everything for calling the actual request function, and potentially
1053 : call the request function via the "new" interface.
1054 :
1055 : Return False if the "legacy" function needs to be called, everything is
1056 : prepared.
1057 :
1058 : Return True if we're done.
1059 :
1060 : I know this API sucks, but it is the one with the least code change I could
1061 : find.
1062 : ****************************************************************************/
1063 :
1064 657285 : static connection_struct *switch_message(uint8_t type, struct smb_request *req)
1065 : {
1066 7878 : const struct loadparm_substitution *lp_sub =
1067 657285 : loadparm_s3_global_substitution();
1068 7878 : int flags;
1069 7878 : uint64_t session_tag;
1070 657285 : connection_struct *conn = NULL;
1071 657285 : struct smbXsrv_connection *xconn = req->xconn;
1072 657285 : NTTIME now = timeval_to_nttime(&req->request_time);
1073 657285 : struct smbXsrv_session *session = NULL;
1074 7878 : NTSTATUS status;
1075 :
1076 657285 : errno = 0;
1077 :
1078 657285 : if (!xconn->smb1.negprot.done) {
1079 5988 : switch (type) {
1080 : /*
1081 : * Without a negprot the request must
1082 : * either be a negprot, or one of the
1083 : * evil old SMB mailslot messaging types.
1084 : */
1085 5847 : case SMBnegprot:
1086 : case SMBsendstrt:
1087 : case SMBsendend:
1088 : case SMBsendtxt:
1089 5847 : break;
1090 0 : default:
1091 0 : exit_server_cleanly("The first request "
1092 : "should be a negprot");
1093 : }
1094 : }
1095 :
1096 657285 : if (smb_messages[type].fn == NULL) {
1097 0 : DEBUG(0,("Unknown message type %d!\n",type));
1098 0 : smb_dump("Unknown", 1, (const char *)req->inbuf);
1099 0 : reply_unknown_new(req, type);
1100 0 : return NULL;
1101 : }
1102 :
1103 657285 : flags = smb_messages[type].flags;
1104 :
1105 : /* In share mode security we must ignore the vuid. */
1106 657285 : session_tag = req->vuid;
1107 657285 : conn = req->conn;
1108 :
1109 657285 : DEBUG(3,("switch message %s (pid %d) conn 0x%lx\n", smb_fn_name(type),
1110 : (int)getpid(), (unsigned long)conn));
1111 :
1112 657285 : smb_dump(smb_fn_name(type), 1, (const char *)req->inbuf);
1113 :
1114 : /* Ensure this value is replaced in the incoming packet. */
1115 657285 : SSVAL(discard_const_p(uint8_t, req->inbuf),smb_uid,session_tag);
1116 :
1117 : /*
1118 : * Ensure the correct username is in current_user_info. This is a
1119 : * really ugly bugfix for problems with multiple session_setup_and_X's
1120 : * being done and allowing %U and %G substitutions to work correctly.
1121 : * There is a reason this code is done here, don't move it unless you
1122 : * know what you're doing... :-).
1123 : * JRA.
1124 : */
1125 :
1126 : /*
1127 : * lookup an existing session
1128 : *
1129 : * Note: for now we only check for NT_STATUS_NETWORK_SESSION_EXPIRED
1130 : * here, the main check is still in change_to_user()
1131 : */
1132 657285 : status = smb1srv_session_lookup(xconn,
1133 : session_tag,
1134 : now,
1135 : &session);
1136 657285 : if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
1137 8 : switch (type) {
1138 4 : case SMBsesssetupX:
1139 4 : status = NT_STATUS_OK;
1140 4 : break;
1141 4 : default:
1142 4 : DEBUG(1,("Error: session %llu is expired, mid=%llu.\n",
1143 : (unsigned long long)session_tag,
1144 : (unsigned long long)req->mid));
1145 4 : reply_nterror(req, NT_STATUS_NETWORK_SESSION_EXPIRED);
1146 4 : return conn;
1147 : }
1148 : }
1149 :
1150 657281 : if (session != NULL &&
1151 643136 : session->global->auth_session_info != NULL &&
1152 635912 : !(flags & AS_USER))
1153 : {
1154 : /*
1155 : * change_to_user() implies set_current_user_info()
1156 : * and chdir_connect_service().
1157 : *
1158 : * So we only call set_current_user_info if
1159 : * we don't have AS_USER specified.
1160 : */
1161 280854 : set_current_user_info(
1162 280565 : session->global->auth_session_info->unix_info->sanitized_username,
1163 280854 : session->global->auth_session_info->unix_info->unix_name,
1164 280854 : session->global->auth_session_info->info->domain_name);
1165 : }
1166 :
1167 : /* Does this call need to be run as the connected user? */
1168 657281 : if (flags & AS_USER) {
1169 :
1170 : /* Does this call need a valid tree connection? */
1171 355087 : if (!conn) {
1172 : /*
1173 : * Amazingly, the error code depends on the command
1174 : * (from Samba4).
1175 : */
1176 21 : if (type == SMBntcreateX) {
1177 0 : reply_nterror(req, NT_STATUS_INVALID_HANDLE);
1178 : } else {
1179 21 : reply_nterror(req, NT_STATUS_NETWORK_NAME_DELETED);
1180 : }
1181 21 : return NULL;
1182 : }
1183 :
1184 355066 : set_current_case_sensitive(conn, SVAL(req->inbuf,smb_flg));
1185 :
1186 : /*
1187 : * change_to_user() implies set_current_user_info()
1188 : * and chdir_connect_service().
1189 : */
1190 355066 : if (!change_to_user_and_service(conn,session_tag)) {
1191 17 : DEBUG(0, ("Error: Could not change to user. Removing "
1192 : "deferred open, mid=%llu.\n",
1193 : (unsigned long long)req->mid));
1194 17 : reply_force_doserror(req, ERRSRV, ERRbaduid);
1195 17 : return conn;
1196 : }
1197 :
1198 : /* All NEED_WRITE and CAN_IPC flags must also have AS_USER. */
1199 :
1200 : /* Does it need write permission? */
1201 355049 : if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) {
1202 4 : reply_nterror(req, NT_STATUS_MEDIA_WRITE_PROTECTED);
1203 4 : return conn;
1204 : }
1205 :
1206 : /* IPC services are limited */
1207 355045 : if (IS_IPC(conn) && !(flags & CAN_IPC)) {
1208 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1209 0 : return conn;
1210 : }
1211 302194 : } else if (flags & AS_GUEST) {
1212 : /*
1213 : * Does this protocol need to be run as guest? (Only archane
1214 : * messenger service requests have this...)
1215 : */
1216 18 : if (!change_to_guest()) {
1217 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1218 0 : return conn;
1219 : }
1220 : } else {
1221 : /* This call needs to be run as root */
1222 302176 : change_to_root_user();
1223 : }
1224 :
1225 : /* load service specific parameters */
1226 657239 : if (conn) {
1227 625045 : if (req->encrypted) {
1228 185618 : conn->encrypted_tid = true;
1229 : /* encrypted required from now on. */
1230 185618 : conn->encrypt_level = SMB_SIGNING_REQUIRED;
1231 439427 : } else if (ENCRYPTION_REQUIRED(conn)) {
1232 14 : if (req->cmd != SMBtrans2 && req->cmd != SMBtranss2) {
1233 14 : DEBUG(1,("service[%s] requires encryption"
1234 : "%s ACCESS_DENIED. mid=%llu\n",
1235 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
1236 : smb_fn_name(type),
1237 : (unsigned long long)req->mid));
1238 14 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1239 14 : return conn;
1240 : }
1241 : }
1242 :
1243 625031 : if (flags & DO_CHDIR) {
1244 16 : bool ok;
1245 :
1246 6811 : ok = chdir_current_service(conn);
1247 6811 : if (!ok) {
1248 0 : reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1249 0 : return conn;
1250 : }
1251 : }
1252 625031 : conn->num_smb_operations++;
1253 : }
1254 :
1255 : /*
1256 : * Update encryption and signing state tracking flags that are
1257 : * used by smbstatus to display signing and encryption status.
1258 : */
1259 657225 : if (session != NULL) {
1260 643109 : bool update_session_global = false;
1261 643109 : bool update_tcon_global = false;
1262 :
1263 643109 : req->session = session;
1264 :
1265 643109 : smb1srv_update_crypto_flags(session, req, type,
1266 : &update_session_global,
1267 : &update_tcon_global);
1268 :
1269 643109 : if (update_session_global) {
1270 13135 : status = smbXsrv_session_update(session);
1271 13135 : if (!NT_STATUS_IS_OK(status)) {
1272 0 : reply_nterror(req, NT_STATUS_UNSUCCESSFUL);
1273 0 : return conn;
1274 : }
1275 : }
1276 :
1277 643109 : if (update_tcon_global) {
1278 9086 : status = smbXsrv_tcon_update(req->conn->tcon);
1279 9086 : if (!NT_STATUS_IS_OK(status)) {
1280 0 : reply_nterror(req, NT_STATUS_UNSUCCESSFUL);
1281 0 : return conn;
1282 : }
1283 : }
1284 : }
1285 :
1286 657225 : smb_messages[type].fn(req);
1287 657219 : return req->conn;
1288 : }
1289 :
1290 : /****************************************************************************
1291 : Construct a reply to the incoming packet.
1292 : ****************************************************************************/
1293 :
1294 657216 : void construct_reply(struct smbXsrv_connection *xconn,
1295 : char *inbuf,
1296 : int size,
1297 : size_t unread_bytes,
1298 : uint32_t seqnum,
1299 : bool encrypted)
1300 : {
1301 657216 : struct smbd_server_connection *sconn = xconn->client->sconn;
1302 7873 : struct smb_request *req;
1303 :
1304 657216 : if (!(req = talloc(talloc_tos(), struct smb_request))) {
1305 0 : smb_panic("could not allocate smb_request");
1306 : }
1307 :
1308 657216 : if (!init_smb1_request(req, sconn, xconn, (uint8_t *)inbuf, unread_bytes,
1309 : encrypted, seqnum)) {
1310 0 : exit_server_cleanly("Invalid SMB request");
1311 : }
1312 :
1313 657216 : req->inbuf = (uint8_t *)talloc_move(req, &inbuf);
1314 :
1315 657216 : req->conn = switch_message(req->cmd, req);
1316 :
1317 657210 : if (req->outbuf == NULL) {
1318 : /*
1319 : * Request has suspended itself, will come
1320 : * back here.
1321 : */
1322 207914 : return;
1323 : }
1324 447787 : if (CVAL(req->outbuf,0) == 0) {
1325 447787 : show_msg((char *)req->outbuf);
1326 : }
1327 447787 : smb_request_done(req);
1328 : }
1329 :
1330 39 : static void construct_reply_chain(struct smbXsrv_connection *xconn,
1331 : char *inbuf,
1332 : int size,
1333 : uint32_t seqnum,
1334 : bool encrypted)
1335 : {
1336 39 : struct smb_request **reqs = NULL;
1337 3 : struct smb_request *req;
1338 3 : unsigned num_reqs;
1339 3 : bool ok;
1340 :
1341 39 : ok = smb1_parse_chain(xconn, (uint8_t *)inbuf, xconn, encrypted,
1342 : seqnum, &reqs, &num_reqs);
1343 39 : if (!ok) {
1344 0 : char errbuf[smb_size];
1345 0 : error_packet(errbuf, 0, 0, NT_STATUS_INVALID_PARAMETER,
1346 : __LINE__, __FILE__);
1347 0 : if (!smb1_srv_send(xconn, errbuf, true, seqnum, encrypted)) {
1348 0 : exit_server_cleanly("construct_reply_chain: "
1349 : "smb1_srv_send failed.");
1350 : }
1351 0 : return;
1352 : }
1353 :
1354 39 : req = reqs[0];
1355 39 : req->inbuf = (uint8_t *)talloc_move(reqs, &inbuf);
1356 :
1357 39 : req->conn = switch_message(req->cmd, req);
1358 :
1359 39 : if (req->outbuf == NULL) {
1360 : /*
1361 : * Request has suspended itself, will come
1362 : * back here.
1363 : */
1364 12 : return;
1365 : }
1366 27 : smb_request_done(req);
1367 : }
1368 :
1369 : /*
1370 : * To be called from an async SMB handler that is potentially chained
1371 : * when it is finished for shipping.
1372 : */
1373 :
1374 456472 : void smb_request_done(struct smb_request *req)
1375 : {
1376 456472 : struct smb_request **reqs = NULL;
1377 6512 : struct smb_request *first_req;
1378 6512 : size_t i, num_reqs, next_index;
1379 6512 : NTSTATUS status;
1380 :
1381 456472 : if (req->chain == NULL) {
1382 456445 : first_req = req;
1383 456445 : goto shipit;
1384 : }
1385 :
1386 27 : reqs = req->chain;
1387 27 : num_reqs = talloc_array_length(reqs);
1388 :
1389 27 : for (i=0; i<num_reqs; i++) {
1390 27 : if (reqs[i] == req) {
1391 24 : break;
1392 : }
1393 : }
1394 27 : if (i == num_reqs) {
1395 : /*
1396 : * Invalid chain, should not happen
1397 : */
1398 0 : status = NT_STATUS_INTERNAL_ERROR;
1399 0 : goto error;
1400 : }
1401 27 : next_index = i+1;
1402 :
1403 57 : while ((next_index < num_reqs) && (IVAL(req->outbuf, smb_rcls) == 0)) {
1404 30 : struct smb_request *next = reqs[next_index];
1405 2 : struct smbXsrv_tcon *tcon;
1406 30 : NTTIME now = timeval_to_nttime(&req->request_time);
1407 :
1408 30 : next->vuid = SVAL(req->outbuf, smb_uid);
1409 30 : next->tid = SVAL(req->outbuf, smb_tid);
1410 30 : status = smb1srv_tcon_lookup(req->xconn, next->tid,
1411 : now, &tcon);
1412 :
1413 30 : if (NT_STATUS_IS_OK(status)) {
1414 26 : next->conn = tcon->compat;
1415 : } else {
1416 4 : next->conn = NULL;
1417 : }
1418 30 : next->chain_fsp = req->chain_fsp;
1419 30 : next->inbuf = req->inbuf;
1420 :
1421 30 : req = next;
1422 30 : req->conn = switch_message(req->cmd, req);
1423 :
1424 30 : if (req->outbuf == NULL) {
1425 : /*
1426 : * Request has suspended itself, will come
1427 : * back here.
1428 : */
1429 0 : return;
1430 : }
1431 30 : next_index += 1;
1432 : }
1433 :
1434 27 : first_req = reqs[0];
1435 :
1436 57 : for (i=1; i<next_index; i++) {
1437 2 : bool ok;
1438 :
1439 30 : ok = smb_splice_chain(&first_req->outbuf, reqs[i]->outbuf);
1440 30 : if (!ok) {
1441 0 : status = NT_STATUS_INTERNAL_ERROR;
1442 0 : goto error;
1443 : }
1444 : }
1445 :
1446 27 : SSVAL(first_req->outbuf, smb_uid, SVAL(req->outbuf, smb_uid));
1447 27 : SSVAL(first_req->outbuf, smb_tid, SVAL(req->outbuf, smb_tid));
1448 :
1449 : /*
1450 : * This scary statement intends to set the
1451 : * FLAGS2_32_BIT_ERROR_CODES flg2 field in first_req->outbuf
1452 : * to the value last_req->outbuf carries
1453 : */
1454 27 : SSVAL(first_req->outbuf, smb_flg2,
1455 : (SVAL(first_req->outbuf, smb_flg2) & ~FLAGS2_32_BIT_ERROR_CODES)
1456 : |(SVAL(req->outbuf, smb_flg2) & FLAGS2_32_BIT_ERROR_CODES));
1457 :
1458 : /*
1459 : * Transfer the error codes from the subrequest to the main one
1460 : */
1461 27 : SSVAL(first_req->outbuf, smb_rcls, SVAL(req->outbuf, smb_rcls));
1462 27 : SSVAL(first_req->outbuf, smb_err, SVAL(req->outbuf, smb_err));
1463 :
1464 27 : _smb_setlen_large(
1465 : first_req->outbuf, talloc_get_size(first_req->outbuf) - 4);
1466 :
1467 456472 : shipit:
1468 456472 : if (!smb1_srv_send(first_req->xconn,
1469 456472 : (char *)first_req->outbuf,
1470 : true,
1471 456472 : first_req->seqnum + 1,
1472 771170 : IS_CONN_ENCRYPTED(req->conn) ||
1473 321210 : first_req->encrypted)) {
1474 80 : exit_server_cleanly("construct_reply_chain: smb1_srv_send "
1475 : "failed.");
1476 : }
1477 456392 : TALLOC_FREE(req); /* non-chained case */
1478 456392 : TALLOC_FREE(reqs); /* chained case */
1479 449880 : return;
1480 :
1481 0 : error:
1482 : {
1483 0 : char errbuf[smb_size];
1484 0 : error_packet(errbuf, 0, 0, status, __LINE__, __FILE__);
1485 0 : if (!smb1_srv_send(req->xconn,
1486 : errbuf,
1487 : true,
1488 0 : req->seqnum + 1,
1489 0 : req->encrypted)) {
1490 0 : exit_server_cleanly("construct_reply_chain: "
1491 : "smb1_srv_send failed.");
1492 : }
1493 : }
1494 0 : TALLOC_FREE(req); /* non-chained case */
1495 0 : TALLOC_FREE(reqs); /* chained case */
1496 : }
1497 :
1498 : /****************************************************************************
1499 : Process an smb from the client
1500 : ****************************************************************************/
1501 :
1502 657267 : void process_smb1(struct smbXsrv_connection *xconn,
1503 : uint8_t *inbuf,
1504 : size_t nread,
1505 : size_t unread_bytes,
1506 : uint32_t seqnum,
1507 : bool encrypted)
1508 : {
1509 657267 : struct smbd_server_connection *sconn = xconn->client->sconn;
1510 :
1511 : /* Make sure this is an SMB packet. smb_size contains NetBIOS header
1512 : * so subtract 4 from it. */
1513 657267 : if ((nread < (smb_size - 4)) || !valid_smb1_header(inbuf)) {
1514 12 : DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",
1515 : smb_len(inbuf)));
1516 :
1517 : /* special magic for immediate exit */
1518 12 : if ((nread == 9) &&
1519 24 : (IVAL(inbuf, 4) == SMB_SUICIDE_PACKET) &&
1520 12 : lp_parm_bool(-1, "smbd", "suicide mode", false)) {
1521 12 : uint8_t exitcode = CVAL(inbuf, 8);
1522 12 : DBG_WARNING("SUICIDE: Exiting immediately with code %d\n",
1523 : (int)exitcode);
1524 12 : exit(exitcode);
1525 : }
1526 :
1527 0 : exit_server_cleanly("Non-SMB packet");
1528 : }
1529 :
1530 657255 : show_msg((char *)inbuf);
1531 :
1532 657255 : if ((unread_bytes == 0) && smb1_is_chain(inbuf)) {
1533 39 : construct_reply_chain(xconn,
1534 : (char *)inbuf,
1535 : nread,
1536 : seqnum,
1537 : encrypted);
1538 : } else {
1539 657216 : construct_reply(xconn,
1540 : (char *)inbuf,
1541 : nread,
1542 : unread_bytes,
1543 : seqnum,
1544 : encrypted);
1545 : }
1546 :
1547 657169 : sconn->trans_num++;
1548 657169 : }
1549 :
1550 : /****************************************************************************
1551 : Return a string containing the function name of a SMB command.
1552 : ****************************************************************************/
1553 :
1554 657299 : const char *smb_fn_name(int type)
1555 : {
1556 657299 : const char *unknown_name = "SMBunknown";
1557 :
1558 657299 : if (smb_messages[type].name == NULL)
1559 0 : return(unknown_name);
1560 :
1561 649421 : return(smb_messages[type].name);
1562 : }
1563 :
1564 : /****************************************************************************
1565 : Helper functions for contruct_reply.
1566 : ****************************************************************************/
1567 :
1568 5527 : void add_to_common_flags2(uint32_t v)
1569 : {
1570 5527 : common_flags2 |= v;
1571 5527 : }
1572 :
1573 32 : void remove_from_common_flags2(uint32_t v)
1574 : {
1575 32 : common_flags2 &= ~v;
1576 32 : }
1577 :
1578 : /**
1579 : * @brief Find the smb_cmd offset of the last command pushed
1580 : * @param[in] buf The buffer we're building up
1581 : * @retval Where can we put our next andx cmd?
1582 : *
1583 : * While chaining requests, the "next" request we're looking at needs to put
1584 : * its SMB_Command before the data the previous request already built up added
1585 : * to the chain. Find the offset to the place where we have to put our cmd.
1586 : */
1587 :
1588 30 : static bool find_andx_cmd_ofs(uint8_t *buf, size_t *pofs)
1589 : {
1590 2 : uint8_t cmd;
1591 2 : size_t ofs;
1592 :
1593 30 : cmd = CVAL(buf, smb_com);
1594 :
1595 30 : if (!smb1cli_is_andx_req(cmd)) {
1596 0 : return false;
1597 : }
1598 :
1599 28 : ofs = smb_vwv0;
1600 :
1601 38 : while (CVAL(buf, ofs) != 0xff) {
1602 :
1603 8 : if (!smb1cli_is_andx_req(CVAL(buf, ofs))) {
1604 0 : return false;
1605 : }
1606 :
1607 : /*
1608 : * ofs is from start of smb header, so add the 4 length
1609 : * bytes. The next cmd is right after the wct field.
1610 : */
1611 8 : ofs = SVAL(buf, ofs+2) + 4 + 1;
1612 :
1613 8 : if (ofs+4 >= talloc_get_size(buf)) {
1614 0 : return false;
1615 : }
1616 : }
1617 :
1618 30 : *pofs = ofs;
1619 30 : return true;
1620 : }
1621 :
1622 : /**
1623 : * @brief Do the smb chaining at a buffer level
1624 : * @param[in] poutbuf Pointer to the talloc'ed buffer to be modified
1625 : * @param[in] andx_buf Buffer to be appended
1626 : */
1627 :
1628 30 : static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf)
1629 : {
1630 30 : uint8_t smb_command = CVAL(andx_buf, smb_com);
1631 30 : uint8_t wct = CVAL(andx_buf, smb_wct);
1632 30 : const uint16_t *vwv = (const uint16_t *)(andx_buf + smb_vwv);
1633 30 : uint32_t num_bytes = smb_buflen(andx_buf);
1634 30 : const uint8_t *bytes = (const uint8_t *)smb_buf_const(andx_buf);
1635 :
1636 2 : uint8_t *outbuf;
1637 2 : size_t old_size, new_size;
1638 2 : size_t ofs;
1639 30 : size_t chain_padding = 0;
1640 2 : size_t andx_cmd_ofs;
1641 :
1642 :
1643 30 : old_size = talloc_get_size(*poutbuf);
1644 :
1645 30 : if ((old_size % 4) != 0) {
1646 : /*
1647 : * Align the wct field of subsequent requests to a 4-byte
1648 : * boundary
1649 : */
1650 30 : chain_padding = 4 - (old_size % 4);
1651 : }
1652 :
1653 : /*
1654 : * After the old request comes the new wct field (1 byte), the vwv's
1655 : * and the num_bytes field.
1656 : */
1657 :
1658 30 : new_size = old_size + chain_padding + 1 + wct * sizeof(uint16_t) + 2;
1659 30 : new_size += num_bytes;
1660 :
1661 30 : if ((smb_command != SMBwriteX) && (new_size > 0xffff)) {
1662 0 : DEBUG(1, ("smb_splice_chain: %u bytes won't fit\n",
1663 : (unsigned)new_size));
1664 0 : return false;
1665 : }
1666 :
1667 30 : outbuf = talloc_realloc(NULL, *poutbuf, uint8_t, new_size);
1668 30 : if (outbuf == NULL) {
1669 0 : DEBUG(0, ("talloc failed\n"));
1670 0 : return false;
1671 : }
1672 30 : *poutbuf = outbuf;
1673 :
1674 30 : if (!find_andx_cmd_ofs(outbuf, &andx_cmd_ofs)) {
1675 0 : DEBUG(1, ("invalid command chain\n"));
1676 0 : *poutbuf = talloc_realloc(NULL, *poutbuf, uint8_t, old_size);
1677 0 : return false;
1678 : }
1679 :
1680 30 : if (chain_padding != 0) {
1681 30 : memset(outbuf + old_size, 0, chain_padding);
1682 30 : old_size += chain_padding;
1683 : }
1684 :
1685 30 : SCVAL(outbuf, andx_cmd_ofs, smb_command);
1686 30 : SSVAL(outbuf, andx_cmd_ofs + 2, old_size - 4);
1687 :
1688 30 : ofs = old_size;
1689 :
1690 : /*
1691 : * Push the chained request:
1692 : *
1693 : * wct field
1694 : */
1695 :
1696 30 : SCVAL(outbuf, ofs, wct);
1697 30 : ofs += 1;
1698 :
1699 : /*
1700 : * vwv array
1701 : */
1702 :
1703 30 : memcpy(outbuf + ofs, vwv, sizeof(uint16_t) * wct);
1704 :
1705 : /*
1706 : * HACK ALERT
1707 : *
1708 : * Read&X has an offset into its data buffer at
1709 : * vwv[6]. reply_read_andx has no idea anymore that it's
1710 : * running from within a chain, so we have to fix up the
1711 : * offset here.
1712 : *
1713 : * Although it looks disgusting at this place, I want to keep
1714 : * it here. The alternative would be to push knowledge about
1715 : * the andx chain down into read&x again.
1716 : */
1717 :
1718 30 : if (smb_command == SMBreadX) {
1719 2 : uint8_t *bytes_addr;
1720 :
1721 10 : if (wct < 7) {
1722 : /*
1723 : * Invalid read&x response
1724 : */
1725 0 : return false;
1726 : }
1727 :
1728 10 : bytes_addr = outbuf + ofs /* vwv start */
1729 10 : + sizeof(uint16_t) * wct /* vwv array */
1730 : + sizeof(uint16_t) /* bcc */
1731 10 : + 1; /* padding byte */
1732 :
1733 10 : SSVAL(outbuf + ofs, 6 * sizeof(uint16_t),
1734 : bytes_addr - outbuf - 4);
1735 : }
1736 :
1737 30 : ofs += sizeof(uint16_t) * wct;
1738 :
1739 : /*
1740 : * bcc (byte count)
1741 : */
1742 :
1743 30 : SSVAL(outbuf, ofs, num_bytes);
1744 30 : ofs += sizeof(uint16_t);
1745 :
1746 : /*
1747 : * The bytes field
1748 : */
1749 :
1750 30 : memcpy(outbuf + ofs, bytes, num_bytes);
1751 :
1752 30 : return true;
1753 : }
1754 :
1755 657255 : bool smb1_is_chain(const uint8_t *buf)
1756 : {
1757 7876 : uint8_t cmd, wct, andx_cmd;
1758 :
1759 657255 : cmd = CVAL(buf, smb_com);
1760 657255 : if (!smb1cli_is_andx_req(cmd)) {
1761 433011 : return false;
1762 : }
1763 217378 : wct = CVAL(buf, smb_wct);
1764 217378 : if (wct < 2) {
1765 0 : return false;
1766 : }
1767 217378 : andx_cmd = CVAL(buf, smb_vwv);
1768 217378 : return (andx_cmd != 0xFF);
1769 : }
1770 :
1771 39 : bool smb1_walk_chain(const uint8_t *buf,
1772 : bool (*fn)(uint8_t cmd,
1773 : uint8_t wct, const uint16_t *vwv,
1774 : uint16_t num_bytes, const uint8_t *bytes,
1775 : void *private_data),
1776 : void *private_data)
1777 : {
1778 39 : size_t smblen = smb_len(buf);
1779 39 : const char *smb_buf = smb_base(buf);
1780 3 : uint8_t cmd, chain_cmd;
1781 3 : uint8_t wct;
1782 3 : const uint16_t *vwv;
1783 3 : uint16_t num_bytes;
1784 3 : const uint8_t *bytes;
1785 :
1786 39 : cmd = CVAL(buf, smb_com);
1787 39 : wct = CVAL(buf, smb_wct);
1788 39 : vwv = (const uint16_t *)(buf + smb_vwv);
1789 39 : num_bytes = smb_buflen(buf);
1790 39 : bytes = (const uint8_t *)smb_buf_const(buf);
1791 :
1792 39 : if (!fn(cmd, wct, vwv, num_bytes, bytes, private_data)) {
1793 0 : return false;
1794 : }
1795 :
1796 39 : if (!smb1cli_is_andx_req(cmd)) {
1797 0 : return true;
1798 : }
1799 39 : if (wct < 2) {
1800 0 : return false;
1801 : }
1802 :
1803 39 : chain_cmd = CVAL(vwv, 0);
1804 :
1805 78 : while (chain_cmd != 0xff) {
1806 3 : uint32_t chain_offset; /* uint32_t to avoid overflow */
1807 3 : size_t length_needed;
1808 3 : ptrdiff_t vwv_offset;
1809 :
1810 51 : chain_offset = SVAL(vwv+1, 0);
1811 :
1812 : /*
1813 : * Check if the client tries to fool us. The chain
1814 : * offset needs to point beyond the current request in
1815 : * the chain, it needs to strictly grow. Otherwise we
1816 : * might be tricked into an endless loop always
1817 : * processing the same request over and over again. We
1818 : * used to assume that vwv and the byte buffer array
1819 : * in a chain are always attached, but OS/2 the
1820 : * Write&X/Read&X chain puts the Read&X vwv array
1821 : * right behind the Write&X vwv chain. The Write&X bcc
1822 : * array is put behind the Read&X vwv array. So now we
1823 : * check whether the chain offset points strictly
1824 : * behind the previous vwv array. req->buf points
1825 : * right after the vwv array of the previous
1826 : * request. See
1827 : * https://bugzilla.samba.org/show_bug.cgi?id=8360 for
1828 : * more information.
1829 : */
1830 :
1831 51 : vwv_offset = ((const char *)vwv - smb_buf);
1832 51 : if (chain_offset <= vwv_offset) {
1833 0 : return false;
1834 : }
1835 :
1836 : /*
1837 : * Next check: Make sure the chain offset does not
1838 : * point beyond the overall smb request length.
1839 : */
1840 :
1841 51 : length_needed = chain_offset+1; /* wct */
1842 51 : if (length_needed > smblen) {
1843 0 : return false;
1844 : }
1845 :
1846 : /*
1847 : * Now comes the pointer magic. Goal here is to set up
1848 : * vwv and buf correctly again. The chain offset (the
1849 : * former vwv[1]) points at the new wct field.
1850 : */
1851 :
1852 51 : wct = CVAL(smb_buf, chain_offset);
1853 :
1854 51 : if (smb1cli_is_andx_req(chain_cmd) && (wct < 2)) {
1855 0 : return false;
1856 : }
1857 :
1858 : /*
1859 : * Next consistency check: Make the new vwv array fits
1860 : * in the overall smb request.
1861 : */
1862 :
1863 51 : length_needed += (wct+1)*sizeof(uint16_t); /* vwv+buflen */
1864 51 : if (length_needed > smblen) {
1865 0 : return false;
1866 : }
1867 51 : vwv = (const uint16_t *)(smb_buf + chain_offset + 1);
1868 :
1869 : /*
1870 : * Now grab the new byte buffer....
1871 : */
1872 :
1873 51 : num_bytes = SVAL(vwv+wct, 0);
1874 :
1875 : /*
1876 : * .. and check that it fits.
1877 : */
1878 :
1879 51 : length_needed += num_bytes;
1880 51 : if (length_needed > smblen) {
1881 0 : return false;
1882 : }
1883 51 : bytes = (const uint8_t *)(vwv+wct+1);
1884 :
1885 51 : if (!fn(chain_cmd, wct, vwv, num_bytes, bytes, private_data)) {
1886 0 : return false;
1887 : }
1888 :
1889 51 : if (!smb1cli_is_andx_req(chain_cmd)) {
1890 12 : return true;
1891 : }
1892 39 : chain_cmd = CVAL(vwv, 0);
1893 : }
1894 24 : return true;
1895 : }
1896 :
1897 0 : static bool smb1_chain_length_cb(uint8_t cmd,
1898 : uint8_t wct, const uint16_t *vwv,
1899 : uint16_t num_bytes, const uint8_t *bytes,
1900 : void *private_data)
1901 : {
1902 0 : unsigned *count = (unsigned *)private_data;
1903 0 : *count += 1;
1904 0 : return true;
1905 : }
1906 :
1907 0 : unsigned smb1_chain_length(const uint8_t *buf)
1908 : {
1909 0 : unsigned count = 0;
1910 :
1911 0 : if (!smb1_walk_chain(buf, smb1_chain_length_cb, &count)) {
1912 0 : return 0;
1913 : }
1914 0 : return count;
1915 : }
1916 :
1917 : struct smb1_parse_chain_state {
1918 : TALLOC_CTX *mem_ctx;
1919 : const uint8_t *buf;
1920 : struct smbd_server_connection *sconn;
1921 : struct smbXsrv_connection *xconn;
1922 : bool encrypted;
1923 : uint32_t seqnum;
1924 :
1925 : struct smb_request **reqs;
1926 : unsigned num_reqs;
1927 : };
1928 :
1929 90 : static bool smb1_parse_chain_cb(uint8_t cmd,
1930 : uint8_t wct, const uint16_t *vwv,
1931 : uint16_t num_bytes, const uint8_t *bytes,
1932 : void *private_data)
1933 : {
1934 90 : struct smb1_parse_chain_state *state =
1935 : (struct smb1_parse_chain_state *)private_data;
1936 6 : struct smb_request **reqs;
1937 6 : struct smb_request *req;
1938 6 : bool ok;
1939 :
1940 90 : reqs = talloc_realloc(state->mem_ctx, state->reqs,
1941 : struct smb_request *, state->num_reqs+1);
1942 90 : if (reqs == NULL) {
1943 0 : return false;
1944 : }
1945 90 : state->reqs = reqs;
1946 :
1947 90 : req = talloc(reqs, struct smb_request);
1948 90 : if (req == NULL) {
1949 0 : return false;
1950 : }
1951 :
1952 96 : ok = init_smb1_request(req, state->sconn, state->xconn, state->buf, 0,
1953 90 : state->encrypted, state->seqnum);
1954 90 : if (!ok) {
1955 0 : return false;
1956 : }
1957 90 : req->cmd = cmd;
1958 90 : req->wct = wct;
1959 90 : req->vwv = vwv;
1960 90 : req->buflen = num_bytes;
1961 90 : req->buf = bytes;
1962 :
1963 90 : reqs[state->num_reqs] = req;
1964 90 : state->num_reqs += 1;
1965 90 : return true;
1966 : }
1967 :
1968 39 : bool smb1_parse_chain(TALLOC_CTX *mem_ctx, const uint8_t *buf,
1969 : struct smbXsrv_connection *xconn,
1970 : bool encrypted, uint32_t seqnum,
1971 : struct smb_request ***reqs, unsigned *num_reqs)
1972 : {
1973 39 : struct smbd_server_connection *sconn = NULL;
1974 3 : struct smb1_parse_chain_state state;
1975 3 : unsigned i;
1976 :
1977 39 : if (xconn != NULL) {
1978 39 : sconn = xconn->client->sconn;
1979 : }
1980 :
1981 39 : state.mem_ctx = mem_ctx;
1982 39 : state.buf = buf;
1983 39 : state.sconn = sconn;
1984 39 : state.xconn = xconn;
1985 39 : state.encrypted = encrypted;
1986 39 : state.seqnum = seqnum;
1987 39 : state.reqs = NULL;
1988 39 : state.num_reqs = 0;
1989 :
1990 39 : if (!smb1_walk_chain(buf, smb1_parse_chain_cb, &state)) {
1991 0 : TALLOC_FREE(state.reqs);
1992 0 : return false;
1993 : }
1994 129 : for (i=0; i<state.num_reqs; i++) {
1995 90 : state.reqs[i]->chain = state.reqs;
1996 : }
1997 39 : *reqs = state.reqs;
1998 39 : *num_reqs = state.num_reqs;
1999 39 : return true;
2000 : }
2001 :
2002 0 : static bool fd_is_readable(int fd)
2003 : {
2004 0 : int ret, revents;
2005 :
2006 0 : ret = poll_one_fd(fd, POLLIN|POLLHUP, 0, &revents);
2007 :
2008 0 : return ((ret > 0) && ((revents & (POLLIN|POLLHUP|POLLERR)) != 0));
2009 :
2010 : }
2011 :
2012 0 : static void smbd_server_connection_write_handler(
2013 : struct smbXsrv_connection *xconn)
2014 : {
2015 : /* TODO: make write nonblocking */
2016 0 : }
2017 :
2018 659150 : void smbd_smb1_server_connection_read_handler(struct smbXsrv_connection *xconn,
2019 : int fd)
2020 : {
2021 659150 : uint8_t *inbuf = NULL;
2022 659150 : size_t inbuf_len = 0;
2023 659150 : size_t unread_bytes = 0;
2024 659150 : bool encrypted = false;
2025 659150 : TALLOC_CTX *mem_ctx = talloc_tos();
2026 7992 : NTSTATUS status;
2027 7992 : uint32_t seqnum;
2028 :
2029 659150 : bool async_echo = lp_async_smb_echo_handler();
2030 659150 : bool from_client = false;
2031 :
2032 659150 : if (async_echo) {
2033 0 : if (fd_is_readable(xconn->smb1.echo_handler.trusted_fd)) {
2034 : /*
2035 : * This is the super-ugly hack to prefer the packets
2036 : * forwarded by the echo handler over the ones by the
2037 : * client directly
2038 : */
2039 0 : fd = xconn->smb1.echo_handler.trusted_fd;
2040 : }
2041 : }
2042 :
2043 659150 : from_client = (xconn->transport.sock == fd);
2044 :
2045 659150 : if (async_echo && from_client) {
2046 0 : smbd_lock_socket(xconn);
2047 :
2048 0 : if (!fd_is_readable(fd)) {
2049 0 : DEBUG(10,("the echo listener was faster\n"));
2050 0 : smbd_unlock_socket(xconn);
2051 0 : return;
2052 : }
2053 : }
2054 :
2055 : /* TODO: make this completely nonblocking */
2056 667142 : status = receive_smb_talloc(mem_ctx, xconn, fd,
2057 : (char **)(void *)&inbuf,
2058 : 0, /* timeout */
2059 : &unread_bytes,
2060 : &encrypted,
2061 : &inbuf_len, &seqnum,
2062 659150 : !from_client /* trusted channel */);
2063 :
2064 659150 : if (async_echo && from_client) {
2065 0 : smbd_unlock_socket(xconn);
2066 : }
2067 :
2068 659150 : if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
2069 0 : goto process;
2070 : }
2071 659150 : if (NT_STATUS_IS_ERR(status)) {
2072 5575 : exit_server_cleanly("failed to receive smb request");
2073 : }
2074 653575 : if (!NT_STATUS_IS_OK(status)) {
2075 0 : return;
2076 : }
2077 :
2078 653575 : process:
2079 653575 : process_smb(xconn, inbuf, inbuf_len, unread_bytes, seqnum, encrypted);
2080 : }
2081 :
2082 0 : static void smbd_server_echo_handler(struct tevent_context *ev,
2083 : struct tevent_fd *fde,
2084 : uint16_t flags,
2085 : void *private_data)
2086 : {
2087 0 : struct smbXsrv_connection *xconn =
2088 0 : talloc_get_type_abort(private_data,
2089 : struct smbXsrv_connection);
2090 :
2091 0 : if (!NT_STATUS_IS_OK(xconn->transport.status)) {
2092 : /*
2093 : * we're not supposed to do any io
2094 : */
2095 0 : TEVENT_FD_NOT_READABLE(xconn->smb1.echo_handler.trusted_fde);
2096 0 : TEVENT_FD_NOT_WRITEABLE(xconn->smb1.echo_handler.trusted_fde);
2097 0 : return;
2098 : }
2099 :
2100 0 : if (flags & TEVENT_FD_WRITE) {
2101 0 : smbd_server_connection_write_handler(xconn);
2102 0 : return;
2103 : }
2104 0 : if (flags & TEVENT_FD_READ) {
2105 0 : smbd_smb1_server_connection_read_handler(
2106 : xconn, xconn->smb1.echo_handler.trusted_fd);
2107 0 : return;
2108 : }
2109 : }
2110 :
2111 : /*
2112 : * Send keepalive packets to our client
2113 : */
2114 27 : bool keepalive_fn(const struct timeval *now, void *private_data)
2115 : {
2116 27 : struct smbd_server_connection *sconn = talloc_get_type_abort(
2117 : private_data, struct smbd_server_connection);
2118 27 : struct smbXsrv_connection *xconn = NULL;
2119 0 : bool ret;
2120 :
2121 27 : if (sconn->using_smb2) {
2122 : /* Don't do keepalives on an SMB2 connection. */
2123 27 : return false;
2124 : }
2125 :
2126 : /*
2127 : * With SMB1 we only have 1 connection
2128 : */
2129 0 : xconn = sconn->client->connections;
2130 0 : smbd_lock_socket(xconn);
2131 0 : ret = send_keepalive(xconn->transport.sock);
2132 0 : smbd_unlock_socket(xconn);
2133 :
2134 0 : if (!ret) {
2135 0 : int saved_errno = errno;
2136 : /*
2137 : * Try and give an error message saying what
2138 : * client failed.
2139 : */
2140 0 : DEBUG(0, ("send_keepalive failed for client %s. "
2141 : "Error %s - exiting\n",
2142 : smbXsrv_connection_dbg(xconn),
2143 : strerror(saved_errno)));
2144 0 : errno = saved_errno;
2145 0 : return False;
2146 : }
2147 0 : return True;
2148 : }
2149 :
2150 : /*
2151 : * Read an smb packet in the echo handler child, giving the parent
2152 : * smbd one second to react once the socket becomes readable.
2153 : */
2154 :
2155 : struct smbd_echo_read_state {
2156 : struct tevent_context *ev;
2157 : struct smbXsrv_connection *xconn;
2158 :
2159 : char *buf;
2160 : size_t buflen;
2161 : uint32_t seqnum;
2162 : };
2163 :
2164 : static void smbd_echo_read_readable(struct tevent_req *subreq);
2165 : static void smbd_echo_read_waited(struct tevent_req *subreq);
2166 :
2167 0 : static struct tevent_req *smbd_echo_read_send(
2168 : TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2169 : struct smbXsrv_connection *xconn)
2170 : {
2171 0 : struct tevent_req *req, *subreq;
2172 0 : struct smbd_echo_read_state *state;
2173 :
2174 0 : req = tevent_req_create(mem_ctx, &state,
2175 : struct smbd_echo_read_state);
2176 0 : if (req == NULL) {
2177 0 : return NULL;
2178 : }
2179 0 : state->ev = ev;
2180 0 : state->xconn = xconn;
2181 :
2182 0 : subreq = wait_for_read_send(state, ev, xconn->transport.sock, false);
2183 0 : if (tevent_req_nomem(subreq, req)) {
2184 0 : return tevent_req_post(req, ev);
2185 : }
2186 0 : tevent_req_set_callback(subreq, smbd_echo_read_readable, req);
2187 0 : return req;
2188 : }
2189 :
2190 0 : static void smbd_echo_read_readable(struct tevent_req *subreq)
2191 : {
2192 0 : struct tevent_req *req = tevent_req_callback_data(
2193 : subreq, struct tevent_req);
2194 0 : struct smbd_echo_read_state *state = tevent_req_data(
2195 : req, struct smbd_echo_read_state);
2196 0 : bool ok;
2197 0 : int err;
2198 :
2199 0 : ok = wait_for_read_recv(subreq, &err);
2200 0 : TALLOC_FREE(subreq);
2201 0 : if (!ok) {
2202 0 : tevent_req_nterror(req, map_nt_error_from_unix(err));
2203 0 : return;
2204 : }
2205 :
2206 : /*
2207 : * Give the parent smbd one second to step in
2208 : */
2209 :
2210 0 : subreq = tevent_wakeup_send(
2211 : state, state->ev, timeval_current_ofs(1, 0));
2212 0 : if (tevent_req_nomem(subreq, req)) {
2213 0 : return;
2214 : }
2215 0 : tevent_req_set_callback(subreq, smbd_echo_read_waited, req);
2216 : }
2217 :
2218 0 : static void smbd_echo_read_waited(struct tevent_req *subreq)
2219 : {
2220 0 : struct tevent_req *req = tevent_req_callback_data(
2221 : subreq, struct tevent_req);
2222 0 : struct smbd_echo_read_state *state = tevent_req_data(
2223 : req, struct smbd_echo_read_state);
2224 0 : struct smbXsrv_connection *xconn = state->xconn;
2225 0 : bool ok;
2226 0 : NTSTATUS status;
2227 0 : size_t unread = 0;
2228 0 : bool encrypted;
2229 :
2230 0 : ok = tevent_wakeup_recv(subreq);
2231 0 : TALLOC_FREE(subreq);
2232 0 : if (!ok) {
2233 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2234 0 : return;
2235 : }
2236 :
2237 0 : ok = smbd_lock_socket_internal(xconn);
2238 0 : if (!ok) {
2239 0 : tevent_req_nterror(req, map_nt_error_from_unix(errno));
2240 0 : DEBUG(0, ("%s: failed to lock socket\n", __location__));
2241 0 : return;
2242 : }
2243 :
2244 0 : if (!fd_is_readable(xconn->transport.sock)) {
2245 0 : DEBUG(10,("echo_handler[%d] the parent smbd was faster\n",
2246 : (int)getpid()));
2247 :
2248 0 : ok = smbd_unlock_socket_internal(xconn);
2249 0 : if (!ok) {
2250 0 : tevent_req_nterror(req, map_nt_error_from_unix(errno));
2251 0 : DEBUG(1, ("%s: failed to unlock socket\n",
2252 : __location__));
2253 0 : return;
2254 : }
2255 :
2256 0 : subreq = wait_for_read_send(state, state->ev,
2257 : xconn->transport.sock, false);
2258 0 : if (tevent_req_nomem(subreq, req)) {
2259 0 : return;
2260 : }
2261 0 : tevent_req_set_callback(subreq, smbd_echo_read_readable, req);
2262 0 : return;
2263 : }
2264 :
2265 0 : status = receive_smb_talloc(state, xconn,
2266 : xconn->transport.sock,
2267 : &state->buf,
2268 : 0 /* timeout */,
2269 : &unread,
2270 : &encrypted,
2271 : &state->buflen,
2272 : &state->seqnum,
2273 : false /* trusted_channel*/);
2274 :
2275 0 : if (tevent_req_nterror(req, status)) {
2276 0 : tevent_req_nterror(req, status);
2277 0 : DEBUG(1, ("echo_handler[%d]: receive_smb_raw_talloc failed: %s\n",
2278 : (int)getpid(), nt_errstr(status)));
2279 0 : return;
2280 : }
2281 :
2282 0 : ok = smbd_unlock_socket_internal(xconn);
2283 0 : if (!ok) {
2284 0 : tevent_req_nterror(req, map_nt_error_from_unix(errno));
2285 0 : DEBUG(1, ("%s: failed to unlock socket\n", __location__));
2286 0 : return;
2287 : }
2288 0 : tevent_req_done(req);
2289 : }
2290 :
2291 0 : static NTSTATUS smbd_echo_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
2292 : char **pbuf, size_t *pbuflen, uint32_t *pseqnum)
2293 : {
2294 0 : struct smbd_echo_read_state *state = tevent_req_data(
2295 : req, struct smbd_echo_read_state);
2296 0 : NTSTATUS status;
2297 :
2298 0 : if (tevent_req_is_nterror(req, &status)) {
2299 0 : return status;
2300 : }
2301 0 : *pbuf = talloc_move(mem_ctx, &state->buf);
2302 0 : *pbuflen = state->buflen;
2303 0 : *pseqnum = state->seqnum;
2304 0 : return NT_STATUS_OK;
2305 : }
2306 :
2307 : struct smbd_echo_state {
2308 : struct tevent_context *ev;
2309 : struct iovec *pending;
2310 : struct smbd_server_connection *sconn;
2311 : struct smbXsrv_connection *xconn;
2312 : int parent_pipe;
2313 :
2314 : struct tevent_fd *parent_fde;
2315 :
2316 : struct tevent_req *write_req;
2317 : };
2318 :
2319 : static void smbd_echo_writer_done(struct tevent_req *req);
2320 :
2321 0 : static void smbd_echo_activate_writer(struct smbd_echo_state *state)
2322 : {
2323 0 : int num_pending;
2324 :
2325 0 : if (state->write_req != NULL) {
2326 0 : return;
2327 : }
2328 :
2329 0 : num_pending = talloc_array_length(state->pending);
2330 0 : if (num_pending == 0) {
2331 0 : return;
2332 : }
2333 :
2334 0 : state->write_req = writev_send(state, state->ev, NULL,
2335 : state->parent_pipe, false,
2336 : state->pending, num_pending);
2337 0 : if (state->write_req == NULL) {
2338 0 : DEBUG(1, ("writev_send failed\n"));
2339 0 : exit(1);
2340 : }
2341 :
2342 0 : talloc_steal(state->write_req, state->pending);
2343 0 : state->pending = NULL;
2344 :
2345 0 : tevent_req_set_callback(state->write_req, smbd_echo_writer_done,
2346 : state);
2347 : }
2348 :
2349 0 : static void smbd_echo_writer_done(struct tevent_req *req)
2350 : {
2351 0 : struct smbd_echo_state *state = tevent_req_callback_data(
2352 : req, struct smbd_echo_state);
2353 0 : ssize_t written;
2354 0 : int err;
2355 :
2356 0 : written = writev_recv(req, &err);
2357 0 : TALLOC_FREE(req);
2358 0 : state->write_req = NULL;
2359 0 : if (written == -1) {
2360 0 : DEBUG(1, ("writev to parent failed: %s\n", strerror(err)));
2361 0 : exit(1);
2362 : }
2363 0 : DEBUG(10,("echo_handler[%d]: forwarded pdu to main\n", (int)getpid()));
2364 0 : smbd_echo_activate_writer(state);
2365 0 : }
2366 :
2367 0 : static bool smbd_echo_reply(struct smbd_echo_state *state,
2368 : uint8_t *inbuf, size_t inbuf_len,
2369 : uint32_t seqnum)
2370 : {
2371 0 : struct smb_request req;
2372 0 : uint16_t num_replies;
2373 0 : char *outbuf;
2374 0 : bool ok;
2375 :
2376 0 : if ((inbuf_len == 4) && (CVAL(inbuf, 0) == NBSSkeepalive)) {
2377 0 : DEBUG(10, ("Got netbios keepalive\n"));
2378 : /*
2379 : * Just swallow it
2380 : */
2381 0 : return true;
2382 : }
2383 :
2384 0 : if (inbuf_len < smb_size) {
2385 0 : DEBUG(10, ("Got short packet: %d bytes\n", (int)inbuf_len));
2386 0 : return false;
2387 : }
2388 0 : if (!valid_smb1_header(inbuf)) {
2389 0 : DEBUG(10, ("Got invalid SMB header\n"));
2390 0 : return false;
2391 : }
2392 :
2393 0 : if (!init_smb1_request(&req, state->sconn, state->xconn, inbuf, 0, false,
2394 : seqnum)) {
2395 0 : return false;
2396 : }
2397 0 : req.inbuf = inbuf;
2398 :
2399 0 : DEBUG(10, ("smbecho handler got cmd %d (%s)\n", (int)req.cmd,
2400 : smb_fn_name(req.cmd)));
2401 :
2402 0 : if (req.cmd != SMBecho) {
2403 0 : return false;
2404 : }
2405 0 : if (req.wct < 1) {
2406 0 : return false;
2407 : }
2408 :
2409 0 : num_replies = SVAL(req.vwv+0, 0);
2410 0 : if (num_replies != 1) {
2411 : /* Not a Windows "Hey, you're still there?" request */
2412 0 : return false;
2413 : }
2414 :
2415 0 : if (!create_smb1_outbuf(talloc_tos(), &req, req.inbuf, &outbuf,
2416 0 : 1, req.buflen)) {
2417 0 : DEBUG(10, ("create_smb1_outbuf failed\n"));
2418 0 : return false;
2419 : }
2420 0 : req.outbuf = (uint8_t *)outbuf;
2421 :
2422 0 : SSVAL(req.outbuf, smb_vwv0, num_replies);
2423 :
2424 0 : if (req.buflen > 0) {
2425 0 : memcpy(smb_buf(req.outbuf), req.buf, req.buflen);
2426 : }
2427 :
2428 0 : ok = smb1_srv_send(req.xconn, (char *)outbuf, true, seqnum + 1, false);
2429 0 : TALLOC_FREE(outbuf);
2430 0 : if (!ok) {
2431 0 : exit(1);
2432 : }
2433 :
2434 0 : return true;
2435 : }
2436 :
2437 0 : static void smbd_echo_exit(struct tevent_context *ev,
2438 : struct tevent_fd *fde, uint16_t flags,
2439 : void *private_data)
2440 : {
2441 0 : DEBUG(2, ("smbd_echo_exit: lost connection to parent\n"));
2442 0 : exit(0);
2443 : }
2444 :
2445 : static void smbd_echo_got_packet(struct tevent_req *req);
2446 :
2447 0 : static void smbd_echo_loop(struct smbXsrv_connection *xconn,
2448 : int parent_pipe)
2449 : {
2450 0 : struct smbd_echo_state *state;
2451 0 : struct tevent_req *read_req;
2452 :
2453 0 : state = talloc_zero(xconn, struct smbd_echo_state);
2454 0 : if (state == NULL) {
2455 0 : DEBUG(1, ("talloc failed\n"));
2456 0 : return;
2457 : }
2458 0 : state->xconn = xconn;
2459 0 : state->parent_pipe = parent_pipe;
2460 0 : state->ev = samba_tevent_context_init(state);
2461 0 : if (state->ev == NULL) {
2462 0 : DEBUG(1, ("samba_tevent_context_init failed\n"));
2463 0 : TALLOC_FREE(state);
2464 0 : return;
2465 : }
2466 0 : state->parent_fde = tevent_add_fd(state->ev, state, parent_pipe,
2467 : TEVENT_FD_READ, smbd_echo_exit,
2468 : state);
2469 0 : if (state->parent_fde == NULL) {
2470 0 : DEBUG(1, ("tevent_add_fd failed\n"));
2471 0 : TALLOC_FREE(state);
2472 0 : return;
2473 : }
2474 :
2475 0 : read_req = smbd_echo_read_send(state, state->ev, xconn);
2476 0 : if (read_req == NULL) {
2477 0 : DEBUG(1, ("smbd_echo_read_send failed\n"));
2478 0 : TALLOC_FREE(state);
2479 0 : return;
2480 : }
2481 0 : tevent_req_set_callback(read_req, smbd_echo_got_packet, state);
2482 :
2483 0 : while (true) {
2484 0 : if (tevent_loop_once(state->ev) == -1) {
2485 0 : DEBUG(1, ("tevent_loop_once failed: %s\n",
2486 : strerror(errno)));
2487 0 : break;
2488 : }
2489 : }
2490 0 : TALLOC_FREE(state);
2491 : }
2492 :
2493 0 : static void smbd_echo_got_packet(struct tevent_req *req)
2494 : {
2495 0 : struct smbd_echo_state *state = tevent_req_callback_data(
2496 : req, struct smbd_echo_state);
2497 0 : NTSTATUS status;
2498 0 : char *buf = NULL;
2499 0 : size_t buflen = 0;
2500 0 : uint32_t seqnum = 0;
2501 0 : bool reply;
2502 :
2503 0 : status = smbd_echo_read_recv(req, state, &buf, &buflen, &seqnum);
2504 0 : TALLOC_FREE(req);
2505 0 : if (!NT_STATUS_IS_OK(status)) {
2506 0 : DEBUG(1, ("smbd_echo_read_recv returned %s\n",
2507 : nt_errstr(status)));
2508 0 : exit(1);
2509 : }
2510 :
2511 0 : reply = smbd_echo_reply(state, (uint8_t *)buf, buflen, seqnum);
2512 0 : if (!reply) {
2513 0 : size_t num_pending;
2514 0 : struct iovec *tmp;
2515 0 : struct iovec *iov;
2516 :
2517 0 : num_pending = talloc_array_length(state->pending);
2518 0 : tmp = talloc_realloc(state, state->pending, struct iovec,
2519 : num_pending+1);
2520 0 : if (tmp == NULL) {
2521 0 : DEBUG(1, ("talloc_realloc failed\n"));
2522 0 : exit(1);
2523 : }
2524 0 : state->pending = tmp;
2525 :
2526 0 : if (buflen >= smb_size) {
2527 : /*
2528 : * place the seqnum in the packet so that the main process
2529 : * can reply with signing
2530 : */
2531 0 : SIVAL(buf, smb_ss_field, seqnum);
2532 0 : SIVAL(buf, smb_ss_field+4, NT_STATUS_V(NT_STATUS_OK));
2533 : }
2534 :
2535 0 : iov = &state->pending[num_pending];
2536 0 : iov->iov_base = talloc_move(state->pending, &buf);
2537 0 : iov->iov_len = buflen;
2538 :
2539 0 : DEBUG(10,("echo_handler[%d]: forward to main\n",
2540 : (int)getpid()));
2541 0 : smbd_echo_activate_writer(state);
2542 : }
2543 :
2544 0 : req = smbd_echo_read_send(state, state->ev, state->xconn);
2545 0 : if (req == NULL) {
2546 0 : DEBUG(1, ("smbd_echo_read_send failed\n"));
2547 0 : exit(1);
2548 : }
2549 0 : tevent_req_set_callback(req, smbd_echo_got_packet, state);
2550 0 : }
2551 :
2552 :
2553 : /*
2554 : * Handle SMBecho requests in a forked child process
2555 : */
2556 0 : bool fork_echo_handler(struct smbXsrv_connection *xconn)
2557 : {
2558 0 : int listener_pipe[2];
2559 0 : int res;
2560 0 : pid_t child;
2561 0 : bool use_mutex = false;
2562 :
2563 0 : res = pipe(listener_pipe);
2564 0 : if (res == -1) {
2565 0 : DEBUG(1, ("pipe() failed: %s\n", strerror(errno)));
2566 0 : return false;
2567 : }
2568 :
2569 : #ifdef HAVE_ROBUST_MUTEXES
2570 0 : use_mutex = tdb_runtime_check_for_robust_mutexes();
2571 :
2572 0 : if (use_mutex) {
2573 0 : pthread_mutexattr_t a;
2574 :
2575 0 : xconn->smb1.echo_handler.socket_mutex =
2576 0 : anonymous_shared_allocate(sizeof(pthread_mutex_t));
2577 0 : if (xconn->smb1.echo_handler.socket_mutex == NULL) {
2578 0 : DEBUG(1, ("Could not create mutex shared memory: %s\n",
2579 : strerror(errno)));
2580 0 : goto fail;
2581 : }
2582 :
2583 0 : res = pthread_mutexattr_init(&a);
2584 0 : if (res != 0) {
2585 0 : DEBUG(1, ("pthread_mutexattr_init failed: %s\n",
2586 : strerror(res)));
2587 0 : goto fail;
2588 : }
2589 0 : res = pthread_mutexattr_settype(&a, PTHREAD_MUTEX_ERRORCHECK);
2590 0 : if (res != 0) {
2591 0 : DEBUG(1, ("pthread_mutexattr_settype failed: %s\n",
2592 : strerror(res)));
2593 0 : pthread_mutexattr_destroy(&a);
2594 0 : goto fail;
2595 : }
2596 0 : res = pthread_mutexattr_setpshared(&a, PTHREAD_PROCESS_SHARED);
2597 0 : if (res != 0) {
2598 0 : DEBUG(1, ("pthread_mutexattr_setpshared failed: %s\n",
2599 : strerror(res)));
2600 0 : pthread_mutexattr_destroy(&a);
2601 0 : goto fail;
2602 : }
2603 0 : res = pthread_mutexattr_setrobust(&a, PTHREAD_MUTEX_ROBUST);
2604 0 : if (res != 0) {
2605 0 : DEBUG(1, ("pthread_mutexattr_setrobust failed: "
2606 : "%s\n", strerror(res)));
2607 0 : pthread_mutexattr_destroy(&a);
2608 0 : goto fail;
2609 : }
2610 0 : res = pthread_mutex_init(xconn->smb1.echo_handler.socket_mutex,
2611 : &a);
2612 0 : pthread_mutexattr_destroy(&a);
2613 0 : if (res != 0) {
2614 0 : DEBUG(1, ("pthread_mutex_init failed: %s\n",
2615 : strerror(res)));
2616 0 : goto fail;
2617 : }
2618 : }
2619 : #endif
2620 :
2621 0 : if (!use_mutex) {
2622 0 : xconn->smb1.echo_handler.socket_lock_fd =
2623 0 : create_unlink_tmp(lp_lock_directory());
2624 0 : if (xconn->smb1.echo_handler.socket_lock_fd == -1) {
2625 0 : DEBUG(1, ("Could not create lock fd: %s\n",
2626 : strerror(errno)));
2627 0 : goto fail;
2628 : }
2629 : }
2630 :
2631 0 : child = fork();
2632 0 : if (child == 0) {
2633 0 : NTSTATUS status;
2634 :
2635 0 : close(listener_pipe[0]);
2636 0 : set_blocking(listener_pipe[1], false);
2637 :
2638 0 : status = smbd_reinit_after_fork(xconn->client->msg_ctx,
2639 0 : xconn->client->raw_ev_ctx,
2640 : true);
2641 0 : if (!NT_STATUS_IS_OK(status)) {
2642 0 : DEBUG(1, ("reinit_after_fork failed: %s\n",
2643 : nt_errstr(status)));
2644 0 : exit(1);
2645 : }
2646 0 : process_set_title("smbd-echo", "echo handler");
2647 0 : initialize_password_db(true, xconn->client->raw_ev_ctx);
2648 0 : smbd_echo_loop(xconn, listener_pipe[1]);
2649 0 : exit(0);
2650 : }
2651 0 : close(listener_pipe[1]);
2652 0 : listener_pipe[1] = -1;
2653 0 : xconn->smb1.echo_handler.trusted_fd = listener_pipe[0];
2654 :
2655 0 : DEBUG(10,("fork_echo_handler: main[%d] echo_child[%d]\n", (int)getpid(), (int)child));
2656 :
2657 : /*
2658 : * Without smb signing this is the same as the normal smbd
2659 : * listener. This needs to change once signing comes in.
2660 : */
2661 0 : xconn->smb1.echo_handler.trusted_fde = tevent_add_fd(
2662 : xconn->client->raw_ev_ctx,
2663 : xconn,
2664 : xconn->smb1.echo_handler.trusted_fd,
2665 : TEVENT_FD_READ,
2666 : smbd_server_echo_handler,
2667 : xconn);
2668 0 : if (xconn->smb1.echo_handler.trusted_fde == NULL) {
2669 0 : DEBUG(1, ("event_add_fd failed\n"));
2670 0 : goto fail;
2671 : }
2672 :
2673 0 : return true;
2674 :
2675 0 : fail:
2676 0 : if (listener_pipe[0] != -1) {
2677 0 : close(listener_pipe[0]);
2678 : }
2679 0 : if (listener_pipe[1] != -1) {
2680 0 : close(listener_pipe[1]);
2681 : }
2682 0 : if (xconn->smb1.echo_handler.socket_lock_fd != -1) {
2683 0 : close(xconn->smb1.echo_handler.socket_lock_fd);
2684 : }
2685 : #ifdef HAVE_ROBUST_MUTEXES
2686 0 : if (xconn->smb1.echo_handler.socket_mutex != NULL) {
2687 0 : pthread_mutex_destroy(xconn->smb1.echo_handler.socket_mutex);
2688 0 : anonymous_shared_free(xconn->smb1.echo_handler.socket_mutex);
2689 : }
2690 : #endif
2691 0 : smbd_echo_init(xconn);
2692 :
2693 0 : return false;
2694 : }
2695 :
2696 151449 : bool req_is_in_chain(const struct smb_request *req)
2697 : {
2698 151449 : if (req->vwv != (const uint16_t *)(req->inbuf+smb_vwv)) {
2699 : /*
2700 : * We're right now handling a subsequent request, so we must
2701 : * be in a chain
2702 : */
2703 32 : return true;
2704 : }
2705 :
2706 151411 : if (!smb1cli_is_andx_req(req->cmd)) {
2707 32 : return false;
2708 : }
2709 :
2710 151379 : if (req->wct < 2) {
2711 : /*
2712 : * Okay, an illegal request, but definitely not chained :-)
2713 : */
2714 0 : return false;
2715 : }
2716 :
2717 151379 : return (CVAL(req->vwv+0, 0) != 0xFF);
2718 : }
|