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