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