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