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