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