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