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