source: branches/samba-3.0/source/smbd/process.c@ 693

Last change on this file since 693 was 693, checked in by Herwig Bauernfeind, 13 years ago

Update Samba 3.0 with CVE-2012-0870 security patch

File size: 50.9 KB
Line 
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
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "includes.h"
23
24uint16 global_smbpid;
25extern int keepalive;
26extern struct auth_context *negprot_global_auth_context;
27extern int smb_echo_count;
28
29static char *InBuffer = NULL;
30static char *OutBuffer = NULL;
31static char *current_inbuf = NULL;
32
33/*
34 * Size of data we can send to client. Set
35 * by the client for all protocols above CORE.
36 * Set by us for CORE protocol.
37 */
38int max_send = BUFFER_SIZE;
39/*
40 * Size of the data we can receive. Set by us.
41 * Can be modified by the max xmit parameter.
42 */
43int max_recv = BUFFER_SIZE;
44
45extern int last_message;
46extern int smb_read_error;
47SIG_ATOMIC_T reload_after_sighup = 0;
48SIG_ATOMIC_T got_sig_term = 0;
49extern BOOL global_machine_password_needs_changing;
50extern int max_send;
51
52/****************************************************************************
53 Function to return the current request mid from Inbuffer.
54****************************************************************************/
55
56uint16 get_current_mid(void)
57{
58 return SVAL(InBuffer,smb_mid);
59}
60
61/****************************************************************************
62 structure to hold a linked list of queued messages.
63 for processing.
64****************************************************************************/
65
66static struct pending_message_list *deferred_open_queue;
67
68/****************************************************************************
69 Function to push a message onto the tail of a linked list of smb messages ready
70 for processing.
71****************************************************************************/
72
73static BOOL push_queued_message(char *buf, int msg_len,
74 struct timeval request_time,
75 struct timeval end_time,
76 char *private_data, size_t private_len)
77{
78 struct pending_message_list *msg;
79
80 msg = TALLOC_ZERO_P(NULL, struct pending_message_list);
81
82 if(msg == NULL) {
83 DEBUG(0,("push_message: malloc fail (1)\n"));
84 return False;
85 }
86
87 msg->buf = data_blob_talloc(msg, buf, msg_len);
88 if(msg->buf.data == NULL) {
89 DEBUG(0,("push_message: malloc fail (2)\n"));
90 TALLOC_FREE(msg);
91 return False;
92 }
93
94 msg->request_time = request_time;
95 msg->end_time = end_time;
96 msg->processed = false;
97
98 if (private_data) {
99 msg->private_data = data_blob_talloc(msg, private_data,
100 private_len);
101 if (msg->private_data.data == NULL) {
102 DEBUG(0,("push_message: malloc fail (3)\n"));
103 TALLOC_FREE(msg);
104 return False;
105 }
106 }
107
108 DLIST_ADD_END(deferred_open_queue, msg, struct pending_message_list *);
109
110 DEBUG(10,("push_message: pushed message length %u on "
111 "deferred_open_queue\n", (unsigned int)msg_len));
112
113 return True;
114}
115
116/****************************************************************************
117 Function to delete a sharing violation open message by mid.
118****************************************************************************/
119
120void remove_deferred_open_smb_message(uint16 mid)
121{
122 struct pending_message_list *pml;
123
124 for (pml = deferred_open_queue; pml; pml = pml->next) {
125 if (mid == SVAL(pml->buf.data,smb_mid)) {
126 DEBUG(10,("remove_sharing_violation_open_smb_message: "
127 "deleting mid %u len %u\n",
128 (unsigned int)mid,
129 (unsigned int)pml->buf.length ));
130 DLIST_REMOVE(deferred_open_queue, pml);
131 TALLOC_FREE(pml);
132 return;
133 }
134 }
135}
136
137/****************************************************************************
138 Move a sharing violation open retry message to the front of the list and
139 schedule it for immediate processing.
140****************************************************************************/
141
142void schedule_deferred_open_smb_message(uint16 mid)
143{
144 struct pending_message_list *pml;
145 int i = 0;
146
147 for (pml = deferred_open_queue; pml; pml = pml->next) {
148 uint16 msg_mid = SVAL(pml->buf.data,smb_mid);
149 DEBUG(10,("schedule_deferred_open_smb_message: [%d] msg_mid = %u\n", i++,
150 (unsigned int)msg_mid ));
151 if (mid == msg_mid) {
152 DEBUG(10,("schedule_deferred_open_smb_message: scheduling mid %u\n",
153 mid ));
154 pml->end_time.tv_sec = 0;
155 pml->end_time.tv_usec = 0;
156 DLIST_PROMOTE(deferred_open_queue, pml);
157 return;
158 }
159 }
160
161 DEBUG(10,("schedule_deferred_open_smb_message: failed to find message mid %u\n",
162 mid ));
163}
164
165/****************************************************************************
166 Return true if this mid is on the deferred queue and was not yet processed.
167****************************************************************************/
168
169BOOL open_was_deferred(uint16 mid)
170{
171 struct pending_message_list *pml;
172
173 for (pml = deferred_open_queue; pml; pml = pml->next) {
174 if (SVAL(pml->buf.data,smb_mid) == mid && !pml->processed) {
175 return True;
176 }
177 }
178 return False;
179}
180
181/****************************************************************************
182 Return the message queued by this mid.
183****************************************************************************/
184
185struct pending_message_list *get_open_deferred_message(uint16 mid)
186{
187 struct pending_message_list *pml;
188
189 for (pml = deferred_open_queue; pml; pml = pml->next) {
190 if (SVAL(pml->buf.data,smb_mid) == mid) {
191 return pml;
192 }
193 }
194 return NULL;
195}
196
197/****************************************************************************
198 Function to push a deferred open smb message onto a linked list of local smb
199 messages ready for processing.
200****************************************************************************/
201
202BOOL push_deferred_smb_message(uint16 mid,
203 struct timeval request_time,
204 struct timeval timeout,
205 char *private_data, size_t priv_len)
206{
207 struct timeval end_time;
208
209 end_time = timeval_sum(&request_time, &timeout);
210
211 DEBUG(10,("push_deferred_open_smb_message: pushing message len %u mid %u "
212 "timeout time [%u.%06u]\n",
213 (unsigned int) smb_len(current_inbuf)+4, (unsigned int)mid,
214 (unsigned int)end_time.tv_sec,
215 (unsigned int)end_time.tv_usec));
216
217 return push_queued_message(current_inbuf, smb_len(current_inbuf)+4,
218 request_time, end_time,
219 private_data, priv_len);
220}
221
222struct idle_event {
223 struct timed_event *te;
224 struct timeval interval;
225 BOOL (*handler)(const struct timeval *now, void *private_data);
226 void *private_data;
227};
228
229static void idle_event_handler(struct event_context *ctx,
230 struct timed_event *te,
231 const struct timeval *now,
232 void *private_data)
233{
234 struct idle_event *event =
235 talloc_get_type_abort(private_data, struct idle_event);
236
237 TALLOC_FREE(event->te);
238
239 if (!event->handler(now, event->private_data)) {
240 /* Don't repeat, delete ourselves */
241 TALLOC_FREE(event);
242 return;
243 }
244
245 event->te = event_add_timed(smbd_event_context(), event,
246 timeval_sum(now, &event->interval),
247 "idle_event_handler",
248 idle_event_handler, event);
249
250 /* We can't do much but fail here. */
251 SMB_ASSERT(event->te != NULL);
252}
253
254struct idle_event *add_idle_event(TALLOC_CTX *mem_ctx,
255 struct timeval interval,
256 BOOL (*handler)(const struct timeval *now,
257 void *private_data),
258 void *private_data)
259{
260 struct idle_event *result;
261 struct timeval now = timeval_current();
262
263 result = TALLOC_P(mem_ctx, struct idle_event);
264 if (result == NULL) {
265 DEBUG(0, ("talloc failed\n"));
266 return NULL;
267 }
268
269 result->interval = interval;
270 result->handler = handler;
271 result->private_data = private_data;
272
273 result->te = event_add_timed(smbd_event_context(), result,
274 timeval_sum(&now, &interval),
275 "idle_event_handler",
276 idle_event_handler, result);
277 if (result->te == NULL) {
278 DEBUG(0, ("event_add_timed failed\n"));
279 TALLOC_FREE(result);
280 return NULL;
281 }
282
283 return result;
284}
285
286/****************************************************************************
287 Do all async processing in here. This includes kernel oplock messages, change
288 notify events etc.
289****************************************************************************/
290
291static void async_processing(fd_set *pfds)
292{
293 DEBUG(10,("async_processing: Doing async processing.\n"));
294
295 process_aio_queue();
296
297 process_kernel_oplocks(pfds);
298
299 /* Do the aio check again after receive_local_message as it does a
300 select and may have eaten our signal. */
301 /* Is this till true? -- vl */
302 process_aio_queue();
303
304 if (got_sig_term) {
305 exit_server_cleanly("termination signal");
306 }
307
308 /* check for sighup processing */
309 if (reload_after_sighup) {
310 change_to_root_user();
311 DEBUG(1,("Reloading services after SIGHUP\n"));
312 reload_services(False);
313 reload_after_sighup = 0;
314 }
315}
316
317/****************************************************************************
318 Add a fd to the set we will be select(2)ing on.
319****************************************************************************/
320
321static int select_on_fd(int fd, int maxfd, fd_set *fds)
322{
323 if (fd != -1) {
324 FD_SET(fd, fds);
325 maxfd = MAX(maxfd, fd);
326 }
327
328 return maxfd;
329}
330
331/****************************************************************************
332 Do a select on an two fd's - with timeout.
333
334 If a local udp message has been pushed onto the
335 queue (this can only happen during oplock break
336 processing) call async_processing()
337
338 If a pending smb message has been pushed onto the
339 queue (this can only happen during oplock break
340 processing) return this next.
341
342 If the first smbfd is ready then read an smb from it.
343 if the second (loopback UDP) fd is ready then read a message
344 from it and setup the buffer header to identify the length
345 and from address.
346 Returns False on timeout or error.
347 Else returns True.
348
349The timeout is in milliseconds
350****************************************************************************/
351
352static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
353{
354 fd_set r_fds, w_fds;
355 int selrtn;
356 struct timeval to;
357 int maxfd = 0;
358
359 smb_read_error = 0;
360
361 again:
362
363 if (timeout >= 0) {
364 to.tv_sec = timeout / 1000;
365 to.tv_usec = (timeout % 1000) * 1000;
366 } else {
367 to.tv_sec = SMBD_SELECT_TIMEOUT;
368 to.tv_usec = 0;
369 }
370
371 /*
372 * Note that this call must be before processing any SMB
373 * messages as we need to synchronously process any messages
374 * we may have sent to ourselves from the previous SMB.
375 */
376 message_dispatch();
377
378 /*
379 * Check to see if we already have a message on the deferred open queue
380 * and it's time to schedule.
381 */
382 if(deferred_open_queue != NULL) {
383 BOOL pop_message = False;
384 struct pending_message_list *msg = deferred_open_queue;
385
386 if (timeval_is_zero(&msg->end_time)) {
387 pop_message = True;
388 } else {
389 struct timeval tv;
390 SMB_BIG_INT tdif;
391
392 GetTimeOfDay(&tv);
393 tdif = usec_time_diff(&msg->end_time, &tv);
394 if (tdif <= 0) {
395 /* Timed out. Schedule...*/
396 pop_message = True;
397 DEBUG(10,("receive_message_or_smb: queued message timed out.\n"));
398 } else {
399 /* Make a more accurate select timeout. */
400 to.tv_sec = tdif / 1000000;
401 to.tv_usec = tdif % 1000000;
402 DEBUG(10,("receive_message_or_smb: select with timeout of [%u.%06u]\n",
403 (unsigned int)to.tv_sec, (unsigned int)to.tv_usec ));
404 }
405 }
406
407 if (pop_message) {
408 memcpy(buffer, msg->buf.data, MIN(buffer_len, msg->buf.length));
409
410 /* We leave this message on the queue so the open code can
411 know this is a retry. */
412 DEBUG(5,("receive_message_or_smb: returning deferred open smb message.\n"));
413
414 /* Mark the message as processed so this is not
415 * re-processed in error. */
416 msg->processed = true;
417 return True;
418 }
419 }
420
421 /*
422 * Setup the select fd sets.
423 */
424
425 FD_ZERO(&r_fds);
426 FD_ZERO(&w_fds);
427
428 /*
429 * Ensure we process oplock break messages by preference.
430 * We have to do this before the select, after the select
431 * and if the select returns EINTR. This is due to the fact
432 * that the selects called from async_processing can eat an EINTR
433 * caused by a signal (we can't take the break message there).
434 * This is hideously complex - *MUST* be simplified for 3.0 ! JRA.
435 */
436
437 if (oplock_message_waiting(&r_fds)) {
438 DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
439 async_processing(&r_fds);
440 /*
441 * After async processing we must go and do the select again, as
442 * the state of the flag in fds for the server file descriptor is
443 * indeterminate - we may have done I/O on it in the oplock processing. JRA.
444 */
445 goto again;
446 }
447
448 /*
449 * Are there any timed events waiting ? If so, ensure we don't
450 * select for longer than it would take to wait for them.
451 */
452
453 {
454 struct timeval now;
455 GetTimeOfDay(&now);
456
457 event_add_to_select_args(smbd_event_context(), &now,
458 &r_fds, &w_fds, &to, &maxfd);
459 }
460
461 if (timeval_is_zero(&to)) {
462 /* Process a timed event now... */
463 if (run_events(smbd_event_context(), 0, NULL, NULL)) {
464 goto again;
465 }
466 }
467
468 {
469 int sav;
470 START_PROFILE(smbd_idle);
471
472 maxfd = select_on_fd(smbd_server_fd(), maxfd, &r_fds);
473 maxfd = select_on_fd(oplock_notify_fd(), maxfd, &r_fds);
474
475 selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&to);
476 sav = errno;
477
478 END_PROFILE(smbd_idle);
479 errno = sav;
480 }
481
482 if (run_events(smbd_event_context(), selrtn, &r_fds, &w_fds)) {
483 goto again;
484 }
485
486 /* if we get EINTR then maybe we have received an oplock
487 signal - treat this as select returning 1. This is ugly, but
488 is the best we can do until the oplock code knows more about
489 signals */
490 if (selrtn == -1 && errno == EINTR) {
491 async_processing(&r_fds);
492 /*
493 * After async processing we must go and do the select again, as
494 * the state of the flag in fds for the server file descriptor is
495 * indeterminate - we may have done I/O on it in the oplock processing. JRA.
496 */
497 goto again;
498 }
499
500 /* Check if error */
501 if (selrtn == -1) {
502 /* something is wrong. Maybe the socket is dead? */
503 smb_read_error = READ_ERROR;
504 return False;
505 }
506
507 /* Did we timeout ? */
508 if (selrtn == 0) {
509 smb_read_error = READ_TIMEOUT;
510 return False;
511 }
512
513 /*
514 * Ensure we process oplock break messages by preference.
515 * This is IMPORTANT ! Otherwise we can starve other processes
516 * sending us an oplock break message. JRA.
517 */
518
519 if (oplock_message_waiting(&r_fds)) {
520 async_processing(&r_fds);
521 /*
522 * After async processing we must go and do the select again, as
523 * the state of the flag in fds for the server file descriptor is
524 * indeterminate - we may have done I/O on it in the oplock processing. JRA.
525 */
526 goto again;
527 }
528
529 return receive_smb(smbd_server_fd(), buffer,
530 BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE, 0);
531}
532
533/*
534 * Only allow 5 outstanding trans requests. We're allocating memory, so
535 * prevent a DoS.
536 */
537
538NTSTATUS allow_new_trans(struct trans_state *list, int mid)
539{
540 int count = 0;
541 for (; list != NULL; list = list->next) {
542
543 if (list->mid == mid) {
544 return NT_STATUS_INVALID_PARAMETER;
545 }
546
547 count += 1;
548 }
549 if (count > 5) {
550 return NT_STATUS_INSUFFICIENT_RESOURCES;
551 }
552
553 return NT_STATUS_OK;
554}
555
556/****************************************************************************
557 We're terminating and have closed all our files/connections etc.
558 If there are any pending local messages we need to respond to them
559 before termination so that other smbds don't think we just died whilst
560 holding oplocks.
561****************************************************************************/
562
563void respond_to_all_remaining_local_messages(void)
564{
565 /*
566 * Assert we have no exclusive open oplocks.
567 */
568
569 if(get_number_of_exclusive_open_oplocks()) {
570 DEBUG(0,("respond_to_all_remaining_local_messages: PANIC : we have %d exclusive oplocks.\n",
571 get_number_of_exclusive_open_oplocks() ));
572 return;
573 }
574
575 process_kernel_oplocks(NULL);
576
577 return;
578}
579
580
581/*
582These flags determine some of the permissions required to do an operation
583
584Note that I don't set NEED_WRITE on some write operations because they
585are used by some brain-dead clients when printing, and I don't want to
586force write permissions on print services.
587*/
588#define AS_USER (1<<0)
589#define NEED_WRITE (1<<1) /* Must be paired with AS_USER */
590#define TIME_INIT (1<<2)
591#define CAN_IPC (1<<3) /* Must be paired with AS_USER */
592#define AS_GUEST (1<<5) /* Must *NOT* be paired with AS_USER */
593#define DO_CHDIR (1<<6)
594
595/*
596 define a list of possible SMB messages and their corresponding
597 functions. Any message that has a NULL function is unimplemented -
598 please feel free to contribute implementations!
599*/
600static const struct smb_message_struct {
601 const char *name;
602 int (*fn)(connection_struct *conn, char *, char *, int, int);
603 int flags;
604} smb_messages[256] = {
605
606/* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
607/* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
608/* 0x02 */ { "SMBopen",reply_open,AS_USER },
609/* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
610/* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
611/* 0x05 */ { "SMBflush",reply_flush,AS_USER},
612/* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
613/* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
614/* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
615/* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
616/* 0x0a */ { "SMBread",reply_read,AS_USER},
617/* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
618/* 0x0c */ { "SMBlock",reply_lock,AS_USER},
619/* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
620/* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
621/* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
622/* 0x10 */ { "SMBcheckpath",reply_checkpath,AS_USER},
623/* 0x11 */ { "SMBexit",reply_exit,DO_CHDIR},
624/* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
625/* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
626/* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
627/* 0x15 */ { NULL, NULL, 0 },
628/* 0x16 */ { NULL, NULL, 0 },
629/* 0x17 */ { NULL, NULL, 0 },
630/* 0x18 */ { NULL, NULL, 0 },
631/* 0x19 */ { NULL, NULL, 0 },
632/* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
633/* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
634/* 0x1c */ { "SMBreadBs",NULL,0 },
635/* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
636/* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
637/* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
638/* 0x20 */ { "SMBwritec",NULL,0},
639/* 0x21 */ { NULL, NULL, 0 },
640/* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
641/* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
642/* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
643/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
644/* 0x26 */ { "SMBtranss",reply_transs,AS_USER | CAN_IPC},
645/* 0x27 */ { "SMBioctl",reply_ioctl,0},
646/* 0x28 */ { "SMBioctls",NULL,AS_USER},
647/* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
648/* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE },
649/* 0x2b */ { "SMBecho",reply_echo,0},
650/* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
651/* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
652/* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
653/* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
654/* 0x30 */ { NULL, NULL, 0 },
655/* 0x31 */ { NULL, NULL, 0 },
656/* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
657/* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
658/* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
659/* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
660/* 0x36 */ { NULL, NULL, 0 },
661/* 0x37 */ { NULL, NULL, 0 },
662/* 0x38 */ { NULL, NULL, 0 },
663/* 0x39 */ { NULL, NULL, 0 },
664/* 0x3a */ { NULL, NULL, 0 },
665/* 0x3b */ { NULL, NULL, 0 },
666/* 0x3c */ { NULL, NULL, 0 },
667/* 0x3d */ { NULL, NULL, 0 },
668/* 0x3e */ { NULL, NULL, 0 },
669/* 0x3f */ { NULL, NULL, 0 },
670/* 0x40 */ { NULL, NULL, 0 },
671/* 0x41 */ { NULL, NULL, 0 },
672/* 0x42 */ { NULL, NULL, 0 },
673/* 0x43 */ { NULL, NULL, 0 },
674/* 0x44 */ { NULL, NULL, 0 },
675/* 0x45 */ { NULL, NULL, 0 },
676/* 0x46 */ { NULL, NULL, 0 },
677/* 0x47 */ { NULL, NULL, 0 },
678/* 0x48 */ { NULL, NULL, 0 },
679/* 0x49 */ { NULL, NULL, 0 },
680/* 0x4a */ { NULL, NULL, 0 },
681/* 0x4b */ { NULL, NULL, 0 },
682/* 0x4c */ { NULL, NULL, 0 },
683/* 0x4d */ { NULL, NULL, 0 },
684/* 0x4e */ { NULL, NULL, 0 },
685/* 0x4f */ { NULL, NULL, 0 },
686/* 0x50 */ { NULL, NULL, 0 },
687/* 0x51 */ { NULL, NULL, 0 },
688/* 0x52 */ { NULL, NULL, 0 },
689/* 0x53 */ { NULL, NULL, 0 },
690/* 0x54 */ { NULL, NULL, 0 },
691/* 0x55 */ { NULL, NULL, 0 },
692/* 0x56 */ { NULL, NULL, 0 },
693/* 0x57 */ { NULL, NULL, 0 },
694/* 0x58 */ { NULL, NULL, 0 },
695/* 0x59 */ { NULL, NULL, 0 },
696/* 0x5a */ { NULL, NULL, 0 },
697/* 0x5b */ { NULL, NULL, 0 },
698/* 0x5c */ { NULL, NULL, 0 },
699/* 0x5d */ { NULL, NULL, 0 },
700/* 0x5e */ { NULL, NULL, 0 },
701/* 0x5f */ { NULL, NULL, 0 },
702/* 0x60 */ { NULL, NULL, 0 },
703/* 0x61 */ { NULL, NULL, 0 },
704/* 0x62 */ { NULL, NULL, 0 },
705/* 0x63 */ { NULL, NULL, 0 },
706/* 0x64 */ { NULL, NULL, 0 },
707/* 0x65 */ { NULL, NULL, 0 },
708/* 0x66 */ { NULL, NULL, 0 },
709/* 0x67 */ { NULL, NULL, 0 },
710/* 0x68 */ { NULL, NULL, 0 },
711/* 0x69 */ { NULL, NULL, 0 },
712/* 0x6a */ { NULL, NULL, 0 },
713/* 0x6b */ { NULL, NULL, 0 },
714/* 0x6c */ { NULL, NULL, 0 },
715/* 0x6d */ { NULL, NULL, 0 },
716/* 0x6e */ { NULL, NULL, 0 },
717/* 0x6f */ { NULL, NULL, 0 },
718/* 0x70 */ { "SMBtcon",reply_tcon,0},
719/* 0x71 */ { "SMBtdis",reply_tdis,DO_CHDIR},
720/* 0x72 */ { "SMBnegprot",reply_negprot,0},
721/* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0},
722/* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
723/* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
724/* 0x76 */ { NULL, NULL, 0 },
725/* 0x77 */ { NULL, NULL, 0 },
726/* 0x78 */ { NULL, NULL, 0 },
727/* 0x79 */ { NULL, NULL, 0 },
728/* 0x7a */ { NULL, NULL, 0 },
729/* 0x7b */ { NULL, NULL, 0 },
730/* 0x7c */ { NULL, NULL, 0 },
731/* 0x7d */ { NULL, NULL, 0 },
732/* 0x7e */ { NULL, NULL, 0 },
733/* 0x7f */ { NULL, NULL, 0 },
734/* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
735/* 0x81 */ { "SMBsearch",reply_search,AS_USER},
736/* 0x82 */ { "SMBffirst",reply_search,AS_USER},
737/* 0x83 */ { "SMBfunique",reply_search,AS_USER},
738/* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
739/* 0x85 */ { NULL, NULL, 0 },
740/* 0x86 */ { NULL, NULL, 0 },
741/* 0x87 */ { NULL, NULL, 0 },
742/* 0x88 */ { NULL, NULL, 0 },
743/* 0x89 */ { NULL, NULL, 0 },
744/* 0x8a */ { NULL, NULL, 0 },
745/* 0x8b */ { NULL, NULL, 0 },
746/* 0x8c */ { NULL, NULL, 0 },
747/* 0x8d */ { NULL, NULL, 0 },
748/* 0x8e */ { NULL, NULL, 0 },
749/* 0x8f */ { NULL, NULL, 0 },
750/* 0x90 */ { NULL, NULL, 0 },
751/* 0x91 */ { NULL, NULL, 0 },
752/* 0x92 */ { NULL, NULL, 0 },
753/* 0x93 */ { NULL, NULL, 0 },
754/* 0x94 */ { NULL, NULL, 0 },
755/* 0x95 */ { NULL, NULL, 0 },
756/* 0x96 */ { NULL, NULL, 0 },
757/* 0x97 */ { NULL, NULL, 0 },
758/* 0x98 */ { NULL, NULL, 0 },
759/* 0x99 */ { NULL, NULL, 0 },
760/* 0x9a */ { NULL, NULL, 0 },
761/* 0x9b */ { NULL, NULL, 0 },
762/* 0x9c */ { NULL, NULL, 0 },
763/* 0x9d */ { NULL, NULL, 0 },
764/* 0x9e */ { NULL, NULL, 0 },
765/* 0x9f */ { NULL, NULL, 0 },
766/* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
767/* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
768/* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC },
769/* 0xa3 */ { NULL, NULL, 0 },
770/* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
771/* 0xa5 */ { "SMBntrename", reply_ntrename, AS_USER | NEED_WRITE },
772/* 0xa6 */ { NULL, NULL, 0 },
773/* 0xa7 */ { NULL, NULL, 0 },
774/* 0xa8 */ { NULL, NULL, 0 },
775/* 0xa9 */ { NULL, NULL, 0 },
776/* 0xaa */ { NULL, NULL, 0 },
777/* 0xab */ { NULL, NULL, 0 },
778/* 0xac */ { NULL, NULL, 0 },
779/* 0xad */ { NULL, NULL, 0 },
780/* 0xae */ { NULL, NULL, 0 },
781/* 0xaf */ { NULL, NULL, 0 },
782/* 0xb0 */ { NULL, NULL, 0 },
783/* 0xb1 */ { NULL, NULL, 0 },
784/* 0xb2 */ { NULL, NULL, 0 },
785/* 0xb3 */ { NULL, NULL, 0 },
786/* 0xb4 */ { NULL, NULL, 0 },
787/* 0xb5 */ { NULL, NULL, 0 },
788/* 0xb6 */ { NULL, NULL, 0 },
789/* 0xb7 */ { NULL, NULL, 0 },
790/* 0xb8 */ { NULL, NULL, 0 },
791/* 0xb9 */ { NULL, NULL, 0 },
792/* 0xba */ { NULL, NULL, 0 },
793/* 0xbb */ { NULL, NULL, 0 },
794/* 0xbc */ { NULL, NULL, 0 },
795/* 0xbd */ { NULL, NULL, 0 },
796/* 0xbe */ { NULL, NULL, 0 },
797/* 0xbf */ { NULL, NULL, 0 },
798/* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER},
799/* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
800/* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
801/* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
802/* 0xc4 */ { NULL, NULL, 0 },
803/* 0xc5 */ { NULL, NULL, 0 },
804/* 0xc6 */ { NULL, NULL, 0 },
805/* 0xc7 */ { NULL, NULL, 0 },
806/* 0xc8 */ { NULL, NULL, 0 },
807/* 0xc9 */ { NULL, NULL, 0 },
808/* 0xca */ { NULL, NULL, 0 },
809/* 0xcb */ { NULL, NULL, 0 },
810/* 0xcc */ { NULL, NULL, 0 },
811/* 0xcd */ { NULL, NULL, 0 },
812/* 0xce */ { NULL, NULL, 0 },
813/* 0xcf */ { NULL, NULL, 0 },
814/* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
815/* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
816/* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
817/* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
818/* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
819/* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
820/* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
821/* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
822/* 0xd8 */ { NULL, NULL, 0 },
823/* 0xd9 */ { NULL, NULL, 0 },
824/* 0xda */ { NULL, NULL, 0 },
825/* 0xdb */ { NULL, NULL, 0 },
826/* 0xdc */ { NULL, NULL, 0 },
827/* 0xdd */ { NULL, NULL, 0 },
828/* 0xde */ { NULL, NULL, 0 },
829/* 0xdf */ { NULL, NULL, 0 },
830/* 0xe0 */ { NULL, NULL, 0 },
831/* 0xe1 */ { NULL, NULL, 0 },
832/* 0xe2 */ { NULL, NULL, 0 },
833/* 0xe3 */ { NULL, NULL, 0 },
834/* 0xe4 */ { NULL, NULL, 0 },
835/* 0xe5 */ { NULL, NULL, 0 },
836/* 0xe6 */ { NULL, NULL, 0 },
837/* 0xe7 */ { NULL, NULL, 0 },
838/* 0xe8 */ { NULL, NULL, 0 },
839/* 0xe9 */ { NULL, NULL, 0 },
840/* 0xea */ { NULL, NULL, 0 },
841/* 0xeb */ { NULL, NULL, 0 },
842/* 0xec */ { NULL, NULL, 0 },
843/* 0xed */ { NULL, NULL, 0 },
844/* 0xee */ { NULL, NULL, 0 },
845/* 0xef */ { NULL, NULL, 0 },
846/* 0xf0 */ { NULL, NULL, 0 },
847/* 0xf1 */ { NULL, NULL, 0 },
848/* 0xf2 */ { NULL, NULL, 0 },
849/* 0xf3 */ { NULL, NULL, 0 },
850/* 0xf4 */ { NULL, NULL, 0 },
851/* 0xf5 */ { NULL, NULL, 0 },
852/* 0xf6 */ { NULL, NULL, 0 },
853/* 0xf7 */ { NULL, NULL, 0 },
854/* 0xf8 */ { NULL, NULL, 0 },
855/* 0xf9 */ { NULL, NULL, 0 },
856/* 0xfa */ { NULL, NULL, 0 },
857/* 0xfb */ { NULL, NULL, 0 },
858/* 0xfc */ { NULL, NULL, 0 },
859/* 0xfd */ { NULL, NULL, 0 },
860/* 0xfe */ { NULL, NULL, 0 },
861/* 0xff */ { NULL, NULL, 0 }
862
863};
864
865/*******************************************************************
866 Dump a packet to a file.
867********************************************************************/
868
869static void smb_dump(const char *name, int type, char *data, ssize_t len)
870{
871 int fd, i;
872 pstring fname;
873 if (DEBUGLEVEL < 50) return;
874
875 if (len < 4) len = smb_len(data)+4;
876 for (i=1;i<100;i++) {
877 slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.%s", name, i,
878 type ? "req" : "resp");
879 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
880 if (fd != -1 || errno != EEXIST) break;
881 }
882 if (fd != -1) {
883 ssize_t ret = write(fd, data, len);
884 if (ret != len)
885 DEBUG(0,("smb_dump: problem: write returned %d\n", (int)ret ));
886 close(fd);
887 DEBUG(0,("created %s len %lu\n", fname, (unsigned long)len));
888 }
889}
890
891
892/****************************************************************************
893 Do a switch on the message type, and return the response size
894****************************************************************************/
895
896static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize)
897{
898 static pid_t pid= (pid_t)-1;
899 int outsize = 0;
900
901 type &= 0xff;
902
903 if (pid == (pid_t)-1)
904 pid = sys_getpid();
905
906 errno = 0;
907
908 last_message = type;
909
910 /* Make sure this is an SMB packet. smb_size contains NetBIOS header so subtract 4 from it. */
911 if ((strncmp(smb_base(inbuf),"\377SMB",4) != 0) || (size < (smb_size - 4))) {
912 DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",smb_len(inbuf)));
913 exit_server_cleanly("Non-SMB packet");
914 return(-1);
915 }
916
917 /* yuck! this is an interim measure before we get rid of our
918 current inbuf/outbuf system */
919 global_smbpid = SVAL(inbuf,smb_pid);
920
921 if (smb_messages[type].fn == NULL) {
922 DEBUG(0,("Unknown message type %d!\n",type));
923 smb_dump("Unknown", 1, inbuf, size);
924 outsize = reply_unknown(inbuf,outbuf);
925 } else {
926 int flags = smb_messages[type].flags;
927 static uint16 last_session_tag = UID_FIELD_INVALID;
928 /* In share mode security we must ignore the vuid. */
929 uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
930 connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
931
932 DEBUG(3,("switch message %s (pid %d) conn 0x%lx\n",smb_fn_name(type),(int)pid,(unsigned long)conn));
933
934 smb_dump(smb_fn_name(type), 1, inbuf, size);
935
936 /* Ensure this value is replaced in the incoming packet. */
937 SSVAL(inbuf,smb_uid,session_tag);
938
939 /*
940 * Ensure the correct username is in current_user_info.
941 * This is a really ugly bugfix for problems with
942 * multiple session_setup_and_X's being done and
943 * allowing %U and %G substitutions to work correctly.
944 * There is a reason this code is done here, don't
945 * move it unless you know what you're doing... :-).
946 * JRA.
947 */
948
949 if (session_tag != last_session_tag) {
950 user_struct *vuser = NULL;
951
952 last_session_tag = session_tag;
953 if(session_tag != UID_FIELD_INVALID) {
954 vuser = get_valid_user_struct(session_tag);
955 if (vuser) {
956 set_current_user_info(&vuser->user);
957 }
958 }
959 }
960
961 /* Does this call need to be run as the connected user? */
962 if (flags & AS_USER) {
963
964 /* Does this call need a valid tree connection? */
965 if (!conn) {
966 /* Amazingly, the error code depends on the command (from Samba4). */
967 if (type == SMBntcreateX) {
968 return ERROR_NT(NT_STATUS_INVALID_HANDLE);
969 } else {
970 return ERROR_DOS(ERRSRV, ERRinvnid);
971 }
972 }
973
974 if (!change_to_user(conn,session_tag)) {
975 return(ERROR_NT(NT_STATUS_DOS(ERRSRV,ERRbaduid)));
976 }
977
978 /* All NEED_WRITE and CAN_IPC flags must also have AS_USER. */
979
980 /* Does it need write permission? */
981 if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) {
982 return ERROR_NT(NT_STATUS_MEDIA_WRITE_PROTECTED);
983 }
984
985 /* IPC services are limited */
986 if (IS_IPC(conn) && !(flags & CAN_IPC)) {
987 return(ERROR_DOS(ERRSRV,ERRaccess));
988 }
989 } else {
990 /* This call needs to be run as root */
991 change_to_root_user();
992 }
993
994 /* load service specific parameters */
995 if (conn) {
996 if (!set_current_service(conn,SVAL(inbuf,smb_flg),(flags & (AS_USER|DO_CHDIR)?True:False))) {
997 return(ERROR_DOS(ERRSRV,ERRaccess));
998 }
999 conn->num_smb_operations++;
1000 }
1001
1002 /* does this protocol need to be run as guest? */
1003 if ((flags & AS_GUEST) && (!change_to_guest() ||
1004 !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) {
1005 return(ERROR_DOS(ERRSRV,ERRaccess));
1006 }
1007
1008 current_inbuf = inbuf; /* In case we need to defer this message in open... */
1009 outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize);
1010 }
1011
1012 smb_dump(smb_fn_name(type), 0, outbuf, outsize);
1013
1014 return(outsize);
1015}
1016
1017/****************************************************************************
1018 Construct a reply to the incoming packet.
1019****************************************************************************/
1020
1021static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
1022{
1023 struct pending_message_list *pml = NULL;
1024 int type = CVAL(inbuf,smb_com);
1025 int outsize = 0;
1026 int msg_type = CVAL(inbuf,0);
1027 uint16_t mid = SVAL(inbuf, smb_mid);
1028 uint8_t wct = CVAL(inbuf, smb_wct);
1029
1030 chain_size = 0;
1031 file_chain_reset();
1032 reset_chain_p();
1033
1034 if (msg_type != 0)
1035 return(reply_special(inbuf,outbuf));
1036
1037 /* Ensure we have at least wct words and 2 bytes of bcc. */
1038 if (smb_size + wct*2 > size) {
1039 DEBUG(0,("init_smb_request: invalid wct number %u (size %u)\n",
1040 (unsigned int)wct,
1041 (unsigned int)size));
1042 exit_server_cleanly("Invalid SMB request");
1043 }
1044 /* Ensure bcc is correct. */
1045 if (((uint8 *)smb_buf(inbuf)) + smb_buflen(inbuf) > inbuf + size) {
1046 DEBUG(0,("init_smb_request: invalid bcc number %u "
1047 "(wct = %u, size %u)\n",
1048 (unsigned int)smb_buflen(inbuf),
1049 (unsigned int)wct,
1050 (unsigned int)size));
1051 exit_server_cleanly("Invalid SMB request");
1052 }
1053
1054 construct_reply_common(inbuf, outbuf);
1055
1056 outsize = switch_message(type,inbuf,outbuf,size,bufsize);
1057
1058 /* If this was a deferred message and it's still there and
1059 * was processed, remove it. */
1060 pml = get_open_deferred_message(mid);
1061 if (pml && pml->processed) {
1062 remove_deferred_open_smb_message(mid);
1063 }
1064
1065 outsize += chain_size;
1066
1067 if(outsize > 4)
1068 smb_setlen(outbuf,outsize - 4);
1069 return(outsize);
1070}
1071
1072/****************************************************************************
1073 Process an smb from the client
1074****************************************************************************/
1075
1076static void process_smb(char *inbuf, char *outbuf)
1077{
1078 static int trans_num;
1079 int msg_type = CVAL(inbuf,0);
1080 int32 len = smb_len(inbuf);
1081 int nread = len + 4;
1082
1083 DO_PROFILE_INC(smb_count);
1084
1085 if (trans_num == 0) {
1086 /* on the first packet, check the global hosts allow/ hosts
1087 deny parameters before doing any parsing of the packet
1088 passed to us by the client. This prevents attacks on our
1089 parsing code from hosts not in the hosts allow list */
1090 if (!check_access(smbd_server_fd(), lp_hostsallow(-1),
1091 lp_hostsdeny(-1))) {
1092 /* send a negative session response "not listening on calling name" */
1093 static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
1094 DEBUG( 1, ( "Connection denied from %s\n", client_addr() ) );
1095 (void)send_smb(smbd_server_fd(),(char *)buf);
1096 exit_server_cleanly("connection denied");
1097 }
1098 }
1099
1100 DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type, len ) );
1101 DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) );
1102
1103 if (msg_type == 0)
1104 show_msg(inbuf);
1105 else if(msg_type == SMBkeepalive)
1106 return; /* Keepalive packet. */
1107
1108 nread = construct_reply(inbuf,outbuf,nread,max_send);
1109
1110 if(nread > 0) {
1111 if (CVAL(outbuf,0) == 0)
1112 show_msg(outbuf);
1113
1114 if (nread != smb_len(outbuf) + 4) {
1115 DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
1116 nread, smb_len(outbuf)));
1117 } else if (!send_smb(smbd_server_fd(),outbuf)) {
1118 exit_server_cleanly("process_smb: send_smb failed.");
1119 }
1120 }
1121 trans_num++;
1122}
1123
1124/****************************************************************************
1125 Return a string containing the function name of a SMB command.
1126****************************************************************************/
1127
1128const char *smb_fn_name(int type)
1129{
1130 const char *unknown_name = "SMBunknown";
1131
1132 if (smb_messages[type].name == NULL)
1133 return(unknown_name);
1134
1135 return(smb_messages[type].name);
1136}
1137
1138/****************************************************************************
1139 Helper functions for contruct_reply.
1140****************************************************************************/
1141
1142static uint32 common_flags2 = FLAGS2_LONG_PATH_COMPONENTS|FLAGS2_32_BIT_ERROR_CODES;
1143
1144void add_to_common_flags2(uint32 v)
1145{
1146 common_flags2 |= v;
1147}
1148
1149void remove_from_common_flags2(uint32 v)
1150{
1151 common_flags2 &= ~v;
1152}
1153
1154void construct_reply_common(const char *inbuf, char *outbuf)
1155{
1156 set_message(outbuf,0,0,False);
1157
1158 SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com));
1159 SIVAL(outbuf,smb_rcls,0);
1160 SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES));
1161 SSVAL(outbuf,smb_flg2,
1162 (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) |
1163 common_flags2);
1164 memset(outbuf+smb_pidhigh,'\0',(smb_tid-smb_pidhigh));
1165
1166 SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
1167 SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
1168 SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
1169 SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));
1170}
1171
1172/****************************************************************************
1173 Construct a chained reply and add it to the already made reply
1174****************************************************************************/
1175
1176int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
1177{
1178 static char *orig_inbuf;
1179 static char *orig_outbuf;
1180 static int orig_size;
1181 int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0);
1182 static unsigned smb_off2;
1183 char *inbuf2, *outbuf2;
1184 int outsize2;
1185 int new_size;
1186 char inbuf_saved[smb_wct];
1187 char outbuf_saved[smb_wct];
1188 int outsize = smb_len(outbuf) + 4;
1189
1190 /* Maybe its not chained, or it's an error packet. */
1191 if (smb_com2 == 0xFF || SVAL(outbuf,smb_rcls) != 0) {
1192 SCVAL(outbuf,smb_vwv0,0xFF);
1193 return outsize;
1194 }
1195
1196 if (chain_size == 0) {
1197 /* this is the first part of the chain */
1198 orig_inbuf = inbuf;
1199 orig_outbuf = outbuf;
1200 orig_size = size;
1201 smb_off2 = 0;
1202 }
1203
1204 if (SVAL(inbuf,smb_vwv1) <= smb_off2) {
1205 DEBUG(1, ("AndX offset not increasing\n"));
1206 SCVAL(outbuf, smb_vwv0, 0xFF);
1207 return outsize;
1208 }
1209 smb_off2 = SVAL(inbuf, smb_vwv1);
1210
1211 /* Validate smb_off2 */
1212 if ((smb_off2 < smb_wct - 4) || orig_size < (smb_off2 + 4 - smb_wct)) {
1213 exit_server_cleanly("Bad chained packet");
1214 return -1;
1215 }
1216
1217 /*
1218 * The original Win95 redirector dies on a reply to
1219 * a lockingX and read chain unless the chain reply is
1220 * 4 byte aligned. JRA.
1221 */
1222
1223 outsize = (outsize + 3) & ~3;
1224
1225 /* we need to tell the client where the next part of the reply will be */
1226 SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf));
1227 SCVAL(outbuf,smb_vwv0,smb_com2);
1228
1229 if (outsize <= smb_wct) {
1230 exit_server_cleanly("Bad chained packet");
1231 return -1;
1232 }
1233
1234 /* remember how much the caller added to the chain, only counting stuff
1235 after the parameter words */
1236 chain_size += outsize - smb_wct;
1237
1238 /* work out pointers into the original packets. The
1239 headers on these need to be filled in */
1240 inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct;
1241 outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct;
1242
1243 /* remember the original command type */
1244 smb_com1 = CVAL(orig_inbuf,smb_com);
1245
1246 /* save the data which will be overwritten by the new headers */
1247 memcpy(inbuf_saved,inbuf2,smb_wct);
1248 memcpy(outbuf_saved,outbuf2,smb_wct);
1249
1250 /* give the new packet the same header as the last part of the SMB */
1251 memmove(inbuf2,inbuf,smb_wct);
1252
1253 /* create the in buffer */
1254 SCVAL(inbuf2,smb_com,smb_com2);
1255
1256 /* work out the new size for the in buffer. */
1257 new_size = size - (inbuf2 - inbuf);
1258 if (new_size < 0) {
1259 DEBUG(0,("chain_reply: chain packet size incorrect (orig size = %d, "
1260 "offset = %d)\n",
1261 size,
1262 (inbuf2 - inbuf) ));
1263 exit_server_cleanly("Bad chained packet");
1264 return(-1);
1265 }
1266
1267 /* And set it in the header. */
1268 smb_setlen(inbuf2, new_size);
1269
1270 /* create the out buffer */
1271 construct_reply_common(inbuf2, outbuf2);
1272
1273 DEBUG(3,("Chained message\n"));
1274 show_msg(inbuf2);
1275
1276 /* process the request */
1277 outsize2 = switch_message(smb_com2,inbuf2,outbuf2,new_size,
1278 bufsize-chain_size);
1279
1280 /* copy the new reply and request headers over the old ones, but
1281 preserve the smb_com field */
1282 memmove(orig_outbuf,outbuf2,smb_wct);
1283 SCVAL(orig_outbuf,smb_com,smb_com1);
1284
1285 /* restore the saved data, being careful not to overwrite any
1286 data from the reply header */
1287 memcpy(inbuf2,inbuf_saved,smb_wct);
1288
1289 {
1290 int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf);
1291 if (ofs < 0) {
1292 ofs = 0;
1293 }
1294 memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs);
1295 }
1296
1297 return outsize2;
1298}
1299
1300/****************************************************************************
1301 Setup the needed select timeout in milliseconds.
1302****************************************************************************/
1303
1304static int setup_select_timeout(void)
1305{
1306 int select_timeout;
1307
1308 select_timeout = blocking_locks_timeout_ms(SMBD_SELECT_TIMEOUT*1000);
1309
1310 if (print_notify_messages_pending()) {
1311 select_timeout = MIN(select_timeout, 1000);
1312 }
1313
1314 return select_timeout;
1315}
1316
1317/****************************************************************************
1318 Check if services need reloading.
1319****************************************************************************/
1320
1321void check_reload(time_t t)
1322{
1323 static pid_t mypid = 0;
1324 static time_t last_smb_conf_reload_time = 0;
1325 static time_t last_printer_reload_time = 0;
1326 time_t printcap_cache_time = (time_t)lp_printcap_cache_time();
1327
1328 if(last_smb_conf_reload_time == 0) {
1329 last_smb_conf_reload_time = t;
1330 /* Our printing subsystem might not be ready at smbd start up.
1331 Then no printer is available till the first printers check
1332 is performed. A lower initial interval circumvents this. */
1333 if ( printcap_cache_time > 60 )
1334 last_printer_reload_time = t - printcap_cache_time + 60;
1335 else
1336 last_printer_reload_time = t;
1337 }
1338
1339 if (mypid != getpid()) { /* First time or fork happened meanwhile */
1340 /* randomize over 60 second the printcap reload to avoid all
1341 * process hitting cupsd at the same time */
1342 int time_range = 60;
1343
1344 last_printer_reload_time += random() % time_range;
1345 mypid = getpid();
1346 }
1347
1348 if (reload_after_sighup || (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK)) {
1349 reload_services(True);
1350 reload_after_sighup = False;
1351 last_smb_conf_reload_time = t;
1352 }
1353
1354 /* 'printcap cache time = 0' disable the feature */
1355
1356 if ( printcap_cache_time != 0 )
1357 {
1358 /* see if it's time to reload or if the clock has been set back */
1359
1360 if ( (t >= last_printer_reload_time+printcap_cache_time)
1361 || (t-last_printer_reload_time < 0) )
1362 {
1363 DEBUG( 3,( "Printcap cache time expired.\n"));
1364 reload_printers();
1365 last_printer_reload_time = t;
1366 }
1367 }
1368}
1369
1370/****************************************************************************
1371 Process any timeout housekeeping. Return False if the caller should exit.
1372****************************************************************************/
1373
1374static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_timeout_processing_time)
1375{
1376 static time_t last_keepalive_sent_time = 0;
1377 static time_t last_idle_closed_check = 0;
1378 time_t t;
1379 BOOL allidle = True;
1380
1381 if (smb_read_error == READ_EOF) {
1382 DEBUG(3,("timeout_processing: End of file from client (client has disconnected).\n"));
1383 return False;
1384 }
1385
1386 if (smb_read_error == READ_ERROR) {
1387 DEBUG(3,("timeout_processing: receive_smb error (%s) Exiting\n",
1388 strerror(errno)));
1389 return False;
1390 }
1391
1392 if (smb_read_error == READ_BAD_SIG) {
1393 DEBUG(3,("timeout_processing: receive_smb error bad smb signature. Exiting\n"));
1394 return False;
1395 }
1396
1397 *last_timeout_processing_time = t = time(NULL);
1398
1399 if(last_keepalive_sent_time == 0)
1400 last_keepalive_sent_time = t;
1401
1402 if(last_idle_closed_check == 0)
1403 last_idle_closed_check = t;
1404
1405 /* become root again if waiting */
1406 change_to_root_user();
1407
1408 /* run all registered idle events */
1409 smb_run_idle_events(t);
1410
1411 /* check if we need to reload services */
1412 check_reload(t);
1413
1414 /* automatic timeout if all connections are closed */
1415 if (conn_num_open()==0 && (t - last_idle_closed_check) >= IDLE_CLOSED_TIMEOUT) {
1416 DEBUG( 2, ( "Closing idle connection\n" ) );
1417 return False;
1418 } else {
1419 last_idle_closed_check = t;
1420 }
1421
1422 if (keepalive && (t - last_keepalive_sent_time)>keepalive) {
1423 if (!send_keepalive(smbd_server_fd())) {
1424 DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
1425 return False;
1426 }
1427
1428 /* send a keepalive for a password server or the like.
1429 This is attached to the auth_info created in the
1430 negprot */
1431 if (negprot_global_auth_context && negprot_global_auth_context->challenge_set_method
1432 && negprot_global_auth_context->challenge_set_method->send_keepalive) {
1433
1434 negprot_global_auth_context->challenge_set_method->send_keepalive
1435 (&negprot_global_auth_context->challenge_set_method->private_data);
1436 }
1437
1438 last_keepalive_sent_time = t;
1439 }
1440
1441 /* check for connection timeouts */
1442 allidle = conn_idle_all(t, deadtime);
1443
1444 if (allidle && conn_num_open()>0) {
1445 DEBUG(2,("Closing idle connection 2.\n"));
1446 return False;
1447 }
1448
1449 if(global_machine_password_needs_changing &&
1450 /* for ADS we need to do a regular ADS password change, not a domain
1451 password change */
1452 lp_security() == SEC_DOMAIN) {
1453
1454 unsigned char trust_passwd_hash[16];
1455 time_t lct;
1456
1457 /*
1458 * We're in domain level security, and the code that
1459 * read the machine password flagged that the machine
1460 * password needs changing.
1461 */
1462
1463 /*
1464 * First, open the machine password file with an exclusive lock.
1465 */
1466
1467 if (secrets_lock_trust_account_password(lp_workgroup(), True) == False) {
1468 DEBUG(0,("process: unable to lock the machine account password for \
1469machine %s in domain %s.\n", global_myname(), lp_workgroup() ));
1470 return True;
1471 }
1472
1473 if(!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd_hash, &lct, NULL)) {
1474 DEBUG(0,("process: unable to read the machine account password for \
1475machine %s in domain %s.\n", global_myname(), lp_workgroup()));
1476 secrets_lock_trust_account_password(lp_workgroup(), False);
1477 return True;
1478 }
1479
1480 /*
1481 * Make sure someone else hasn't already done this.
1482 */
1483
1484 if(t < lct + lp_machine_password_timeout()) {
1485 global_machine_password_needs_changing = False;
1486 secrets_lock_trust_account_password(lp_workgroup(), False);
1487 return True;
1488 }
1489
1490 /* always just contact the PDC here */
1491
1492 change_trust_account_password( lp_workgroup(), NULL);
1493 global_machine_password_needs_changing = False;
1494 secrets_lock_trust_account_password(lp_workgroup(), False);
1495 }
1496
1497 /*
1498 * Check to see if we have any blocking locks
1499 * outstanding on the queue.
1500 */
1501 process_blocking_lock_queue();
1502
1503 /* update printer queue caches if necessary */
1504
1505 update_monitored_printq_cache();
1506
1507 /*
1508 * Now we are root, check if the log files need pruning.
1509 * Force a log file check.
1510 */
1511 force_check_log_size();
1512 check_log_size();
1513
1514 /* Send any queued printer notify message to interested smbd's. */
1515
1516 print_notify_send_messages(0);
1517
1518 /*
1519 * Modify the select timeout depending upon
1520 * what we have remaining in our queues.
1521 */
1522
1523 *select_timeout = setup_select_timeout();
1524
1525 return True;
1526}
1527
1528/****************************************************************************
1529 Accessor functions for InBuffer, OutBuffer.
1530****************************************************************************/
1531
1532char *get_InBuffer(void)
1533{
1534 return InBuffer;
1535}
1536
1537char *get_OutBuffer(void)
1538{
1539 return OutBuffer;
1540}
1541
1542const int total_buffer_size = (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN);
1543
1544/****************************************************************************
1545 Allocate a new InBuffer. Returns the new and old ones.
1546****************************************************************************/
1547
1548static char *NewInBuffer(char **old_inbuf)
1549{
1550 char *new_inbuf = (char *)SMB_MALLOC(total_buffer_size);
1551 if (!new_inbuf) {
1552 return NULL;
1553 }
1554 if (old_inbuf) {
1555 *old_inbuf = InBuffer;
1556 }
1557 InBuffer = new_inbuf;
1558#if defined(DEVELOPER)
1559 clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size);
1560#endif
1561 return InBuffer;
1562}
1563
1564/****************************************************************************
1565 Allocate a new OutBuffer. Returns the new and old ones.
1566****************************************************************************/
1567
1568static char *NewOutBuffer(char **old_outbuf)
1569{
1570 char *new_outbuf = (char *)SMB_MALLOC(total_buffer_size);
1571 if (!new_outbuf) {
1572 return NULL;
1573 }
1574 if (old_outbuf) {
1575 *old_outbuf = OutBuffer;
1576 }
1577 OutBuffer = new_outbuf;
1578#if defined(DEVELOPER)
1579 clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer, total_buffer_size);
1580#endif
1581 return OutBuffer;
1582}
1583
1584/****************************************************************************
1585 Process commands from the client
1586****************************************************************************/
1587
1588void smbd_process(void)
1589{
1590 time_t last_timeout_processing_time = time(NULL);
1591 unsigned int num_smbs = 0;
1592
1593 /* Allocate the primary Inbut/Output buffers. */
1594
1595 if ((NewInBuffer(NULL) == NULL) || (NewOutBuffer(NULL) == NULL))
1596 return;
1597
1598 max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
1599
1600 while (True) {
1601 int deadtime = lp_deadtime()*60;
1602 int select_timeout = setup_select_timeout();
1603 int num_echos;
1604
1605 if (deadtime <= 0)
1606 deadtime = DEFAULT_SMBD_TIMEOUT;
1607
1608 errno = 0;
1609
1610 /* free up temporary memory */
1611 lp_TALLOC_FREE();
1612 main_loop_TALLOC_FREE();
1613
1614 /* Did someone ask for immediate checks on things like blocking locks ? */
1615 if (select_timeout == 0) {
1616 if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1617 return;
1618 num_smbs = 0; /* Reset smb counter. */
1619 }
1620
1621 run_events(smbd_event_context(), 0, NULL, NULL);
1622
1623#if defined(DEVELOPER)
1624 clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size);
1625#endif
1626
1627 while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,select_timeout)) {
1628 if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1629 return;
1630 num_smbs = 0; /* Reset smb counter. */
1631 }
1632
1633 /*
1634 * Ensure we do timeout processing if the SMB we just got was
1635 * only an echo request. This allows us to set the select
1636 * timeout in 'receive_message_or_smb()' to any value we like
1637 * without worrying that the client will send echo requests
1638 * faster than the select timeout, thus starving out the
1639 * essential processing (change notify, blocking locks) that
1640 * the timeout code does. JRA.
1641 */
1642 num_echos = smb_echo_count;
1643
1644 clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer, total_buffer_size);
1645
1646 process_smb(InBuffer, OutBuffer);
1647
1648 if (smb_echo_count != num_echos) {
1649 if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1650 return;
1651 num_smbs = 0; /* Reset smb counter. */
1652 }
1653
1654 num_smbs++;
1655
1656 /*
1657 * If we are getting smb requests in a constant stream
1658 * with no echos, make sure we attempt timeout processing
1659 * every select_timeout milliseconds - but only check for this
1660 * every 200 smb requests.
1661 */
1662
1663 if ((num_smbs % 200) == 0) {
1664 time_t new_check_time = time(NULL);
1665 if(new_check_time - last_timeout_processing_time >= (select_timeout/1000)) {
1666 if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1667 return;
1668 num_smbs = 0; /* Reset smb counter. */
1669 last_timeout_processing_time = new_check_time; /* Reset time. */
1670 }
1671 }
1672
1673 /* The timeout_processing function isn't run nearly
1674 often enough to implement 'max log size' without
1675 overrunning the size of the file by many megabytes.
1676 This is especially true if we are running at debug
1677 level 10. Checking every 50 SMBs is a nice
1678 tradeoff of performance vs log file size overrun. */
1679
1680 if ((num_smbs % 50) == 0 && need_to_check_log_size()) {
1681 change_to_root_user();
1682 check_log_size();
1683 }
1684 }
1685}
Note: See TracBrowser for help on using the repository browser.