| 1 | /*
|
|---|
| 2 | Unix SMB/CIFS implementation.
|
|---|
| 3 | process incoming packets - main loop
|
|---|
| 4 | Copyright (C) Andrew Tridgell 1992-1998
|
|---|
| 5 | Copyright (C) Volker Lendecke 2005
|
|---|
| 6 |
|
|---|
| 7 | This program is free software; you can redistribute it and/or modify
|
|---|
| 8 | it under the terms of the GNU General Public License as published by
|
|---|
| 9 | the Free Software Foundation; either version 2 of the License, or
|
|---|
| 10 | (at your option) any later version.
|
|---|
| 11 |
|
|---|
| 12 | This program is distributed in the hope that it will be useful,
|
|---|
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 15 | GNU General Public License for more details.
|
|---|
| 16 |
|
|---|
| 17 | You should have received a copy of the GNU General Public License
|
|---|
| 18 | along with this program; if not, write to the Free Software
|
|---|
| 19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|---|
| 20 | */
|
|---|
| 21 |
|
|---|
| 22 | #include "includes.h"
|
|---|
| 23 |
|
|---|
| 24 | uint16 global_smbpid;
|
|---|
| 25 | extern int keepalive;
|
|---|
| 26 | extern struct auth_context *negprot_global_auth_context;
|
|---|
| 27 | extern int smb_echo_count;
|
|---|
| 28 |
|
|---|
| 29 | static char *InBuffer = NULL;
|
|---|
| 30 | static char *OutBuffer = NULL;
|
|---|
| 31 | static char *current_inbuf = NULL;
|
|---|
| 32 |
|
|---|
| 33 | /*
|
|---|
| 34 | * Size of data we can send to client. Set
|
|---|
| 35 | * by the client for all protocols above CORE.
|
|---|
| 36 | * Set by us for CORE protocol.
|
|---|
| 37 | */
|
|---|
| 38 | int max_send = BUFFER_SIZE;
|
|---|
| 39 | /*
|
|---|
| 40 | * Size of the data we can receive. Set by us.
|
|---|
| 41 | * Can be modified by the max xmit parameter.
|
|---|
| 42 | */
|
|---|
| 43 | int max_recv = BUFFER_SIZE;
|
|---|
| 44 |
|
|---|
| 45 | extern int last_message;
|
|---|
| 46 | extern int smb_read_error;
|
|---|
| 47 | SIG_ATOMIC_T reload_after_sighup = 0;
|
|---|
| 48 | SIG_ATOMIC_T got_sig_term = 0;
|
|---|
| 49 | extern BOOL global_machine_password_needs_changing;
|
|---|
| 50 | extern int max_send;
|
|---|
| 51 |
|
|---|
| 52 | /****************************************************************************
|
|---|
| 53 | Function to return the current request mid from Inbuffer.
|
|---|
| 54 | ****************************************************************************/
|
|---|
| 55 |
|
|---|
| 56 | uint16 get_current_mid(void)
|
|---|
| 57 | {
|
|---|
| 58 | return SVAL(InBuffer,smb_mid);
|
|---|
| 59 | }
|
|---|
| 60 |
|
|---|
| 61 | /****************************************************************************
|
|---|
| 62 | structure to hold a linked list of queued messages.
|
|---|
| 63 | for processing.
|
|---|
| 64 | ****************************************************************************/
|
|---|
| 65 |
|
|---|
| 66 | static struct pending_message_list *deferred_open_queue;
|
|---|
| 67 |
|
|---|
| 68 | /****************************************************************************
|
|---|
| 69 | Function to push a message onto the tail of a linked list of smb messages ready
|
|---|
| 70 | for processing.
|
|---|
| 71 | ****************************************************************************/
|
|---|
| 72 |
|
|---|
| 73 | static BOOL push_queued_message(char *buf, int msg_len,
|
|---|
| 74 | struct timeval request_time,
|
|---|
| 75 | struct timeval end_time,
|
|---|
| 76 | char *private_data, size_t private_len)
|
|---|
| 77 | {
|
|---|
| 78 | struct pending_message_list *msg;
|
|---|
| 79 |
|
|---|
| 80 | msg = TALLOC_ZERO_P(NULL, struct pending_message_list);
|
|---|
| 81 |
|
|---|
| 82 | if(msg == NULL) {
|
|---|
| 83 | DEBUG(0,("push_message: malloc fail (1)\n"));
|
|---|
| 84 | return False;
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | msg->buf = data_blob_talloc(msg, buf, msg_len);
|
|---|
| 88 | if(msg->buf.data == NULL) {
|
|---|
| 89 | DEBUG(0,("push_message: malloc fail (2)\n"));
|
|---|
| 90 | TALLOC_FREE(msg);
|
|---|
| 91 | return False;
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | msg->request_time = request_time;
|
|---|
| 95 | msg->end_time = end_time;
|
|---|
| 96 |
|
|---|
| 97 | if (private_data) {
|
|---|
| 98 | msg->private_data = data_blob_talloc(msg, private_data,
|
|---|
| 99 | private_len);
|
|---|
| 100 | if (msg->private_data.data == NULL) {
|
|---|
| 101 | DEBUG(0,("push_message: malloc fail (3)\n"));
|
|---|
| 102 | TALLOC_FREE(msg);
|
|---|
| 103 | return False;
|
|---|
| 104 | }
|
|---|
| 105 | }
|
|---|
| 106 |
|
|---|
| 107 | DLIST_ADD_END(deferred_open_queue, msg, struct pending_message_list *);
|
|---|
| 108 |
|
|---|
| 109 | DEBUG(10,("push_message: pushed message length %u on "
|
|---|
| 110 | "deferred_open_queue\n", (unsigned int)msg_len));
|
|---|
| 111 |
|
|---|
| 112 | return True;
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | /****************************************************************************
|
|---|
| 116 | Function to delete a sharing violation open message by mid.
|
|---|
| 117 | ****************************************************************************/
|
|---|
| 118 |
|
|---|
| 119 | void remove_deferred_open_smb_message(uint16 mid)
|
|---|
| 120 | {
|
|---|
| 121 | struct pending_message_list *pml;
|
|---|
| 122 |
|
|---|
| 123 | for (pml = deferred_open_queue; pml; pml = pml->next) {
|
|---|
| 124 | if (mid == SVAL(pml->buf.data,smb_mid)) {
|
|---|
| 125 | DEBUG(10,("remove_sharing_violation_open_smb_message: "
|
|---|
| 126 | "deleting mid %u len %u\n",
|
|---|
| 127 | (unsigned int)mid,
|
|---|
| 128 | (unsigned int)pml->buf.length ));
|
|---|
| 129 | DLIST_REMOVE(deferred_open_queue, pml);
|
|---|
| 130 | TALLOC_FREE(pml);
|
|---|
| 131 | return;
|
|---|
| 132 | }
|
|---|
| 133 | }
|
|---|
| 134 | }
|
|---|
| 135 |
|
|---|
| 136 | /****************************************************************************
|
|---|
| 137 | Move a sharing violation open retry message to the front of the list and
|
|---|
| 138 | schedule it for immediate processing.
|
|---|
| 139 | ****************************************************************************/
|
|---|
| 140 |
|
|---|
| 141 | void schedule_deferred_open_smb_message(uint16 mid)
|
|---|
| 142 | {
|
|---|
| 143 | struct pending_message_list *pml;
|
|---|
| 144 | int i = 0;
|
|---|
| 145 |
|
|---|
| 146 | for (pml = deferred_open_queue; pml; pml = pml->next) {
|
|---|
| 147 | uint16 msg_mid = SVAL(pml->buf.data,smb_mid);
|
|---|
| 148 | DEBUG(10,("schedule_deferred_open_smb_message: [%d] msg_mid = %u\n", i++,
|
|---|
| 149 | (unsigned int)msg_mid ));
|
|---|
| 150 | if (mid == msg_mid) {
|
|---|
| 151 | DEBUG(10,("schedule_deferred_open_smb_message: scheduling mid %u\n",
|
|---|
| 152 | mid ));
|
|---|
| 153 | pml->end_time.tv_sec = 0;
|
|---|
| 154 | pml->end_time.tv_usec = 0;
|
|---|
| 155 | DLIST_PROMOTE(deferred_open_queue, pml);
|
|---|
| 156 | return;
|
|---|
| 157 | }
|
|---|
| 158 | }
|
|---|
| 159 |
|
|---|
| 160 | DEBUG(10,("schedule_deferred_open_smb_message: failed to find message mid %u\n",
|
|---|
| 161 | mid ));
|
|---|
| 162 | }
|
|---|
| 163 |
|
|---|
| 164 | /****************************************************************************
|
|---|
| 165 | Return true if this mid is on the deferred queue.
|
|---|
| 166 | ****************************************************************************/
|
|---|
| 167 |
|
|---|
| 168 | BOOL open_was_deferred(uint16 mid)
|
|---|
| 169 | {
|
|---|
| 170 | struct pending_message_list *pml;
|
|---|
| 171 |
|
|---|
| 172 | for (pml = deferred_open_queue; pml; pml = pml->next) {
|
|---|
| 173 | if (SVAL(pml->buf.data,smb_mid) == mid) {
|
|---|
| 174 | return True;
|
|---|
| 175 | }
|
|---|
| 176 | }
|
|---|
| 177 | return False;
|
|---|
| 178 | }
|
|---|
| 179 |
|
|---|
| 180 | /****************************************************************************
|
|---|
| 181 | Return the message queued by this mid.
|
|---|
| 182 | ****************************************************************************/
|
|---|
| 183 |
|
|---|
| 184 | struct pending_message_list *get_open_deferred_message(uint16 mid)
|
|---|
| 185 | {
|
|---|
| 186 | struct pending_message_list *pml;
|
|---|
| 187 |
|
|---|
| 188 | for (pml = deferred_open_queue; pml; pml = pml->next) {
|
|---|
| 189 | if (SVAL(pml->buf.data,smb_mid) == mid) {
|
|---|
| 190 | return pml;
|
|---|
| 191 | }
|
|---|
| 192 | }
|
|---|
| 193 | return NULL;
|
|---|
| 194 | }
|
|---|
| 195 |
|
|---|
| 196 | /****************************************************************************
|
|---|
| 197 | Function to push a deferred open smb message onto a linked list of local smb
|
|---|
| 198 | messages ready for processing.
|
|---|
| 199 | ****************************************************************************/
|
|---|
| 200 |
|
|---|
| 201 | BOOL push_deferred_smb_message(uint16 mid,
|
|---|
| 202 | struct timeval request_time,
|
|---|
| 203 | struct timeval timeout,
|
|---|
| 204 | char *private_data, size_t priv_len)
|
|---|
| 205 | {
|
|---|
| 206 | struct timeval end_time;
|
|---|
| 207 |
|
|---|
| 208 | end_time = timeval_sum(&request_time, &timeout);
|
|---|
| 209 |
|
|---|
| 210 | DEBUG(10,("push_deferred_open_smb_message: pushing message len %u mid %u "
|
|---|
| 211 | "timeout time [%u.%06u]\n",
|
|---|
| 212 | (unsigned int) smb_len(current_inbuf)+4, (unsigned int)mid,
|
|---|
| 213 | (unsigned int)end_time.tv_sec,
|
|---|
| 214 | (unsigned int)end_time.tv_usec));
|
|---|
| 215 |
|
|---|
| 216 | return push_queued_message(current_inbuf, smb_len(current_inbuf)+4,
|
|---|
| 217 | request_time, end_time,
|
|---|
| 218 | private_data, priv_len);
|
|---|
| 219 | }
|
|---|
| 220 |
|
|---|
| 221 | struct idle_event {
|
|---|
| 222 | struct timed_event *te;
|
|---|
| 223 | struct timeval interval;
|
|---|
| 224 | BOOL (*handler)(const struct timeval *now, void *private_data);
|
|---|
| 225 | void *private_data;
|
|---|
| 226 | };
|
|---|
| 227 |
|
|---|
| 228 | static void idle_event_handler(struct event_context *ctx,
|
|---|
| 229 | struct timed_event *te,
|
|---|
| 230 | const struct timeval *now,
|
|---|
| 231 | void *private_data)
|
|---|
| 232 | {
|
|---|
| 233 | struct idle_event *event =
|
|---|
| 234 | talloc_get_type_abort(private_data, struct idle_event);
|
|---|
| 235 |
|
|---|
| 236 | TALLOC_FREE(event->te);
|
|---|
| 237 |
|
|---|
| 238 | if (!event->handler(now, event->private_data)) {
|
|---|
| 239 | /* Don't repeat, delete ourselves */
|
|---|
| 240 | TALLOC_FREE(event);
|
|---|
| 241 | return;
|
|---|
| 242 | }
|
|---|
| 243 |
|
|---|
| 244 | event->te = event_add_timed(smbd_event_context(), event,
|
|---|
| 245 | timeval_sum(now, &event->interval),
|
|---|
| 246 | "idle_event_handler",
|
|---|
| 247 | idle_event_handler, event);
|
|---|
| 248 |
|
|---|
| 249 | /* We can't do much but fail here. */
|
|---|
| 250 | SMB_ASSERT(event->te != NULL);
|
|---|
| 251 | }
|
|---|
| 252 |
|
|---|
| 253 | struct idle_event *add_idle_event(TALLOC_CTX *mem_ctx,
|
|---|
| 254 | struct timeval interval,
|
|---|
| 255 | BOOL (*handler)(const struct timeval *now,
|
|---|
| 256 | void *private_data),
|
|---|
| 257 | void *private_data)
|
|---|
| 258 | {
|
|---|
| 259 | struct idle_event *result;
|
|---|
| 260 | struct timeval now = timeval_current();
|
|---|
| 261 |
|
|---|
| 262 | result = TALLOC_P(mem_ctx, struct idle_event);
|
|---|
| 263 | if (result == NULL) {
|
|---|
| 264 | DEBUG(0, ("talloc failed\n"));
|
|---|
| 265 | return NULL;
|
|---|
| 266 | }
|
|---|
| 267 |
|
|---|
| 268 | result->interval = interval;
|
|---|
| 269 | result->handler = handler;
|
|---|
| 270 | result->private_data = private_data;
|
|---|
| 271 |
|
|---|
| 272 | result->te = event_add_timed(smbd_event_context(), result,
|
|---|
| 273 | timeval_sum(&now, &interval),
|
|---|
| 274 | "idle_event_handler",
|
|---|
| 275 | idle_event_handler, result);
|
|---|
| 276 | if (result->te == NULL) {
|
|---|
| 277 | DEBUG(0, ("event_add_timed failed\n"));
|
|---|
| 278 | TALLOC_FREE(result);
|
|---|
| 279 | return NULL;
|
|---|
| 280 | }
|
|---|
| 281 |
|
|---|
| 282 | return result;
|
|---|
| 283 | }
|
|---|
| 284 |
|
|---|
| 285 | /****************************************************************************
|
|---|
| 286 | Do all async processing in here. This includes kernel oplock messages, change
|
|---|
| 287 | notify events etc.
|
|---|
| 288 | ****************************************************************************/
|
|---|
| 289 |
|
|---|
| 290 | static void async_processing(fd_set *pfds)
|
|---|
| 291 | {
|
|---|
| 292 | DEBUG(10,("async_processing: Doing async processing.\n"));
|
|---|
| 293 |
|
|---|
| 294 | process_aio_queue();
|
|---|
| 295 |
|
|---|
| 296 | process_kernel_oplocks(pfds);
|
|---|
| 297 |
|
|---|
| 298 | /* Do the aio check again after receive_local_message as it does a
|
|---|
| 299 | select and may have eaten our signal. */
|
|---|
| 300 | /* Is this till true? -- vl */
|
|---|
| 301 | process_aio_queue();
|
|---|
| 302 |
|
|---|
| 303 | if (got_sig_term) {
|
|---|
| 304 | exit_server_cleanly("termination signal");
|
|---|
| 305 | }
|
|---|
| 306 |
|
|---|
| 307 | /* check for sighup processing */
|
|---|
| 308 | if (reload_after_sighup) {
|
|---|
| 309 | change_to_root_user();
|
|---|
| 310 | DEBUG(1,("Reloading services after SIGHUP\n"));
|
|---|
| 311 | reload_services(False);
|
|---|
| 312 | reload_after_sighup = 0;
|
|---|
| 313 | }
|
|---|
| 314 | }
|
|---|
| 315 |
|
|---|
| 316 | /****************************************************************************
|
|---|
| 317 | Add a fd to the set we will be select(2)ing on.
|
|---|
| 318 | ****************************************************************************/
|
|---|
| 319 |
|
|---|
| 320 | static int select_on_fd(int fd, int maxfd, fd_set *fds)
|
|---|
| 321 | {
|
|---|
| 322 | if (fd != -1) {
|
|---|
| 323 | FD_SET(fd, fds);
|
|---|
| 324 | maxfd = MAX(maxfd, fd);
|
|---|
| 325 | }
|
|---|
| 326 |
|
|---|
| 327 | return maxfd;
|
|---|
| 328 | }
|
|---|
| 329 |
|
|---|
| 330 | /****************************************************************************
|
|---|
| 331 | Do a select on an two fd's - with timeout.
|
|---|
| 332 |
|
|---|
| 333 | If a local udp message has been pushed onto the
|
|---|
| 334 | queue (this can only happen during oplock break
|
|---|
| 335 | processing) call async_processing()
|
|---|
| 336 |
|
|---|
| 337 | If a pending smb message has been pushed onto the
|
|---|
| 338 | queue (this can only happen during oplock break
|
|---|
| 339 | processing) return this next.
|
|---|
| 340 |
|
|---|
| 341 | If the first smbfd is ready then read an smb from it.
|
|---|
| 342 | if the second (loopback UDP) fd is ready then read a message
|
|---|
| 343 | from it and setup the buffer header to identify the length
|
|---|
| 344 | and from address.
|
|---|
| 345 | Returns False on timeout or error.
|
|---|
| 346 | Else returns True.
|
|---|
| 347 |
|
|---|
| 348 | The timeout is in milliseconds
|
|---|
| 349 | ****************************************************************************/
|
|---|
| 350 |
|
|---|
| 351 | static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
|
|---|
| 352 | {
|
|---|
| 353 | fd_set r_fds, w_fds;
|
|---|
| 354 | int selrtn;
|
|---|
| 355 | struct timeval to;
|
|---|
| 356 | int maxfd = 0;
|
|---|
| 357 |
|
|---|
| 358 | smb_read_error = 0;
|
|---|
| 359 |
|
|---|
| 360 | again:
|
|---|
| 361 |
|
|---|
| 362 | if (timeout >= 0) {
|
|---|
| 363 | to.tv_sec = timeout / 1000;
|
|---|
| 364 | to.tv_usec = (timeout % 1000) * 1000;
|
|---|
| 365 | } else {
|
|---|
| 366 | to.tv_sec = SMBD_SELECT_TIMEOUT;
|
|---|
| 367 | to.tv_usec = 0;
|
|---|
| 368 | }
|
|---|
| 369 |
|
|---|
| 370 | /*
|
|---|
| 371 | * Note that this call must be before processing any SMB
|
|---|
| 372 | * messages as we need to synchronously process any messages
|
|---|
| 373 | * we may have sent to ourselves from the previous SMB.
|
|---|
| 374 | */
|
|---|
| 375 | message_dispatch();
|
|---|
| 376 |
|
|---|
|
|---|