Reformatting only before real change.
[abartlet/samba.git/.git] / source3 / smbd / process.c
1 /* 
2    Unix SMB/CIFS implementation.
3    process incoming packets - main loop
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 struct timeval smb_last_time;
24
25 static char *InBuffer = NULL;
26 char *OutBuffer = NULL;
27 char *last_inbuf = NULL;
28
29 /* 
30  * Size of data we can send to client. Set
31  *  by the client for all protocols above CORE.
32  *  Set by us for CORE protocol.
33  */
34 int max_send = BUFFER_SIZE;
35 /*
36  * Size of the data we can receive. Set by us.
37  * Can be modified by the max xmit parameter.
38  */
39 int max_recv = BUFFER_SIZE;
40
41 extern int last_message;
42 extern int global_oplock_break;
43 extern userdom_struct current_user_info;
44 extern int smb_read_error;
45 SIG_ATOMIC_T reload_after_sighup = 0;
46 SIG_ATOMIC_T got_sig_term = 0;
47 extern BOOL global_machine_password_needs_changing;
48 extern fstring global_myworkgroup;
49 extern pstring global_myname;
50 extern int max_send;
51
52 /****************************************************************************
53  structure to hold a linked list of queued messages.
54  for processing.
55 ****************************************************************************/
56
57 typedef struct {
58    ubi_slNode msg_next;
59    char *msg_buf;
60    int msg_len;
61 } pending_message_list;
62
63 static ubi_slList smb_oplock_queue = { NULL, (ubi_slNodePtr)&smb_oplock_queue, 0};
64
65 /****************************************************************************
66  Function to push a message onto the tail of a linked list of smb messages ready
67  for processing.
68 ****************************************************************************/
69
70 static BOOL push_message(ubi_slList *list_head, char *buf, int msg_len)
71 {
72   pending_message_list *msg = (pending_message_list *)
73                                malloc(sizeof(pending_message_list));
74
75   if(msg == NULL)
76   {
77     DEBUG(0,("push_message: malloc fail (1)\n"));
78     return False;
79   }
80
81   msg->msg_buf = (char *)malloc(msg_len);
82   if(msg->msg_buf == NULL)
83   {
84     DEBUG(0,("push_message: malloc fail (2)\n"));
85     SAFE_FREE(msg);
86     return False;
87   }
88
89   memcpy(msg->msg_buf, buf, msg_len);
90   msg->msg_len = msg_len;
91
92   ubi_slAddTail( list_head, msg);
93
94   return True;
95 }
96
97 /****************************************************************************
98  Function to push a smb message onto a linked list of local smb messages ready
99  for processing.
100 ****************************************************************************/
101
102 BOOL push_oplock_pending_smb_message(char *buf, int msg_len)
103 {
104         return push_message(&smb_oplock_queue, buf, msg_len);
105 }
106
107 /****************************************************************************
108  Do all async processing in here. This includes UDB oplock messages, kernel
109  oplock messages, change notify events etc.
110 ****************************************************************************/
111
112 static void async_processing(char *buffer, int buffer_len)
113 {
114         DEBUG(10,("async_processing: Doing async processing.\n"));
115
116         /* check for oplock messages (both UDP and kernel) */
117         if (receive_local_message(buffer, buffer_len, 1)) {
118                 process_local_message(buffer, buffer_len);
119         }
120
121         if (got_sig_term) {
122                 exit_server("Caught TERM signal");
123         }
124
125         /* check for async change notify events */
126         process_pending_change_notify_queue(0);
127
128         /* check for sighup processing */
129         if (reload_after_sighup) {
130                 change_to_root_user();
131                 DEBUG(1,("Reloading services after SIGHUP\n"));
132                 reload_services(False);
133                 reload_after_sighup = 0;
134         }
135 }
136
137 /****************************************************************************
138   Do a select on an two fd's - with timeout. 
139
140   If a local udp message has been pushed onto the
141   queue (this can only happen during oplock break
142   processing) call async_processing()
143
144   If a pending smb message has been pushed onto the
145   queue (this can only happen during oplock break
146   processing) return this next.
147
148   If the first smbfd is ready then read an smb from it.
149   if the second (loopback UDP) fd is ready then read a message
150   from it and setup the buffer header to identify the length
151   and from address.
152   Returns False on timeout or error.
153   Else returns True.
154
155 The timeout is in milliseconds
156 ****************************************************************************/
157
158 static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
159 {
160         fd_set fds;
161         int selrtn;
162         struct timeval to;
163         int maxfd;
164
165         smb_read_error = 0;
166
167  again:
168
169         /*
170          * Note that this call must be before processing any SMB
171          * messages as we need to synchronously process any messages
172          * we may have sent to ourselves from the previous SMB.
173          */
174         message_dispatch();
175
176         /*
177          * Check to see if we already have a message on the smb queue.
178          * If so - copy and return it.
179          */
180         if(ubi_slCount(&smb_oplock_queue) != 0) {
181                 pending_message_list *msg = (pending_message_list *)ubi_slRemHead(&smb_oplock_queue);
182                 memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
183   
184                 /* Free the message we just copied. */
185                 SAFE_FREE(msg->msg_buf);
186                 SAFE_FREE(msg);
187                 
188                 DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
189                 return True;
190         }
191
192
193         /*
194          * Setup the select read fd set.
195          */
196
197         FD_ZERO(&fds);
198
199         /*
200          * Ensure we process oplock break messages by preference.
201          * We have to do this before the select, after the select
202          * and if the select returns EINTR. This is due to the fact
203          * that the selects called from async_processing can eat an EINTR
204          * caused by a signal (we can't take the break message there).
205          * This is hideously complex - *MUST* be simplified for 3.0 ! JRA.
206          */
207
208         if (oplock_message_waiting(&fds)) {
209                 DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
210                 async_processing(buffer, buffer_len);
211                 /*
212                  * After async processing we must go and do the select again, as
213                  * the state of the flag in fds for the server file descriptor is
214                  * indeterminate - we may have done I/O on it in the oplock processing. JRA.
215                  */
216                 goto again;
217         }
218         
219         FD_SET(smbd_server_fd(),&fds);
220         maxfd = setup_oplock_select_set(&fds);
221
222         to.tv_sec = timeout / 1000;
223         to.tv_usec = (timeout % 1000) * 1000;
224
225         selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,timeout>0?&to:NULL);
226
227         /* if we get EINTR then maybe we have received an oplock
228            signal - treat this as select returning 1. This is ugly, but
229            is the best we can do until the oplock code knows more about
230            signals */
231         if (selrtn == -1 && errno == EINTR) {
232                 async_processing(buffer, buffer_len);
233                 /*
234                  * After async processing we must go and do the select again, as
235                  * the state of the flag in fds for the server file descriptor is
236                  * indeterminate - we may have done I/O on it in the oplock processing. JRA.
237                  */
238                 goto again;
239         }
240
241         /* Check if error */
242         if (selrtn == -1) {
243                 /* something is wrong. Maybe the socket is dead? */
244                 smb_read_error = READ_ERROR;
245                 return False;
246         } 
247     
248         /* Did we timeout ? */
249         if (selrtn == 0) {
250                 smb_read_error = READ_TIMEOUT;
251                 return False;
252         }
253
254         /*
255          * Ensure we process oplock break messages by preference.
256          * This is IMPORTANT ! Otherwise we can starve other processes
257          * sending us an oplock break message. JRA.
258          */
259
260         if (oplock_message_waiting(&fds)) {
261                 async_processing(buffer, buffer_len);
262                 /*
263                  * After async processing we must go and do the select again, as
264                  * the state of the flag in fds for the server file descriptor is
265                  * indeterminate - we may have done I/O on it in the oplock processing. JRA.
266                  */
267                 goto again;
268         }
269         
270         return receive_smb(smbd_server_fd(), buffer, 0);
271 }
272
273 /****************************************************************************
274 Get the next SMB packet, doing the local message processing automatically.
275 ****************************************************************************/
276
277 BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
278 {
279         BOOL got_keepalive;
280         BOOL ret;
281
282         do {
283                 ret = receive_message_or_smb(inbuf,bufsize,timeout);
284                 
285                 got_keepalive = (ret && (CVAL(inbuf,0) == SMBkeepalive));
286         } while (ret && got_keepalive);
287
288         return ret;
289 }
290
291 /****************************************************************************
292  We're terminating and have closed all our files/connections etc.
293  If there are any pending local messages we need to respond to them
294  before termination so that other smbds don't think we just died whilst
295  holding oplocks.
296 ****************************************************************************/
297
298 void respond_to_all_remaining_local_messages(void)
299 {
300   char buffer[1024];
301
302   /*
303    * Assert we have no exclusive open oplocks.
304    */
305
306   if(get_number_of_exclusive_open_oplocks()) {
307     DEBUG(0,("respond_to_all_remaining_local_messages: PANIC : we have %d exclusive oplocks.\n",
308           get_number_of_exclusive_open_oplocks() ));
309     return;
310   }
311
312   /*
313    * Keep doing receive_local_message with a 1 ms timeout until
314    * we have no more messages.
315    */
316   while(receive_local_message(buffer, sizeof(buffer), 1)) {
317           /* Deal with oplock break requests from other smbd's. */
318           process_local_message(buffer, sizeof(buffer));
319   }
320
321   return;
322 }
323
324
325 /*
326 These flags determine some of the permissions required to do an operation 
327
328 Note that I don't set NEED_WRITE on some write operations because they
329 are used by some brain-dead clients when printing, and I don't want to
330 force write permissions on print services.
331 */
332 #define AS_USER (1<<0)
333 #define NEED_WRITE (1<<1)
334 #define TIME_INIT (1<<2)
335 #define CAN_IPC (1<<3)
336 #define AS_GUEST (1<<5)
337 #define QUEUE_IN_OPLOCK (1<<6)
338
339 /* 
340    define a list of possible SMB messages and their corresponding
341    functions. Any message that has a NULL function is unimplemented -
342    please feel free to contribute implementations!
343 */
344 const static struct smb_message_struct
345 {
346   const char *name;
347   int (*fn)(connection_struct *conn, char *, char *, int, int);
348   int flags;
349 }
350  smb_messages[256] = {
351
352 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
353 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
354 /* 0x02 */ { "SMBopen",reply_open,AS_USER | QUEUE_IN_OPLOCK },
355 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
356 /* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
357 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
358 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
359 /* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
360 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
361 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
362 /* 0x0a */ { "SMBread",reply_read,AS_USER},
363 /* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
364 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
365 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
366 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER | QUEUE_IN_OPLOCK },
367 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER}, 
368 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
369 /* 0x11 */ { "SMBexit",reply_exit,0},
370 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
371 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
372 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
373 /* 0x15 */ { NULL, NULL, 0 },
374 /* 0x16 */ { NULL, NULL, 0 },
375 /* 0x17 */ { NULL, NULL, 0 },
376 /* 0x18 */ { NULL, NULL, 0 },
377 /* 0x19 */ { NULL, NULL, 0 },
378 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
379 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
380 /* 0x1c */ { "SMBreadBs",NULL,0 },
381 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
382 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
383 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
384 /* 0x20 */ { "SMBwritec",NULL,0},
385 /* 0x21 */ { NULL, NULL, 0 },
386 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
387 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
388 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
389 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
390 /* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
391 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
392 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
393 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
394 /* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
395 /* 0x2b */ { "SMBecho",reply_echo,0},
396 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
397 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
398 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
399 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
400 /* 0x30 */ { NULL, NULL, 0 },
401 /* 0x31 */ { NULL, NULL, 0 },
402 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
403 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
404 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
405 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
406 /* 0x36 */ { NULL, NULL, 0 },
407 /* 0x37 */ { NULL, NULL, 0 },
408 /* 0x38 */ { NULL, NULL, 0 },
409 /* 0x39 */ { NULL, NULL, 0 },
410 /* 0x3a */ { NULL, NULL, 0 },
411 /* 0x3b */ { NULL, NULL, 0 },
412 /* 0x3c */ { NULL, NULL, 0 },
413 /* 0x3d */ { NULL, NULL, 0 },
414 /* 0x3e */ { NULL, NULL, 0 },
415 /* 0x3f */ { NULL, NULL, 0 },
416 /* 0x40 */ { NULL, NULL, 0 },
417 /* 0x41 */ { NULL, NULL, 0 },
418 /* 0x42 */ { NULL, NULL, 0 },
419 /* 0x43 */ { NULL, NULL, 0 },
420 /* 0x44 */ { NULL, NULL, 0 },
421 /* 0x45 */ { NULL, NULL, 0 },
422 /* 0x46 */ { NULL, NULL, 0 },
423 /* 0x47 */ { NULL, NULL, 0 },
424 /* 0x48 */ { NULL, NULL, 0 },
425 /* 0x49 */ { NULL, NULL, 0 },
426 /* 0x4a */ { NULL, NULL, 0 },
427 /* 0x4b */ { NULL, NULL, 0 },
428 /* 0x4c */ { NULL, NULL, 0 },
429 /* 0x4d */ { NULL, NULL, 0 },
430 /* 0x4e */ { NULL, NULL, 0 },
431 /* 0x4f */ { NULL, NULL, 0 },
432 /* 0x50 */ { NULL, NULL, 0 },
433 /* 0x51 */ { NULL, NULL, 0 },
434 /* 0x52 */ { NULL, NULL, 0 },
435 /* 0x53 */ { NULL, NULL, 0 },
436 /* 0x54 */ { NULL, NULL, 0 },
437 /* 0x55 */ { NULL, NULL, 0 },
438 /* 0x56 */ { NULL, NULL, 0 },
439 /* 0x57 */ { NULL, NULL, 0 },
440 /* 0x58 */ { NULL, NULL, 0 },
441 /* 0x59 */ { NULL, NULL, 0 },
442 /* 0x5a */ { NULL, NULL, 0 },
443 /* 0x5b */ { NULL, NULL, 0 },
444 /* 0x5c */ { NULL, NULL, 0 },
445 /* 0x5d */ { NULL, NULL, 0 },
446 /* 0x5e */ { NULL, NULL, 0 },
447 /* 0x5f */ { NULL, NULL, 0 },
448 /* 0x60 */ { NULL, NULL, 0 },
449 /* 0x61 */ { NULL, NULL, 0 },
450 /* 0x62 */ { NULL, NULL, 0 },
451 /* 0x63 */ { NULL, NULL, 0 },
452 /* 0x64 */ { NULL, NULL, 0 },
453 /* 0x65 */ { NULL, NULL, 0 },
454 /* 0x66 */ { NULL, NULL, 0 },
455 /* 0x67 */ { NULL, NULL, 0 },
456 /* 0x68 */ { NULL, NULL, 0 },
457 /* 0x69 */ { NULL, NULL, 0 },
458 /* 0x6a */ { NULL, NULL, 0 },
459 /* 0x6b */ { NULL, NULL, 0 },
460 /* 0x6c */ { NULL, NULL, 0 },
461 /* 0x6d */ { NULL, NULL, 0 },
462 /* 0x6e */ { NULL, NULL, 0 },
463 /* 0x6f */ { NULL, NULL, 0 },
464 /* 0x70 */ { "SMBtcon",reply_tcon,0},
465 /* 0x71 */ { "SMBtdis",reply_tdis,0},
466 /* 0x72 */ { "SMBnegprot",reply_negprot,0},
467 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0},
468 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
469 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
470 /* 0x76 */ { NULL, NULL, 0 },
471 /* 0x77 */ { NULL, NULL, 0 },
472 /* 0x78 */ { NULL, NULL, 0 },
473 /* 0x79 */ { NULL, NULL, 0 },
474 /* 0x7a */ { NULL, NULL, 0 },
475 /* 0x7b */ { NULL, NULL, 0 },
476 /* 0x7c */ { NULL, NULL, 0 },
477 /* 0x7d */ { NULL, NULL, 0 },
478 /* 0x7e */ { NULL, NULL, 0 },
479 /* 0x7f */ { NULL, NULL, 0 },
480 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
481 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
482 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
483 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
484 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
485 /* 0x85 */ { NULL, NULL, 0 },
486 /* 0x86 */ { NULL, NULL, 0 },
487 /* 0x87 */ { NULL, NULL, 0 },
488 /* 0x88 */ { NULL, NULL, 0 },
489 /* 0x89 */ { NULL, NULL, 0 },
490 /* 0x8a */ { NULL, NULL, 0 },
491 /* 0x8b */ { NULL, NULL, 0 },
492 /* 0x8c */ { NULL, NULL, 0 },
493 /* 0x8d */ { NULL, NULL, 0 },
494 /* 0x8e */ { NULL, NULL, 0 },
495 /* 0x8f */ { NULL, NULL, 0 },
496 /* 0x90 */ { NULL, NULL, 0 },
497 /* 0x91 */ { NULL, NULL, 0 },
498 /* 0x92 */ { NULL, NULL, 0 },
499 /* 0x93 */ { NULL, NULL, 0 },
500 /* 0x94 */ { NULL, NULL, 0 },
501 /* 0x95 */ { NULL, NULL, 0 },
502 /* 0x96 */ { NULL, NULL, 0 },
503 /* 0x97 */ { NULL, NULL, 0 },
504 /* 0x98 */ { NULL, NULL, 0 },
505 /* 0x99 */ { NULL, NULL, 0 },
506 /* 0x9a */ { NULL, NULL, 0 },
507 /* 0x9b */ { NULL, NULL, 0 },
508 /* 0x9c */ { NULL, NULL, 0 },
509 /* 0x9d */ { NULL, NULL, 0 },
510 /* 0x9e */ { NULL, NULL, 0 },
511 /* 0x9f */ { NULL, NULL, 0 },
512 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK},
513 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
514 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
515 /* 0xa3 */ { NULL, NULL, 0 },
516 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
517 /* 0xa5 */ { NULL, NULL, 0 },
518 /* 0xa6 */ { NULL, NULL, 0 },
519 /* 0xa7 */ { NULL, NULL, 0 },
520 /* 0xa8 */ { NULL, NULL, 0 },
521 /* 0xa9 */ { NULL, NULL, 0 },
522 /* 0xaa */ { NULL, NULL, 0 },
523 /* 0xab */ { NULL, NULL, 0 },
524 /* 0xac */ { NULL, NULL, 0 },
525 /* 0xad */ { NULL, NULL, 0 },
526 /* 0xae */ { NULL, NULL, 0 },
527 /* 0xaf */ { NULL, NULL, 0 },
528 /* 0xb0 */ { NULL, NULL, 0 },
529 /* 0xb1 */ { NULL, NULL, 0 },
530 /* 0xb2 */ { NULL, NULL, 0 },
531 /* 0xb3 */ { NULL, NULL, 0 },
532 /* 0xb4 */ { NULL, NULL, 0 },
533 /* 0xb5 */ { NULL, NULL, 0 },
534 /* 0xb6 */ { NULL, NULL, 0 },
535 /* 0xb7 */ { NULL, NULL, 0 },
536 /* 0xb8 */ { NULL, NULL, 0 },
537 /* 0xb9 */ { NULL, NULL, 0 },
538 /* 0xba */ { NULL, NULL, 0 },
539 /* 0xbb */ { NULL, NULL, 0 },
540 /* 0xbc */ { NULL, NULL, 0 },
541 /* 0xbd */ { NULL, NULL, 0 },
542 /* 0xbe */ { NULL, NULL, 0 },
543 /* 0xbf */ { NULL, NULL, 0 },
544 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER | QUEUE_IN_OPLOCK },
545 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
546 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
547 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
548 /* 0xc4 */ { NULL, NULL, 0 },
549 /* 0xc5 */ { NULL, NULL, 0 },
550 /* 0xc6 */ { NULL, NULL, 0 },
551 /* 0xc7 */ { NULL, NULL, 0 },
552 /* 0xc8 */ { NULL, NULL, 0 },
553 /* 0xc9 */ { NULL, NULL, 0 },
554 /* 0xca */ { NULL, NULL, 0 },
555 /* 0xcb */ { NULL, NULL, 0 },
556 /* 0xcc */ { NULL, NULL, 0 },
557 /* 0xcd */ { NULL, NULL, 0 },
558 /* 0xce */ { NULL, NULL, 0 },
559 /* 0xcf */ { NULL, NULL, 0 },
560 /* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
561 /* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
562 /* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
563 /* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
564 /* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
565 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
566 /* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
567 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
568 /* 0xd8 */ { NULL, NULL, 0 },
569 /* 0xd9 */ { NULL, NULL, 0 },
570 /* 0xda */ { NULL, NULL, 0 },
571 /* 0xdb */ { NULL, NULL, 0 },
572 /* 0xdc */ { NULL, NULL, 0 },
573 /* 0xdd */ { NULL, NULL, 0 },
574 /* 0xde */ { NULL, NULL, 0 },
575 /* 0xdf */ { NULL, NULL, 0 },
576 /* 0xe0 */ { NULL, NULL, 0 },
577 /* 0xe1 */ { NULL, NULL, 0 },
578 /* 0xe2 */ { NULL, NULL, 0 },
579 /* 0xe3 */ { NULL, NULL, 0 },
580 /* 0xe4 */ { NULL, NULL, 0 },
581 /* 0xe5 */ { NULL, NULL, 0 },
582 /* 0xe6 */ { NULL, NULL, 0 },
583 /* 0xe7 */ { NULL, NULL, 0 },
584 /* 0xe8 */ { NULL, NULL, 0 },
585 /* 0xe9 */ { NULL, NULL, 0 },
586 /* 0xea */ { NULL, NULL, 0 },
587 /* 0xeb */ { NULL, NULL, 0 },
588 /* 0xec */ { NULL, NULL, 0 },
589 /* 0xed */ { NULL, NULL, 0 },
590 /* 0xee */ { NULL, NULL, 0 },
591 /* 0xef */ { NULL, NULL, 0 },
592 /* 0xf0 */ { NULL, NULL, 0 },
593 /* 0xf1 */ { NULL, NULL, 0 },
594 /* 0xf2 */ { NULL, NULL, 0 },
595 /* 0xf3 */ { NULL, NULL, 0 },
596 /* 0xf4 */ { NULL, NULL, 0 },
597 /* 0xf5 */ { NULL, NULL, 0 },
598 /* 0xf6 */ { NULL, NULL, 0 },
599 /* 0xf7 */ { NULL, NULL, 0 },
600 /* 0xf8 */ { NULL, NULL, 0 },
601 /* 0xf9 */ { NULL, NULL, 0 },
602 /* 0xfa */ { NULL, NULL, 0 },
603 /* 0xfb */ { NULL, NULL, 0 },
604 /* 0xfc */ { NULL, NULL, 0 },
605 /* 0xfd */ { NULL, NULL, 0 },
606 /* 0xfe */ { NULL, NULL, 0 },
607 /* 0xff */ { NULL, NULL, 0 }
608
609 };
610
611 /*******************************************************************
612  Dump a packet to a file.
613 ********************************************************************/
614
615 static void smb_dump(const char *name, int type, char *data, ssize_t len)
616 {
617         int fd, i;
618         pstring fname;
619         if (DEBUGLEVEL < 50) return;
620
621         if (len < 4) len = smb_len(data)+4;
622         for (i=1;i<100;i++) {
623                 slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.%s", name, i,
624                                 type ? "req" : "resp");
625                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
626                 if (fd != -1 || errno != EEXIST) break;
627         }
628         if (fd != -1) {
629                 ssize_t ret = write(fd, data, len);
630                 if (ret != len)
631                         DEBUG(0,("smb_dump: problem: write returned %d\n", (int)ret ));
632                 close(fd);
633                 DEBUG(0,("created %s len %d\n", fname, len));
634         }
635 }
636
637
638 /****************************************************************************
639  Do a switch on the message type, and return the response size
640 ****************************************************************************/
641
642 static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize)
643 {
644         static pid_t pid= (pid_t)-1;
645         int outsize = 0;
646         extern uint16 global_smbpid;
647
648         type &= 0xff;
649
650         if (pid == (pid_t)-1)
651                 pid = sys_getpid();
652
653         errno = 0;
654         last_message = type;
655
656         /* Make sure this is an SMB packet */
657         if (strncmp(smb_base(inbuf),"\377SMB",4) != 0) {
658                 DEBUG(2,("Non-SMB packet of length %d\n",smb_len(inbuf)));
659                 return(-1);
660         }
661
662         /* yuck! this is an interim measure before we get rid of our
663                 current inbuf/outbuf system */
664         global_smbpid = SVAL(inbuf,smb_pid);
665
666         if (smb_messages[type].fn == NULL) {
667                 DEBUG(0,("Unknown message type %d!\n",type));
668                 smb_dump("Unknown", 1, inbuf, size);
669                 outsize = reply_unknown(inbuf,outbuf);
670         } else {
671                 int flags = smb_messages[type].flags;
672                 static uint16 last_session_tag = UID_FIELD_INVALID;
673                 /* In share mode security we must ignore the vuid. */
674                 uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
675                 connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
676
677                 DEBUG(3,("switch message %s (pid %d)\n",smb_fn_name(type),(int)pid));
678
679                 smb_dump(smb_fn_name(type), 1, inbuf, size);
680                 if(global_oplock_break) {
681                         if(flags & QUEUE_IN_OPLOCK) {
682                                 /* 
683                                  * Queue this message as we are the process of an oplock break.
684                                  */
685
686                                 DEBUG( 2, ( "switch_message: queueing message due to being in " ) );
687                                 DEBUGADD( 2, ( "oplock break state.\n" ) );
688
689                                 push_oplock_pending_smb_message( inbuf, size );
690                                 return -1;
691                         }
692                 }
693
694                 /* Ensure this value is replaced in the incoming packet. */
695                 SSVAL(inbuf,smb_uid,session_tag);
696
697                 /*
698                  * Ensure the correct username is in current_user_info.
699                  * This is a really ugly bugfix for problems with
700                  * multiple session_setup_and_X's being done and
701                  * allowing %U and %G substitutions to work correctly.
702                  * There is a reason this code is done here, don't
703                  * move it unless you know what you're doing... :-).
704                  * JRA.
705                  */
706
707                 if (session_tag != last_session_tag) {
708                         user_struct *vuser = NULL;
709
710                         last_session_tag = session_tag;
711                         if(session_tag != UID_FIELD_INVALID)
712                                 vuser = get_valid_user_struct(session_tag);           
713                         if(vuser != NULL)
714                                 current_user_info = vuser->user;
715                 }
716
717                 /* does this protocol need to be run as root? */
718                 if (!(flags & AS_USER))
719                         change_to_root_user();
720
721                 /* does this protocol need a valid tree connection? */
722                 if ((flags & AS_USER) && !conn)
723                         return ERROR_DOS(ERRSRV, ERRinvnid);
724
725
726                 /* does this protocol need to be run as the connected user? */
727                 if ((flags & AS_USER) && !change_to_user(conn,session_tag)) {
728                         if (flags & AS_GUEST) 
729                                 flags &= ~AS_USER;
730                         else
731                                 return(ERROR_DOS(ERRSRV,ERRaccess));
732                 }
733
734                 /* this code is to work around a bug is MS client 3 without
735                         introducing a security hole - it needs to be able to do
736                         print queue checks as guest if it isn't logged in properly */
737                 if (flags & AS_USER)
738                         flags &= ~AS_GUEST;
739
740                 /* does it need write permission? */
741                 if ((flags & NEED_WRITE) && !CAN_WRITE(conn))
742                         return(ERROR_DOS(ERRSRV,ERRaccess));
743
744                 /* ipc services are limited */
745                 if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC))
746                         return(ERROR_DOS(ERRSRV,ERRaccess));        
747
748                 /* load service specific parameters */
749                 if (conn && !set_current_service(conn,(flags & AS_USER)?True:False))
750                         return(ERROR_DOS(ERRSRV,ERRaccess));
751
752                 /* does this protocol need to be run as guest? */
753                 if ((flags & AS_GUEST) && (!change_to_guest() || 
754                                 !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1))))
755                         return(ERROR_DOS(ERRSRV,ERRaccess));
756
757                 last_inbuf = inbuf;
758
759                 outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize);
760         }
761
762         smb_dump(smb_fn_name(type), 0, outbuf, outsize);
763
764         return(outsize);
765 }
766
767
768 /****************************************************************************
769  Construct a reply to the incoming packet.
770 ****************************************************************************/
771
772 static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
773 {
774         int type = CVAL(inbuf,smb_com);
775         int outsize = 0;
776         int msg_type = CVAL(inbuf,0);
777
778         GetTimeOfDay(&smb_last_time);
779
780         chain_size = 0;
781         file_chain_reset();
782         reset_chain_p();
783
784         if (msg_type != 0)
785                 return(reply_special(inbuf,outbuf));  
786
787         construct_reply_common(inbuf, outbuf);
788
789         outsize = switch_message(type,inbuf,outbuf,size,bufsize);
790
791         outsize += chain_size;
792
793         if(outsize > 4)
794                 smb_setlen(outbuf,outsize - 4);
795         return(outsize);
796 }
797
798 /****************************************************************************
799  Keep track of the number of running smbd's. This functionality is used to
800  'hard' limit Samba overhead on resource constrained systems. 
801 ****************************************************************************/
802
803 static BOOL smbd_process_limit(void)
804 {
805         int32  total_smbds;
806         
807         if (lp_max_smbd_processes()) {
808
809                 /* Always add one to the smbd process count, as exit_server() always
810                  * subtracts one.
811                  */
812
813                 total_smbds = 1; /* In case we need to create the entry. */
814
815                 if (!conn_tdb_ctx()) {
816                         DEBUG(0,("smbd_process_limit: max smbd processes parameter set with status parameter not \
817 set. Ignoring max smbd restriction.\n"));
818                         return False;
819                 }
820
821                 if (tdb_change_int32_atomic(conn_tdb_ctx(), "INFO/total_smbds", &total_smbds, 1) == -1)
822                         return True;
823
824                 return total_smbds > lp_max_smbd_processes();
825         }
826         else
827                 return False;
828 }
829
830 /****************************************************************************
831   process an smb from the client - split out from the smbd_process() code so
832   it can be used by the oplock break code.
833 ****************************************************************************/
834 void process_smb(char *inbuf, char *outbuf)
835 {
836   static int trans_num;
837   int msg_type = CVAL(inbuf,0);
838   int32 len = smb_len(inbuf);
839   int nread = len + 4;
840
841   DO_PROFILE_INC(smb_count);
842
843   if (trans_num == 0) {
844           /* on the first packet, check the global hosts allow/ hosts
845              deny parameters before doing any parsing of the packet
846              passed to us by the client.  This prevents attacks on our
847              parsing code from hosts not in the hosts allow list */
848           if (smbd_process_limit() ||
849                   !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1))) {
850                   /* send a negative session response "not listening on calling
851                    name" */
852                   static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
853                   DEBUG( 1, ( "Connection denied from %s\n",
854                               client_addr() ) );
855                   (void)send_smb(smbd_server_fd(),(char *)buf);
856                   exit_server("connection denied");
857           }
858   }
859
860   DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type, len ) );
861   DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) );
862
863   if (msg_type == 0)
864     show_msg(inbuf);
865   else if(msg_type == SMBkeepalive)
866     return; /* Keepalive packet. */
867
868   nread = construct_reply(inbuf,outbuf,nread,max_send);
869       
870   if(nread > 0) 
871   {
872     if (CVAL(outbuf,0) == 0)
873       show_msg(outbuf);
874         
875     if (nread != smb_len(outbuf) + 4) 
876     {
877       DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
878                  nread, smb_len(outbuf)));
879     }
880     else
881       if (!send_smb(smbd_server_fd(),outbuf))
882         exit_server("process_smb: send_smb failed.");
883   }
884   trans_num++;
885 }
886
887
888
889 /****************************************************************************
890 return a string containing the function name of a SMB command
891 ****************************************************************************/
892 const char *smb_fn_name(int type)
893 {
894         static char *unknown_name = "SMBunknown";
895
896         if (smb_messages[type].name == NULL)
897                 return(unknown_name);
898
899         return(smb_messages[type].name);
900 }
901
902
903 /****************************************************************************
904  Helper function for contruct_reply.
905 ****************************************************************************/
906
907 void construct_reply_common(char *inbuf,char *outbuf)
908 {
909         memset(outbuf,'\0',smb_size);
910
911         set_message(outbuf,0,0,True);
912         SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com));
913         
914         memcpy(outbuf+4,inbuf+4,4);
915         SCVAL(outbuf,smb_rcls,SMB_SUCCESS);
916         SCVAL(outbuf,smb_reh,0);
917         SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); 
918         SSVAL(outbuf,smb_flg2,
919               (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) |
920               FLAGS2_LONG_PATH_COMPONENTS |
921               FLAGS2_32_BIT_ERROR_CODES | FLAGS2_EXTENDED_SECURITY);
922
923         SSVAL(outbuf,smb_err,SMB_SUCCESS);
924         SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
925         SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
926         SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
927         SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));
928 }
929
930 /****************************************************************************
931   construct a chained reply and add it to the already made reply
932   **************************************************************************/
933 int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
934 {
935   static char *orig_inbuf;
936   static char *orig_outbuf;
937   int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0);
938   unsigned smb_off2 = SVAL(inbuf,smb_vwv1);
939   char *inbuf2, *outbuf2;
940   int outsize2;
941   char inbuf_saved[smb_wct];
942   char outbuf_saved[smb_wct];
943   int wct = CVAL(outbuf,smb_wct);
944   int outsize = smb_size + 2*wct + SVAL(outbuf,smb_vwv0+2*wct);
945
946   /* maybe its not chained */
947   if (smb_com2 == 0xFF) {
948     SCVAL(outbuf,smb_vwv0,0xFF);
949     return outsize;
950   }
951
952   if (chain_size == 0) {
953     /* this is the first part of the chain */
954     orig_inbuf = inbuf;
955     orig_outbuf = outbuf;
956   }
957
958   /*
959    * The original Win95 redirector dies on a reply to
960    * a lockingX and read chain unless the chain reply is
961    * 4 byte aligned. JRA.
962    */
963
964   outsize = (outsize + 3) & ~3;
965
966   /* we need to tell the client where the next part of the reply will be */
967   SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf));
968   SCVAL(outbuf,smb_vwv0,smb_com2);
969
970   /* remember how much the caller added to the chain, only counting stuff
971      after the parameter words */
972   chain_size += outsize - smb_wct;
973
974   /* work out pointers into the original packets. The
975      headers on these need to be filled in */
976   inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct;
977   outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct;
978
979   /* remember the original command type */
980   smb_com1 = CVAL(orig_inbuf,smb_com);
981
982   /* save the data which will be overwritten by the new headers */
983   memcpy(inbuf_saved,inbuf2,smb_wct);
984   memcpy(outbuf_saved,outbuf2,smb_wct);
985
986   /* give the new packet the same header as the last part of the SMB */
987   memmove(inbuf2,inbuf,smb_wct);
988
989   /* create the in buffer */
990   SCVAL(inbuf2,smb_com,smb_com2);
991
992   /* create the out buffer */
993   construct_reply_common(inbuf2, outbuf2);
994
995   DEBUG(3,("Chained message\n"));
996   show_msg(inbuf2);
997
998   /* process the request */
999   outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size,
1000                             bufsize-chain_size);
1001
1002   /* copy the new reply and request headers over the old ones, but
1003      preserve the smb_com field */
1004   memmove(orig_outbuf,outbuf2,smb_wct);
1005   SCVAL(orig_outbuf,smb_com,smb_com1);
1006
1007   /* restore the saved data, being careful not to overwrite any
1008    data from the reply header */
1009   memcpy(inbuf2,inbuf_saved,smb_wct);
1010   {
1011     int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf);
1012     if (ofs < 0) ofs = 0;
1013     memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs);
1014   }
1015
1016   return outsize2;
1017 }
1018
1019 /****************************************************************************
1020  Setup the needed select timeout.
1021 ****************************************************************************/
1022
1023 static int setup_select_timeout(void)
1024 {
1025         int select_timeout;
1026         int t;
1027
1028         select_timeout = blocking_locks_timeout(SMBD_SELECT_TIMEOUT);
1029         select_timeout *= 1000;
1030
1031         t = change_notify_timeout();
1032         if (t != -1) select_timeout = MIN(select_timeout, t*1000);
1033
1034         return select_timeout;
1035 }
1036
1037 /****************************************************************************
1038  Check if services need reloading.
1039 ****************************************************************************/
1040
1041 void check_reload(int t)
1042 {
1043   static time_t last_smb_conf_reload_time = 0;
1044
1045   if(last_smb_conf_reload_time == 0)
1046     last_smb_conf_reload_time = t;
1047
1048   if (reload_after_sighup || (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK))
1049   {
1050     reload_services(True);
1051     reload_after_sighup = False;
1052     last_smb_conf_reload_time = t;
1053   }
1054 }
1055
1056 /****************************************************************************
1057  Process any timeout housekeeping. Return False if the caller should exit.
1058 ****************************************************************************/
1059
1060 static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_timeout_processing_time)
1061 {
1062   static time_t last_keepalive_sent_time = 0;
1063   static time_t last_idle_closed_check = 0;
1064   time_t t;
1065   BOOL allidle = True;
1066   extern int keepalive;
1067
1068   if (smb_read_error == READ_EOF) 
1069   {
1070     DEBUG(3,("end of file from client\n"));
1071     return False;
1072   }
1073
1074   if (smb_read_error == READ_ERROR) 
1075   {
1076     DEBUG(3,("receive_smb error (%s) exiting\n",
1077               strerror(errno)));
1078     return False;
1079   }
1080
1081   *last_timeout_processing_time = t = time(NULL);
1082
1083   if(last_keepalive_sent_time == 0)
1084     last_keepalive_sent_time = t;
1085
1086   if(last_idle_closed_check == 0)
1087     last_idle_closed_check = t;
1088
1089   /* become root again if waiting */
1090   change_to_root_user();
1091
1092   /* check if we need to reload services */
1093   check_reload(t);
1094
1095   /* automatic timeout if all connections are closed */      
1096   if (conn_num_open()==0 && (t - last_idle_closed_check) >= IDLE_CLOSED_TIMEOUT) 
1097   {
1098     DEBUG( 2, ( "Closing idle connection\n" ) );
1099     return False;
1100   }
1101   else
1102     last_idle_closed_check = t;
1103
1104   if (keepalive && (t - last_keepalive_sent_time)>keepalive) 
1105   {
1106           extern struct auth_context *negprot_global_auth_context;
1107           if (!send_keepalive(smbd_server_fd())) {
1108                   DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
1109                   return False;
1110           }
1111           
1112           /* send a keepalive for a password server or the like.
1113              This is attached to the auth_info created in the
1114              negprot */
1115           if (negprot_global_auth_context 
1116               && negprot_global_auth_context->challenge_set_method 
1117               && negprot_global_auth_context->challenge_set_method->send_keepalive) {
1118                   negprot_global_auth_context->challenge_set_method->send_keepalive
1119                           (&negprot_global_auth_context->challenge_set_method->private_data);
1120           }
1121
1122           last_keepalive_sent_time = t;
1123   }
1124
1125   /* check for connection timeouts */
1126   allidle = conn_idle_all(t, deadtime);
1127
1128   if (allidle && conn_num_open()>0) {
1129     DEBUG(2,("Closing idle connection 2.\n"));
1130     return False;
1131   }
1132
1133   if(global_machine_password_needs_changing && 
1134      /* for ADS we need to do a regular ADS password change, not a domain
1135         password change */
1136      lp_security() == SEC_DOMAIN)
1137   {
1138     unsigned char trust_passwd_hash[16];
1139     time_t lct;
1140     pstring remote_machine_list;
1141
1142     /*
1143      * We're in domain level security, and the code that
1144      * read the machine password flagged that the machine
1145      * password needs changing.
1146      */
1147
1148     /*
1149      * First, open the machine password file with an exclusive lock.
1150      */
1151
1152     if(!secrets_fetch_trust_account_password(global_myworkgroup, trust_passwd_hash, &lct)) {
1153       DEBUG(0,("process: unable to read the machine account password for \
1154 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
1155       return True;
1156     }
1157
1158     /*
1159      * Make sure someone else hasn't already done this.
1160      */
1161
1162     if(t < lct + lp_machine_password_timeout()) {
1163       global_machine_password_needs_changing = False;
1164       return True;
1165     }
1166
1167     pstrcpy(remote_machine_list, lp_passwordserver());
1168
1169     change_trust_account_password( global_myworkgroup, remote_machine_list);
1170     global_machine_password_needs_changing = False;
1171   }
1172
1173   /*
1174    * Check to see if we have any blocking locks
1175    * outstanding on the queue.
1176    */
1177   process_blocking_lock_queue(t);
1178
1179   /*
1180    * Check to see if we have any change notifies 
1181    * outstanding on the queue.
1182    */
1183   process_pending_change_notify_queue(t);
1184
1185   /*
1186    * Now we are root, check if the log files need pruning.
1187    * Force a log file check.
1188    */
1189   force_check_log_size();
1190   check_log_size();
1191
1192   /*
1193    * Modify the select timeout depending upon
1194    * what we have remaining in our queues.
1195    */
1196
1197   *select_timeout = setup_select_timeout();
1198
1199   return True;
1200 }
1201
1202 /****************************************************************************
1203   process commands from the client
1204 ****************************************************************************/
1205
1206 void smbd_process(void)
1207 {
1208         extern int smb_echo_count;
1209         time_t last_timeout_processing_time = time(NULL);
1210         unsigned int num_smbs = 0;
1211
1212         InBuffer = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN);
1213         OutBuffer = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN);
1214         if ((InBuffer == NULL) || (OutBuffer == NULL)) 
1215                 return;
1216
1217         max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
1218
1219         while (True) {
1220                 int deadtime = lp_deadtime()*60;
1221                 int select_timeout = setup_select_timeout();
1222                 int num_echos;
1223
1224                 if (deadtime <= 0)
1225                         deadtime = DEFAULT_SMBD_TIMEOUT;
1226
1227                 errno = 0;      
1228                 
1229                 /* free up temporary memory */
1230                 lp_talloc_free();
1231                 main_loop_talloc_free();
1232
1233                 while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,select_timeout)) {
1234                         if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1235                                 return;
1236                         num_smbs = 0; /* Reset smb counter. */
1237                 }
1238
1239                 /*
1240                  * Ensure we do timeout processing if the SMB we just got was
1241                  * only an echo request. This allows us to set the select
1242                  * timeout in 'receive_message_or_smb()' to any value we like
1243                  * without worrying that the client will send echo requests
1244                  * faster than the select timeout, thus starving out the
1245                  * essential processing (change notify, blocking locks) that
1246                  * the timeout code does. JRA.
1247                  */ 
1248                 num_echos = smb_echo_count;
1249
1250                 process_smb(InBuffer, OutBuffer);
1251
1252                 if (smb_echo_count != num_echos) {
1253                         if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1254                                 return;
1255                         num_smbs = 0; /* Reset smb counter. */
1256                 }
1257
1258                 num_smbs++;
1259
1260                 /*
1261                  * If we are getting smb requests in a constant stream
1262                  * with no echos, make sure we attempt timeout processing
1263                  * every select_timeout milliseconds - but only check for this
1264                  * every 200 smb requests.
1265                  */
1266                 
1267                 if ((num_smbs % 200) == 0) {
1268                         time_t new_check_time = time(NULL);
1269                         if(new_check_time - last_timeout_processing_time >= (select_timeout/1000)) {
1270                                 if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
1271                                         return;
1272                                 num_smbs = 0; /* Reset smb counter. */
1273                                 last_timeout_processing_time = new_check_time; /* Reset time. */
1274                         }
1275                 }
1276         }
1277 }