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