smbd/process.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    process incoming packets - main loop
00004    Copyright (C) Andrew Tridgell 1992-1998
00005    Copyright (C) Volker Lendecke 2005
00006    
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011    
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016    
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 */
00021 
00022 #include "includes.h"
00023 
00024 uint16 global_smbpid;
00025 extern int keepalive;
00026 extern struct auth_context *negprot_global_auth_context;
00027 extern int smb_echo_count;
00028 
00029 static char *InBuffer = NULL;
00030 static char *OutBuffer = NULL;
00031 static char *current_inbuf = NULL;
00032 
00033 /* 
00034  * Size of data we can send to client. Set
00035  *  by the client for all protocols above CORE.
00036  *  Set by us for CORE protocol.
00037  */
00038 int max_send = BUFFER_SIZE;
00039 /*
00040  * Size of the data we can receive. Set by us.
00041  * Can be modified by the max xmit parameter.
00042  */
00043 int max_recv = BUFFER_SIZE;
00044 
00045 extern int last_message;
00046 extern int smb_read_error;
00047 SIG_ATOMIC_T reload_after_sighup = 0;
00048 SIG_ATOMIC_T got_sig_term = 0;
00049 extern BOOL global_machine_password_needs_changing;
00050 extern int max_send;
00051 
00052 /****************************************************************************
00053  Function to return the current request mid from Inbuffer.
00054 ****************************************************************************/
00055 
00056 uint16 get_current_mid(void)
00057 {
00058         return SVAL(InBuffer,smb_mid);
00059 }
00060 
00061 /****************************************************************************
00062  structure to hold a linked list of queued messages.
00063  for processing.
00064 ****************************************************************************/
00065 
00066 static struct pending_message_list *deferred_open_queue;
00067 
00068 /****************************************************************************
00069  Function to push a message onto the tail of a linked list of smb messages ready
00070  for processing.
00071 ****************************************************************************/
00072 
00073 static BOOL push_queued_message(char *buf, int msg_len,
00074                                 struct timeval request_time,
00075                                 struct timeval end_time,
00076                                 char *private_data, size_t private_len)
00077 {
00078         struct pending_message_list *msg;
00079 
00080         msg = TALLOC_ZERO_P(NULL, struct pending_message_list);
00081 
00082         if(msg == NULL) {
00083                 DEBUG(0,("push_message: malloc fail (1)\n"));
00084                 return False;
00085         }
00086 
00087         msg->buf = data_blob_talloc(msg, buf, msg_len);
00088         if(msg->buf.data == NULL) {
00089                 DEBUG(0,("push_message: malloc fail (2)\n"));
00090                 TALLOC_FREE(msg);
00091                 return False;
00092         }
00093 
00094         msg->request_time = request_time;
00095         msg->end_time = end_time;
00096 
00097         if (private_data) {
00098                 msg->private_data = data_blob_talloc(msg, private_data,
00099                                                      private_len);
00100                 if (msg->private_data.data == NULL) {
00101                         DEBUG(0,("push_message: malloc fail (3)\n"));
00102                         TALLOC_FREE(msg);
00103                         return False;
00104                 }
00105         }
00106 
00107         DLIST_ADD_END(deferred_open_queue, msg, struct pending_message_list *);
00108 
00109         DEBUG(10,("push_message: pushed message length %u on "
00110                   "deferred_open_queue\n", (unsigned int)msg_len));
00111 
00112         return True;
00113 }
00114 
00115 /****************************************************************************
00116  Function to delete a sharing violation open message by mid.
00117 ****************************************************************************/
00118 
00119 void remove_deferred_open_smb_message(uint16 mid)
00120 {
00121         struct pending_message_list *pml;
00122 
00123         for (pml = deferred_open_queue; pml; pml = pml->next) {
00124                 if (mid == SVAL(pml->buf.data,smb_mid)) {
00125                         DEBUG(10,("remove_sharing_violation_open_smb_message: "
00126                                   "deleting mid %u len %u\n",
00127                                   (unsigned int)mid,
00128                                   (unsigned int)pml->buf.length ));
00129                         DLIST_REMOVE(deferred_open_queue, pml);
00130                         TALLOC_FREE(pml);
00131                         return;
00132                 }
00133         }
00134 }
00135 
00136 /****************************************************************************
00137  Move a sharing violation open retry message to the front of the list and
00138  schedule it for immediate processing.
00139 ****************************************************************************/
00140 
00141 void schedule_deferred_open_smb_message(uint16 mid)
00142 {
00143         struct pending_message_list *pml;
00144         int i = 0;
00145 
00146         for (pml = deferred_open_queue; pml; pml = pml->next) {
00147                 uint16 msg_mid = SVAL(pml->buf.data,smb_mid);
00148                 DEBUG(10,("schedule_deferred_open_smb_message: [%d] msg_mid = %u\n", i++,
00149                         (unsigned int)msg_mid ));
00150                 if (mid == msg_mid) {
00151                         DEBUG(10,("schedule_deferred_open_smb_message: scheduling mid %u\n",
00152                                 mid ));
00153                         pml->end_time.tv_sec = 0;
00154                         pml->end_time.tv_usec = 0;
00155                         DLIST_PROMOTE(deferred_open_queue, pml);
00156                         return;
00157                 }
00158         }
00159 
00160         DEBUG(10,("schedule_deferred_open_smb_message: failed to find message mid %u\n",
00161                 mid ));
00162 }
00163 
00164 /****************************************************************************
00165  Return true if this mid is on the deferred queue.
00166 ****************************************************************************/
00167 
00168 BOOL open_was_deferred(uint16 mid)
00169 {
00170         struct pending_message_list *pml;
00171 
00172         for (pml = deferred_open_queue; pml; pml = pml->next) {
00173                 if (SVAL(pml->buf.data,smb_mid) == mid) {
00174                         return True;
00175                 }
00176         }
00177         return False;
00178 }
00179 
00180 /****************************************************************************
00181  Return the message queued by this mid.
00182 ****************************************************************************/
00183 
00184 struct pending_message_list *get_open_deferred_message(uint16 mid)
00185 {
00186         struct pending_message_list *pml;
00187 
00188         for (pml = deferred_open_queue; pml; pml = pml->next) {
00189                 if (SVAL(pml->buf.data,smb_mid) == mid) {
00190                         return pml;
00191                 }
00192         }
00193         return NULL;
00194 }
00195 
00196 /****************************************************************************
00197  Function to push a deferred open smb message onto a linked list of local smb
00198  messages ready for processing.
00199 ****************************************************************************/
00200 
00201 BOOL push_deferred_smb_message(uint16 mid,
00202                                struct timeval request_time,
00203                                struct timeval timeout,
00204                                char *private_data, size_t priv_len)
00205 {
00206         struct timeval end_time;
00207 
00208         end_time = timeval_sum(&request_time, &timeout);
00209 
00210         DEBUG(10,("push_deferred_open_smb_message: pushing message len %u mid %u "
00211                   "timeout time [%u.%06u]\n",
00212                   (unsigned int) smb_len(current_inbuf)+4, (unsigned int)mid,
00213                   (unsigned int)end_time.tv_sec,
00214                   (unsigned int)end_time.tv_usec));
00215 
00216         return push_queued_message(current_inbuf, smb_len(current_inbuf)+4,
00217                                    request_time, end_time,
00218                                    private_data, priv_len);
00219 }
00220 
00221 struct idle_event {
00222         struct timed_event *te;
00223         struct timeval interval;
00224         BOOL (*handler)(const struct timeval *now, void *private_data);
00225         void *private_data;
00226 };
00227 
00228 static void idle_event_handler(struct event_context *ctx,
00229                                struct timed_event *te,
00230                                const struct timeval *now,
00231                                void *private_data)
00232 {
00233         struct idle_event *event =
00234                 talloc_get_type_abort(private_data, struct idle_event);
00235 
00236         TALLOC_FREE(event->te);
00237 
00238         if (!event->handler(now, event->private_data)) {
00239                 /* Don't repeat, delete ourselves */
00240                 TALLOC_FREE(event);
00241                 return;
00242         }
00243 
00244         event->te = event_add_timed(smbd_event_context(), event,
00245                                     timeval_sum(now, &event->interval),
00246                                     "idle_event_handler",
00247                                     idle_event_handler, event);
00248 
00249         /* We can't do much but fail here. */
00250         SMB_ASSERT(event->te != NULL);
00251 }
00252 
00253 struct idle_event *add_idle_event(TALLOC_CTX *mem_ctx,
00254                                   struct timeval interval,
00255                                   BOOL (*handler)(const struct timeval *now,
00256                                                   void *private_data),
00257                                   void *private_data)
00258 {
00259         struct idle_event *result;
00260         struct timeval now = timeval_current();
00261 
00262         result = TALLOC_P(mem_ctx, struct idle_event);
00263         if (result == NULL) {
00264                 DEBUG(0, ("talloc failed\n"));
00265                 return NULL;
00266         }
00267 
00268         result->interval = interval;
00269         result->handler = handler;
00270         result->private_data = private_data;
00271 
00272         result->te = event_add_timed(smbd_event_context(), result,
00273                                      timeval_sum(&now, &interval),
00274                                      "idle_event_handler",
00275                                      idle_event_handler, result);
00276         if (result->te == NULL) {
00277                 DEBUG(0, ("event_add_timed failed\n"));
00278                 TALLOC_FREE(result);
00279                 return NULL;
00280         }
00281 
00282         return result;
00283 }
00284 
00285 /****************************************************************************
00286  Do all async processing in here. This includes kernel oplock messages, change
00287  notify events etc.
00288 ****************************************************************************/
00289 
00290 static void async_processing(fd_set *pfds)
00291 {
00292         DEBUG(10,("async_processing: Doing async processing.\n"));
00293 
00294         process_aio_queue();
00295 
00296         process_kernel_oplocks(pfds);
00297 
00298         /* Do the aio check again after receive_local_message as it does a
00299            select and may have eaten our signal. */
00300         /* Is this till true? -- vl */
00301         process_aio_queue();
00302 
00303         if (got_sig_term) {
00304                 exit_server_cleanly("termination signal");
00305         }
00306 
00307         /* check for sighup processing */
00308         if (reload_after_sighup) {
00309                 change_to_root_user();
00310                 DEBUG(1,("Reloading services after SIGHUP\n"));
00311                 reload_services(False);
00312                 reload_after_sighup = 0;
00313         }
00314 }
00315 
00316 /****************************************************************************
00317  Add a fd to the set we will be select(2)ing on.
00318 ****************************************************************************/
00319 
00320 static int select_on_fd(int fd, int maxfd, fd_set *fds)
00321 {
00322         if (fd != -1) {
00323                 FD_SET(fd, fds);
00324                 maxfd = MAX(maxfd, fd);
00325         }
00326 
00327         return maxfd;
00328 }
00329 
00330 /****************************************************************************
00331   Do a select on an two fd's - with timeout. 
00332 
00333   If a local udp message has been pushed onto the
00334   queue (this can only happen during oplock break
00335   processing) call async_processing()
00336 
00337   If a pending smb message has been pushed onto the
00338   queue (this can only happen during oplock break
00339   processing) return this next.
00340 
00341   If the first smbfd is ready then read an smb from it.
00342   if the second (loopback UDP) fd is ready then read a message
00343   from it and setup the buffer header to identify the length
00344   and from address.
00345   Returns False on timeout or error.
00346   Else returns True.
00347 
00348 The timeout is in milliseconds
00349 ****************************************************************************/
00350 
00351 static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
00352 {
00353         fd_set r_fds, w_fds;
00354         int selrtn;
00355         struct timeval to;
00356         int maxfd = 0;
00357 
00358         smb_read_error = 0;
00359 
00360  again:
00361 
00362         if (timeout >= 0) {
00363                 to.tv_sec = timeout / 1000;
00364                 to.tv_usec = (timeout % 1000) * 1000;
00365         } else {
00366                 to.tv_sec = SMBD_SELECT_TIMEOUT;
00367                 to.tv_usec = 0;
00368         }
00369 
00370         /*
00371          * Note that this call must be before processing any SMB
00372          * messages as we need to synchronously process any messages
00373          * we may have sent to ourselves from the previous SMB.
00374          */
00375         message_dispatch();
00376 
00377         /*
00378          * Check to see if we already have a message on the deferred open queue
00379          * and it's time to schedule.
00380          */
00381         if(deferred_open_queue != NULL) {
00382                 BOOL pop_message = False;
00383                 struct pending_message_list *msg = deferred_open_queue;
00384 
00385                 if (timeval_is_zero(&msg->end_time)) {
00386                         pop_message = True;
00387                 } else {
00388                         struct timeval tv;
00389                         SMB_BIG_INT tdif;
00390 
00391                         GetTimeOfDay(&tv);
00392                         tdif = usec_time_diff(&msg->end_time, &tv);
00393                         if (tdif <= 0) {
00394                                 /* Timed out. Schedule...*/
00395                                 pop_message = True;
00396                                 DEBUG(10,("receive_message_or_smb: queued message timed out.\n"));
00397                         } else {
00398                                 /* Make a more accurate select timeout. */
00399                                 to.tv_sec = tdif / 1000000;
00400                                 to.tv_usec = tdif % 1000000;
00401                                 DEBUG(10,("receive_message_or_smb: select with timeout of [%u.%06u]\n",
00402                                         (unsigned int)to.tv_sec, (unsigned int)to.tv_usec ));
00403                         }
00404                 }
00405 
00406                 if (pop_message) {
00407                         memcpy(buffer, msg->buf.data, MIN(buffer_len, msg->buf.length));
00408   
00409                         /* We leave this message on the queue so the open code can
00410                            know this is a retry. */
00411                         DEBUG(5,("receive_message_or_smb: returning deferred open smb message.\n"));
00412                         return True;
00413                 }
00414         }
00415 
00416         /*
00417          * Setup the select fd sets.
00418          */
00419 
00420         FD_ZERO(&r_fds);
00421         FD_ZERO(&w_fds);
00422 
00423         /*
00424          * Ensure we process oplock break messages by preference.
00425          * We have to do this before the select, after the select
00426          * and if the select returns EINTR. This is due to the fact
00427          * that the selects called from async_processing can eat an EINTR
00428          * caused by a signal (we can't take the break message there).
00429          * This is hideously complex - *MUST* be simplified for 3.0 ! JRA.
00430          */
00431 
00432         if (oplock_message_waiting(&r_fds)) {
00433                 DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
00434                 async_processing(&r_fds);
00435                 /*
00436                  * After async processing we must go and do the select again, as
00437                  * the state of the flag in fds for the server file descriptor is
00438                  * indeterminate - we may have done I/O on it in the oplock processing. JRA.
00439                  */
00440                 goto again;
00441         }
00442 
00443         /*
00444          * Are there any timed events waiting ? If so, ensure we don't
00445          * select for longer than it would take to wait for them.
00446          */
00447 
00448         {
00449                 struct timeval now;
00450                 GetTimeOfDay(&now);
00451 
00452                 event_add_to_select_args(smbd_event_context(), &now,
00453                                          &r_fds, &w_fds, &to, &maxfd);
00454         }
00455 
00456         if (timeval_is_zero(&to)) {
00457                 /* Process a timed event now... */
00458                 if (run_events(smbd_event_context(), 0, NULL, NULL)) {
00459                         goto again;
00460                 }
00461         }
00462         
00463         {
00464                 int sav;
00465                 START_PROFILE(smbd_idle);
00466 
00467                 maxfd = select_on_fd(smbd_server_fd(), maxfd, &r_fds);
00468                 maxfd = select_on_fd(oplock_notify_fd(), maxfd, &r_fds);
00469 
00470                 selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&to);
00471                 sav = errno;
00472 
00473                 END_PROFILE(smbd_idle);
00474                 errno = sav;
00475         }
00476 
00477         if (run_events(smbd_event_context(), selrtn, &r_fds, &w_fds)) {
00478                 goto again;
00479         }
00480 
00481         /* if we get EINTR then maybe we have received an oplock
00482            signal - treat this as select returning 1. This is ugly, but
00483            is the best we can do until the oplock code knows more about
00484            signals */
00485         if (selrtn == -1 && errno == EINTR) {
00486                 async_processing(&r_fds);
00487                 /*
00488                  * After async processing we must go and do the select again, as
00489                  * the state of the flag in fds for the server file descriptor is
00490                  * indeterminate - we may have done I/O on it in the oplock processing. JRA.
00491                  */
00492                 goto again;
00493         }
00494 
00495         /* Check if error */
00496         if (selrtn == -1) {
00497                 /* something is wrong. Maybe the socket is dead? */
00498                 smb_read_error = READ_ERROR;
00499                 return False;
00500         } 
00501     
00502         /* Did we timeout ? */
00503         if (selrtn == 0) {
00504                 smb_read_error = READ_TIMEOUT;
00505                 return False;
00506         }
00507 
00508         /*
00509          * Ensure we process oplock break messages by preference.
00510          * This is IMPORTANT ! Otherwise we can starve other processes
00511          * sending us an oplock break message. JRA.
00512          */
00513 
00514         if (oplock_message_waiting(&r_fds)) {
00515                 async_processing(&r_fds);
00516                 /*
00517                  * After async processing we must go and do the select again, as
00518                  * the state of the flag in fds for the server file descriptor is
00519                  * indeterminate - we may have done I/O on it in the oplock processing. JRA.
00520                  */
00521                 goto again;
00522         }
00523 
00524         return receive_smb(smbd_server_fd(), buffer,
00525                         BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE, 0);
00526 }
00527 
00528 /*
00529  * Only allow 5 outstanding trans requests. We're allocating memory, so
00530  * prevent a DoS.
00531  */
00532 
00533 NTSTATUS allow_new_trans(struct trans_state *list, int mid)
00534 {
00535         int count = 0;
00536         for (; list != NULL; list = list->next) {
00537 
00538                 if (list->mid == mid) {
00539                         return NT_STATUS_INVALID_PARAMETER;
00540                 }
00541 
00542                 count += 1;
00543         }
00544         if (count > 5) {
00545                 return NT_STATUS_INSUFFICIENT_RESOURCES;
00546         }
00547 
00548         return NT_STATUS_OK;
00549 }
00550 
00551 /****************************************************************************
00552  We're terminating and have closed all our files/connections etc.
00553  If there are any pending local messages we need to respond to them
00554  before termination so that other smbds don't think we just died whilst
00555  holding oplocks.
00556 ****************************************************************************/
00557 
00558 void respond_to_all_remaining_local_messages(void)
00559 {
00560         /*
00561          * Assert we have no exclusive open oplocks.
00562          */
00563 
00564         if(get_number_of_exclusive_open_oplocks()) {
00565                 DEBUG(0,("respond_to_all_remaining_local_messages: PANIC : we have %d exclusive oplocks.\n",
00566                         get_number_of_exclusive_open_oplocks() ));
00567                 return;
00568         }
00569 
00570         process_kernel_oplocks(NULL);
00571 
00572         return;
00573 }
00574 
00575 
00576 /*
00577 These flags determine some of the permissions required to do an operation 
00578 
00579 Note that I don't set NEED_WRITE on some write operations because they
00580 are used by some brain-dead clients when printing, and I don't want to
00581 force write permissions on print services.
00582 */
00583 #define AS_USER (1<<0)
00584 #define NEED_WRITE (1<<1) /* Must be paired with AS_USER */
00585 #define TIME_INIT (1<<2)
00586 #define CAN_IPC (1<<3) /* Must be paired with AS_USER */
00587 #define AS_GUEST (1<<5) /* Must *NOT* be paired with AS_USER */
00588 #define DO_CHDIR (1<<6)
00589 
00590 /* 
00591    define a list of possible SMB messages and their corresponding
00592    functions. Any message that has a NULL function is unimplemented -
00593    please feel free to contribute implementations!
00594 */
00595 static const struct smb_message_struct {
00596         const char *name;
00597         int (*fn)(connection_struct *conn, char *, char *, int, int);
00598         int flags;
00599 } smb_messages[256] = {
00600 
00601 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
00602 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
00603 /* 0x02 */ { "SMBopen",reply_open,AS_USER },
00604 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
00605 /* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
00606 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
00607 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE }, 
00608 /* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
00609 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
00610 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
00611 /* 0x0a */ { "SMBread",reply_read,AS_USER},
00612 /* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
00613 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
00614 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
00615 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
00616 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER}, 
00617 /* 0x10 */ { "SMBcheckpath",reply_checkpath,AS_USER},
00618 /* 0x11 */ { "SMBexit",reply_exit,DO_CHDIR},
00619 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
00620 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
00621 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
00622 /* 0x15 */ { NULL, NULL, 0 },
00623 /* 0x16 */ { NULL, NULL, 0 },
00624 /* 0x17 */ { NULL, NULL, 0 },
00625 /* 0x18 */ { NULL, NULL, 0 },
00626 /* 0x19 */ { NULL, NULL, 0 },
00627 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
00628 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
00629 /* 0x1c */ { "SMBreadBs",NULL,0 },
00630 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
00631 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
00632 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
00633 /* 0x20 */ { "SMBwritec",NULL,0},
00634 /* 0x21 */ { NULL, NULL, 0 },
00635 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
00636 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
00637 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
00638 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
00639 /* 0x26 */ { "SMBtranss",reply_transs,AS_USER | CAN_IPC},
00640 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
00641 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
00642 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
00643 /* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE },
00644 /* 0x2b */ { "SMBecho",reply_echo,0},
00645 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
00646 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
00647 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
00648 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
00649 /* 0x30 */ { NULL, NULL, 0 },
00650 /* 0x31 */ { NULL, NULL, 0 },
00651 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
00652 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
00653 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
00654 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
00655 /* 0x36 */ { NULL, NULL, 0 },
00656 /* 0x37 */ { NULL, NULL, 0 },
00657 /* 0x38 */ { NULL, NULL, 0 },
00658 /* 0x39 */ { NULL, NULL, 0 },
00659 /* 0x3a */ { NULL, NULL, 0 },
00660 /* 0x3b */ { NULL, NULL, 0 },
00661 /* 0x3c */ { NULL, NULL, 0 },
00662 /* 0x3d */ { NULL, NULL, 0 },
00663 /* 0x3e */ { NULL, NULL, 0 },
00664 /* 0x3f */ { NULL, NULL, 0 },
00665 /* 0x40 */ { NULL, NULL, 0 },
00666 /* 0x41 */ { NULL, NULL, 0 },
00667 /* 0x42 */ { NULL, NULL, 0 },
00668 /* 0x43 */ { NULL, NULL, 0 },
00669 /* 0x44 */ { NULL, NULL, 0 },
00670 /* 0x45 */ { NULL, NULL, 0 },
00671 /* 0x46 */ { NULL, NULL, 0 },
00672 /* 0x47 */ { NULL, NULL, 0 },
00673 /* 0x48 */ { NULL, NULL, 0 },
00674 /* 0x49 */ { NULL, NULL, 0 },
00675 /* 0x4a */ { NULL, NULL, 0 },
00676 /* 0x4b */ { NULL, NULL, 0 },
00677 /* 0x4c */ { NULL, NULL, 0 },
00678 /* 0x4d */ { NULL, NULL, 0 },
00679 /* 0x4e */ { NULL, NULL, 0 },
00680 /* 0x4f */ { NULL, NULL, 0 },
00681 /* 0x50 */ { NULL, NULL, 0 },
00682 /* 0x51 */ { NULL, NULL, 0 },
00683 /* 0x52 */ { NULL, NULL, 0 },
00684 /* 0x53 */ { NULL, NULL, 0 },
00685 /* 0x54 */ { NULL, NULL, 0 },
00686 /* 0x55 */ { NULL, NULL, 0 },
00687 /* 0x56 */ { NULL, NULL, 0 },
00688 /* 0x57 */ { NULL, NULL, 0 },
00689 /* 0x58 */ { NULL, NULL, 0 },
00690 /* 0x59 */ { NULL, NULL, 0 },
00691 /* 0x5a */ { NULL, NULL, 0 },
00692 /* 0x5b */ { NULL, NULL, 0 },
00693 /* 0x5c */ { NULL, NULL, 0 },
00694 /* 0x5d */ { NULL, NULL, 0 },
00695 /* 0x5e */ { NULL, NULL, 0 },
00696 /* 0x5f */ { NULL, NULL, 0 },
00697 /* 0x60 */ { NULL, NULL, 0 },
00698 /* 0x61 */ { NULL, NULL, 0 },
00699 /* 0x62 */ { NULL, NULL, 0 },
00700 /* 0x63 */ { NULL, NULL, 0 },
00701 /* 0x64 */ { NULL, NULL, 0 },
00702 /* 0x65 */ { NULL, NULL, 0 },
00703 /* 0x66 */ { NULL, NULL, 0 },
00704 /* 0x67 */ { NULL, NULL, 0 },
00705 /* 0x68 */ { NULL, NULL, 0 },
00706 /* 0x69 */ { NULL, NULL, 0 },
00707 /* 0x6a */ { NULL, NULL, 0 },
00708 /* 0x6b */ { NULL, NULL, 0 },
00709 /* 0x6c */ { NULL, NULL, 0 },
00710 /* 0x6d */ { NULL, NULL, 0 },
00711 /* 0x6e */ { NULL, NULL, 0 },
00712 /* 0x6f */ { NULL, NULL, 0 },
00713 /* 0x70 */ { "SMBtcon",reply_tcon,0},
00714 /* 0x71 */ { "SMBtdis",reply_tdis,DO_CHDIR},
00715 /* 0x72 */ { "SMBnegprot",reply_negprot,0},
00716 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0},
00717 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
00718 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
00719 /* 0x76 */ { NULL, NULL, 0 },
00720 /* 0x77 */ { NULL, NULL, 0 },
00721 /* 0x78 */ { NULL, NULL, 0 },
00722 /* 0x79 */ { NULL, NULL, 0 },
00723 /* 0x7a */ { NULL, NULL, 0 },
00724 /* 0x7b */ { NULL, NULL, 0 },
00725 /* 0x7c */ { NULL, NULL, 0 },
00726 /* 0x7d */ { NULL, NULL, 0 },
00727 /* 0x7e */ { NULL, NULL, 0 },
00728 /* 0x7f */ { NULL, NULL, 0 },
00729 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
00730 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
00731 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
00732 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
00733 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
00734 /* 0x85 */ { NULL, NULL, 0 },
00735 /* 0x86 */ { NULL, NULL, 0 },
00736 /* 0x87 */ { NULL, NULL, 0 },
00737 /* 0x88 */ { NULL, NULL, 0 },
00738 /* 0x89 */ { NULL, NULL, 0 },
00739 /* 0x8a */ { NULL, NULL, 0 },
00740 /* 0x8b */ { NULL, NULL, 0 },
00741 /* 0x8c */ { NULL, NULL, 0 },
00742 /* 0x8d */ { NULL, NULL, 0 },
00743 /* 0x8e */ { NULL, NULL, 0 },
00744 /* 0x8f */ { NULL, NULL, 0 },
00745 /* 0x90 */ { NULL, NULL, 0 },
00746 /* 0x91 */ { NULL, NULL, 0 },
00747 /* 0x92 */ { NULL, NULL, 0 },
00748 /* 0x93 */ { NULL, NULL, 0 },
00749 /* 0x94 */ { NULL, NULL, 0 },
00750 /* 0x95 */ { NULL, NULL, 0 },
00751 /* 0x96 */ { NULL, NULL, 0 },
00752 /* 0x97 */ { NULL, NULL, 0 },
00753 /* 0x98 */ { NULL, NULL, 0 },
00754 /* 0x99 */ { NULL, NULL, 0 },
00755 /* 0x9a */ { NULL, NULL, 0 },
00756 /* 0x9b */ { NULL, NULL, 0 },
00757 /* 0x9c */ { NULL, NULL, 0 },
00758 /* 0x9d */ { NULL, NULL, 0 },
00759 /* 0x9e */ { NULL, NULL, 0 },
00760 /* 0x9f */ { NULL, NULL, 0 },
00761 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
00762 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
00763 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC },
00764 /* 0xa3 */ { NULL, NULL, 0 },
00765 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
00766 /* 0xa5 */ { "SMBntrename", reply_ntrename, AS_USER | NEED_WRITE },
00767 /* 0xa6 */ { NULL, NULL, 0 },
00768 /* 0xa7 */ { NULL, NULL, 0 },
00769 /* 0xa8 */ { NULL, NULL, 0 },
00770 /* 0xa9 */ { NULL, NULL, 0 },
00771 /* 0xaa */ { NULL, NULL, 0 },
00772 /* 0xab */ { NULL, NULL, 0 },
00773 /* 0xac */ { NULL, NULL, 0 },
00774 /* 0xad */ { NULL, NULL, 0 },
00775 /* 0xae */ { NULL, NULL, 0 },
00776 /* 0xaf */ { NULL, NULL, 0 },
00777 /* 0xb0 */ { NULL, NULL, 0 },
00778 /* 0xb1 */ { NULL, NULL, 0 },
00779 /* 0xb2 */ { NULL, NULL, 0 },
00780 /* 0xb3 */ { NULL, NULL, 0 },
00781 /* 0xb4 */ { NULL, NULL, 0 },
00782 /* 0xb5 */ { NULL, NULL, 0 },
00783 /* 0xb6 */ { NULL, NULL, 0 },
00784 /* 0xb7 */ { NULL, NULL, 0 },
00785 /* 0xb8 */ { NULL, NULL, 0 },
00786 /* 0xb9 */ { NULL, NULL, 0 },
00787 /* 0xba */ { NULL, NULL, 0 },
00788 /* 0xbb */ { NULL, NULL, 0 },
00789 /* 0xbc */ { NULL, NULL, 0 },
00790 /* 0xbd */ { NULL, NULL, 0 },
00791 /* 0xbe */ { NULL, NULL, 0 },
00792 /* 0xbf */ { NULL, NULL, 0 },
00793 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER},
00794 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
00795 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
00796 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
00797 /* 0xc4 */ { NULL, NULL, 0 },
00798 /* 0xc5 */ { NULL, NULL, 0 },
00799 /* 0xc6 */ { NULL, NULL, 0 },
00800 /* 0xc7 */ { NULL, NULL, 0 },
00801 /* 0xc8 */ { NULL, NULL, 0 },
00802 /* 0xc9 */ { NULL, NULL, 0 },
00803 /* 0xca */ { NULL, NULL, 0 },
00804 /* 0xcb */ { NULL, NULL, 0 },
00805 /* 0xcc */ { NULL, NULL, 0 },
00806 /* 0xcd */ { NULL, NULL, 0 },
00807 /* 0xce */ { NULL, NULL, 0 },
00808 /* 0xcf */ { NULL, NULL, 0 },
00809 /* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
00810 /* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
00811 /* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
00812 /* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
00813 /* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
00814 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
00815 /* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
00816 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
00817 /* 0xd8 */ { NULL, NULL, 0 },
00818 /* 0xd9 */ { NULL, NULL, 0 },
00819 /* 0xda */ { NULL, NULL, 0 },
00820 /* 0xdb */ { NULL, NULL, 0 },
00821 /* 0xdc */ { NULL, NULL, 0 },
00822 /* 0xdd */ { NULL, NULL, 0 },
00823 /* 0xde */ { NULL, NULL, 0 },
00824 /* 0xdf */ { NULL, NULL, 0 },
00825 /* 0xe0 */ { NULL, NULL, 0 },
00826 /* 0xe1 */ { NULL, NULL, 0 },
00827 /* 0xe2 */ { NULL, NULL, 0 },
00828 /* 0xe3 */ { NULL, NULL, 0 },
00829 /* 0xe4 */ { NULL, NULL, 0 },
00830 /* 0xe5 */ { NULL, NULL, 0 },
00831 /* 0xe6 */ { NULL, NULL, 0 },
00832 /* 0xe7 */ { NULL, NULL, 0 },
00833 /* 0xe8 */ { NULL, NULL, 0 },
00834 /* 0xe9 */ { NULL, NULL, 0 },
00835 /* 0xea */ { NULL, NULL, 0 },
00836 /* 0xeb */ { NULL, NULL, 0 },
00837 /* 0xec */ { NULL, NULL, 0 },
00838 /* 0xed */ { NULL, NULL, 0 },
00839 /* 0xee */ { NULL, NULL, 0 },
00840 /* 0xef */ { NULL, NULL, 0 },
00841 /* 0xf0 */ { NULL, NULL, 0 },
00842 /* 0xf1 */ { NULL, NULL, 0 },
00843 /* 0xf2 */ { NULL, NULL, 0 },
00844 /* 0xf3 */ { NULL, NULL, 0 },
00845 /* 0xf4 */ { NULL, NULL, 0 },
00846 /* 0xf5 */ { NULL, NULL, 0 },
00847 /* 0xf6 */ { NULL, NULL, 0 },
00848 /* 0xf7 */ { NULL, NULL, 0 },
00849 /* 0xf8 */ { NULL, NULL, 0 },
00850 /* 0xf9 */ { NULL, NULL, 0 },
00851 /* 0xfa */ { NULL, NULL, 0 },
00852 /* 0xfb */ { NULL, NULL, 0 },
00853 /* 0xfc */ { NULL, NULL, 0 },
00854 /* 0xfd */ { NULL, NULL, 0 },
00855 /* 0xfe */ { NULL, NULL, 0 },
00856 /* 0xff */ { NULL, NULL, 0 }
00857 
00858 };
00859 
00860 /*******************************************************************
00861  Dump a packet to a file.
00862 ********************************************************************/
00863 
00864 static void smb_dump(const char *name, int type, char *data, ssize_t len)
00865 {
00866         int fd, i;
00867         pstring fname;
00868         if (DEBUGLEVEL < 50) return;
00869 
00870         if (len < 4) len = smb_len(data)+4;
00871         for (i=1;i<100;i++) {
00872                 slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.%s", name, i,
00873                                 type ? "req" : "resp");
00874                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
00875                 if (fd != -1 || errno != EEXIST) break;
00876         }
00877         if (fd != -1) {
00878                 ssize_t ret = write(fd, data, len);
00879                 if (ret != len)
00880                         DEBUG(0,("smb_dump: problem: write returned %d\n", (int)ret ));
00881                 close(fd);
00882                 DEBUG(0,("created %s len %lu\n", fname, (unsigned long)len));
00883         }
00884 }
00885 
00886 
00887 /****************************************************************************
00888  Do a switch on the message type, and return the response size
00889 ****************************************************************************/
00890 
00891 static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize)
00892 {
00893         static pid_t pid= (pid_t)-1;
00894         int outsize = 0;
00895 
00896         type &= 0xff;
00897 
00898         if (pid == (pid_t)-1)
00899                 pid = sys_getpid();
00900 
00901         errno = 0;
00902 
00903         last_message = type;
00904 
00905         /* Make sure this is an SMB packet. smb_size contains NetBIOS header so subtract 4 from it. */
00906         if ((strncmp(smb_base(inbuf),"\377SMB",4) != 0) || (size < (smb_size - 4))) {
00907                 DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",smb_len(inbuf)));
00908                 exit_server_cleanly("Non-SMB packet");
00909                 return(-1);
00910         }
00911 
00912         /* yuck! this is an interim measure before we get rid of our
00913                 current inbuf/outbuf system */
00914         global_smbpid = SVAL(inbuf,smb_pid);
00915 
00916         if (smb_messages[type].fn == NULL) {
00917                 DEBUG(0,("Unknown message type %d!\n",type));
00918                 smb_dump("Unknown", 1, inbuf, size);
00919                 outsize = reply_unknown(inbuf,outbuf);
00920         } else {
00921                 int flags = smb_messages[type].flags;
00922                 static uint16 last_session_tag = UID_FIELD_INVALID;
00923                 /* In share mode security we must ignore the vuid. */
00924                 uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
00925                 connection_struct *conn = conn_find(SVAL(inbuf,smb_tid));
00926 
00927                 DEBUG(3,("switch message %s (pid %d) conn 0x%lx\n",smb_fn_name(type),(int)pid,(unsigned long)conn));
00928 
00929                 smb_dump(smb_fn_name(type), 1, inbuf, size);
00930 
00931                 /* Ensure this value is replaced in the incoming packet. */
00932                 SSVAL(inbuf,smb_uid,session_tag);
00933 
00934                 /*
00935                  * Ensure the correct username is in current_user_info.
00936                  * This is a really ugly bugfix for problems with
00937                  * multiple session_setup_and_X's being done and
00938                  * allowing %U and %G substitutions to work correctly.
00939                  * There is a reason this code is done here, don't
00940                  * move it unless you know what you're doing... :-).
00941                  * JRA.
00942                  */
00943 
00944                 if (session_tag != last_session_tag) {
00945                         user_struct *vuser = NULL;
00946 
00947                         last_session_tag = session_tag;
00948                         if(session_tag != UID_FIELD_INVALID) {
00949                                 vuser = get_valid_user_struct(session_tag);           
00950                                 if (vuser) {
00951                                         set_current_user_info(&vuser->user);
00952                                 }
00953                         }
00954                 }
00955 
00956                 /* Does this call need to be run as the connected user? */
00957                 if (flags & AS_USER) {
00958 
00959                         /* Does this call need a valid tree connection? */
00960                         if (!conn) {
00961                                 /* Amazingly, the error code depends on the command (from Samba4). */
00962                                 if (type == SMBntcreateX) {
00963                                         return ERROR_NT(NT_STATUS_INVALID_HANDLE);
00964                                 } else {
00965                                         return ERROR_DOS(ERRSRV, ERRinvnid);
00966                                 }
00967                         }
00968 
00969                         if (!change_to_user(conn,session_tag)) {
00970                                 return(ERROR_NT(NT_STATUS_DOS(ERRSRV,ERRbaduid)));
00971                         }
00972 
00973                         /* All NEED_WRITE and CAN_IPC flags must also have AS_USER. */
00974 
00975                         /* Does it need write permission? */
00976                         if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) {
00977                                 return ERROR_NT(NT_STATUS_MEDIA_WRITE_PROTECTED);
00978                         }
00979 
00980                         /* IPC services are limited */
00981                         if (IS_IPC(conn) && !(flags & CAN_IPC)) {
00982                                 return(ERROR_DOS(ERRSRV,ERRaccess));
00983                         }
00984                 } else {
00985                         /* This call needs to be run as root */
00986                         change_to_root_user();
00987                 }
00988 
00989                 /* load service specific parameters */
00990                 if (conn) {
00991                         if (!set_current_service(conn,SVAL(inbuf,smb_flg),(flags & (AS_USER|DO_CHDIR)?True:False))) {
00992                                 return(ERROR_DOS(ERRSRV,ERRaccess));
00993                         }
00994                         conn->num_smb_operations++;
00995                 }
00996 
00997                 /* does this protocol need to be run as guest? */
00998                 if ((flags & AS_GUEST) && (!change_to_guest() || 
00999                                 !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) {
01000                         return(ERROR_DOS(ERRSRV,ERRaccess));
01001                 }
01002 
01003                 current_inbuf = inbuf; /* In case we need to defer this message in open... */
01004                 outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize);
01005         }
01006 
01007         smb_dump(smb_fn_name(type), 0, outbuf, outsize);
01008 
01009         return(outsize);
01010 }
01011 
01012 /****************************************************************************
01013  Construct a reply to the incoming packet.
01014 ****************************************************************************/
01015 
01016 static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
01017 {
01018         int type = CVAL(inbuf,smb_com);
01019         int outsize = 0;
01020         int msg_type = CVAL(inbuf,0);
01021 
01022         chain_size = 0;
01023         file_chain_reset();
01024         reset_chain_p();
01025 
01026         if (msg_type != 0)
01027                 return(reply_special(inbuf,outbuf));  
01028 
01029         construct_reply_common(inbuf, outbuf);
01030 
01031         outsize = switch_message(type,inbuf,outbuf,size,bufsize);
01032 
01033         outsize += chain_size;
01034 
01035         if(outsize > 4)
01036                 smb_setlen(outbuf,outsize - 4);
01037         return(outsize);
01038 }
01039 
01040 /****************************************************************************
01041  Process an smb from the client
01042 ****************************************************************************/
01043 
01044 static void process_smb(char *inbuf, char *outbuf)
01045 {
01046         static int trans_num;
01047         int msg_type = CVAL(inbuf,0);
01048         int32 len = smb_len(inbuf);
01049         int nread = len + 4;
01050 
01051         DO_PROFILE_INC(smb_count);
01052 
01053         if (trans_num == 0) {
01054                 /* on the first packet, check the global hosts allow/ hosts
01055                 deny parameters before doing any parsing of the packet
01056                 passed to us by the client.  This prevents attacks on our
01057                 parsing code from hosts not in the hosts allow list */
01058                 if (!check_access(smbd_server_fd(), lp_hostsallow(-1),
01059                                   lp_hostsdeny(-1))) {
01060                         /* send a negative session response "not listening on calling name" */
01061                         static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
01062                         DEBUG( 1, ( "Connection denied from %s\n", client_addr() ) );
01063                         (void)send_smb(smbd_server_fd(),(char *)buf);
01064                         exit_server_cleanly("connection denied");
01065                 }
01066         }
01067 
01068         DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type, len ) );
01069         DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) );
01070 
01071         if (msg_type == 0)
01072                 show_msg(inbuf);
01073         else if(msg_type == SMBkeepalive)
01074                 return; /* Keepalive packet. */
01075 
01076         nread = construct_reply(inbuf,outbuf,nread,max_send);
01077       
01078         if(nread > 0) {
01079                 if (CVAL(outbuf,0) == 0)
01080                         show_msg(outbuf);
01081         
01082                 if (nread != smb_len(outbuf) + 4) {
01083                         DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
01084                                 nread, smb_len(outbuf)));
01085                 } else if (!send_smb(smbd_server_fd(),outbuf)) {
01086                         exit_server_cleanly("process_smb: send_smb failed.");
01087                 }
01088         }
01089         trans_num++;
01090 }
01091 
01092 /****************************************************************************
01093  Return a string containing the function name of a SMB command.
01094 ****************************************************************************/
01095 
01096 const char *smb_fn_name(int type)
01097 {
01098         const char *unknown_name = "SMBunknown";
01099 
01100         if (smb_messages[type].name == NULL)
01101                 return(unknown_name);
01102 
01103         return(smb_messages[type].name);
01104 }
01105 
01106 /****************************************************************************
01107  Helper functions for contruct_reply.
01108 ****************************************************************************/
01109 
01110 static uint32 common_flags2 = FLAGS2_LONG_PATH_COMPONENTS|FLAGS2_32_BIT_ERROR_CODES;
01111 
01112 void add_to_common_flags2(uint32 v)
01113 {
01114         common_flags2 |= v;
01115 }
01116 
01117 void remove_from_common_flags2(uint32 v)
01118 {
01119         common_flags2 &= ~v;
01120 }
01121 
01122 void construct_reply_common(const char *inbuf, char *outbuf)
01123 {
01124         set_message(outbuf,0,0,False);
01125         
01126         SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com));
01127         SIVAL(outbuf,smb_rcls,0);
01128         SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); 
01129         SSVAL(outbuf,smb_flg2,
01130                 (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) |
01131                 common_flags2);
01132         memset(outbuf+smb_pidhigh,'\0',(smb_tid-smb_pidhigh));
01133 
01134         SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
01135         SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
01136         SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
01137         SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));
01138 }
01139 
01140 /****************************************************************************
01141  Construct a chained reply and add it to the already made reply
01142 ****************************************************************************/
01143 
01144 int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
01145 {
01146         static char *orig_inbuf;
01147         static char *orig_outbuf;
01148         int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0);
01149         unsigned smb_off2 = SVAL(inbuf,smb_vwv1);
01150         char *inbuf2, *outbuf2;
01151         int outsize2;
01152         int new_size;
01153         char inbuf_saved[smb_wct];
01154         char outbuf_saved[smb_wct];
01155         int outsize = smb_len(outbuf) + 4;
01156 
01157         /* Maybe its not chained, or it's an error packet. */
01158         if (smb_com2 == 0xFF || SVAL(outbuf,smb_rcls) != 0) {
01159                 SCVAL(outbuf,smb_vwv0,0xFF);
01160                 return outsize;
01161         }
01162 
01163         if (chain_size == 0) {
01164                 /* this is the first part of the chain */
01165                 orig_inbuf = inbuf;
01166                 orig_outbuf = outbuf;
01167         }
01168 
01169         /*
01170          * The original Win95 redirector dies on a reply to
01171          * a lockingX and read chain unless the chain reply is
01172          * 4 byte aligned. JRA.
01173          */
01174 
01175         outsize = (outsize + 3) & ~3;
01176 
01177         /* we need to tell the client where the next part of the reply will be */
01178         SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf));
01179         SCVAL(outbuf,smb_vwv0,smb_com2);
01180 
01181         /* remember how much the caller added to the chain, only counting stuff
01182                 after the parameter words */
01183         chain_size += outsize - smb_wct;
01184 
01185         /* work out pointers into the original packets. The
01186                 headers on these need to be filled in */
01187         inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct;
01188         outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct;
01189 
01190         /* remember the original command type */
01191         smb_com1 = CVAL(orig_inbuf,smb_com);
01192 
01193         /* save the data which will be overwritten by the new headers */
01194         memcpy(inbuf_saved,inbuf2,smb_wct);
01195         memcpy(outbuf_saved,outbuf2,smb_wct);
01196 
01197         /* give the new packet the same header as the last part of the SMB */
01198         memmove(inbuf2,inbuf,smb_wct);
01199 
01200         /* create the in buffer */
01201         SCVAL(inbuf2,smb_com,smb_com2);
01202 
01203         /* work out the new size for the in buffer. */
01204         new_size = size - (inbuf2 - inbuf);
01205         if (new_size < 0) {
01206                 DEBUG(0,("chain_reply: chain packet size incorrect (orig size = %d, "
01207                         "offset = %d)\n",
01208                         size,
01209                         (inbuf2 - inbuf) ));
01210                 exit_server_cleanly("Bad chained packet");
01211                 return(-1);
01212         }
01213 
01214         /* And set it in the header. */
01215         smb_setlen(inbuf2, new_size);
01216 
01217         /* create the out buffer */
01218         construct_reply_common(inbuf2, outbuf2);
01219 
01220         DEBUG(3,("Chained message\n"));
01221         show_msg(inbuf2);
01222 
01223         /* process the request */
01224         outsize2 = switch_message(smb_com2,inbuf2,outbuf2,new_size,
01225                                 bufsize-chain_size);
01226 
01227         /* copy the new reply and request headers over the old ones, but
01228                 preserve the smb_com field */
01229         memmove(orig_outbuf,outbuf2,smb_wct);
01230         SCVAL(orig_outbuf,smb_com,smb_com1);
01231 
01232         /* restore the saved data, being careful not to overwrite any
01233                 data from the reply header */
01234         memcpy(inbuf2,inbuf_saved,smb_wct);
01235 
01236         {
01237                 int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf);
01238                 if (ofs < 0) {
01239                         ofs = 0;
01240                 }
01241                 memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs);
01242         }
01243 
01244         return outsize2;
01245 }
01246 
01247 /****************************************************************************
01248  Setup the needed select timeout in milliseconds.
01249 ****************************************************************************/
01250 
01251 static int setup_select_timeout(void)
01252 {
01253         int select_timeout;
01254 
01255         select_timeout = blocking_locks_timeout_ms(SMBD_SELECT_TIMEOUT*1000);
01256 
01257         if (print_notify_messages_pending()) {
01258                 select_timeout = MIN(select_timeout, 1000);
01259         }
01260 
01261         return select_timeout;
01262 }
01263 
01264 /****************************************************************************
01265  Check if services need reloading.
01266 ****************************************************************************/
01267 
01268 void check_reload(time_t t)
01269 {
01270         static pid_t mypid = 0;
01271         static time_t last_smb_conf_reload_time = 0;
01272         static time_t last_printer_reload_time = 0;
01273         time_t printcap_cache_time = (time_t)lp_printcap_cache_time();
01274 
01275         if(last_smb_conf_reload_time == 0) {
01276                 last_smb_conf_reload_time = t;
01277                 /* Our printing subsystem might not be ready at smbd start up.
01278                    Then no printer is available till the first printers check
01279                    is performed.  A lower initial interval circumvents this. */
01280                 if ( printcap_cache_time > 60 )
01281                         last_printer_reload_time = t - printcap_cache_time + 60;
01282                 else
01283                         last_printer_reload_time = t;
01284         }
01285 
01286         if (mypid != getpid()) { /* First time or fork happened meanwhile */
01287                 /* randomize over 60 second the printcap reload to avoid all
01288                  * process hitting cupsd at the same time */
01289                 int time_range = 60;
01290 
01291                 last_printer_reload_time += random() % time_range;
01292                 mypid = getpid();
01293         }
01294 
01295         if (reload_after_sighup || (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK)) {
01296                 reload_services(True);
01297                 reload_after_sighup = False;
01298                 last_smb_conf_reload_time = t;
01299         }
01300 
01301         /* 'printcap cache time = 0' disable the feature */
01302         
01303         if ( printcap_cache_time != 0 )
01304         { 
01305                 /* see if it's time to reload or if the clock has been set back */
01306                 
01307                 if ( (t >= last_printer_reload_time+printcap_cache_time) 
01308                         || (t-last_printer_reload_time  < 0) ) 
01309                 {
01310                         DEBUG( 3,( "Printcap cache time expired.\n"));
01311                         reload_printers();
01312                         last_printer_reload_time = t;
01313                 }
01314         }
01315 }
01316 
01317 /****************************************************************************
01318  Process any timeout housekeeping. Return False if the caller should exit.
01319 ****************************************************************************/
01320 
01321 static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_timeout_processing_time)
01322 {
01323         static time_t last_keepalive_sent_time = 0;
01324         static time_t last_idle_closed_check = 0;
01325         time_t t;
01326         BOOL allidle = True;
01327 
01328         if (smb_read_error == READ_EOF) {
01329                 DEBUG(3,("timeout_processing: End of file from client (client has disconnected).\n"));
01330                 return False;
01331         }
01332 
01333         if (smb_read_error == READ_ERROR) {
01334                 DEBUG(3,("timeout_processing: receive_smb error (%s) Exiting\n",
01335                         strerror(errno)));
01336                 return False;
01337         }
01338 
01339         if (smb_read_error == READ_BAD_SIG) {
01340                 DEBUG(3,("timeout_processing: receive_smb error bad smb signature. Exiting\n"));
01341                 return False;
01342         }
01343 
01344         *last_timeout_processing_time = t = time(NULL);
01345 
01346         if(last_keepalive_sent_time == 0)
01347                 last_keepalive_sent_time = t;
01348 
01349         if(last_idle_closed_check == 0)
01350                 last_idle_closed_check = t;
01351 
01352         /* become root again if waiting */
01353         change_to_root_user();
01354 
01355         /* run all registered idle events */
01356         smb_run_idle_events(t);
01357 
01358         /* check if we need to reload services */
01359         check_reload(t);
01360 
01361         /* automatic timeout if all connections are closed */      
01362         if (conn_num_open()==0 && (t - last_idle_closed_check) >= IDLE_CLOSED_TIMEOUT) {
01363                 DEBUG( 2, ( "Closing idle connection\n" ) );
01364                 return False;
01365         } else {
01366                 last_idle_closed_check = t;
01367         }
01368 
01369         if (keepalive && (t - last_keepalive_sent_time)>keepalive) {
01370                 if (!send_keepalive(smbd_server_fd())) {
01371                         DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
01372                         return False;
01373                 }
01374 
01375                 /* send a keepalive for a password server or the like.
01376                         This is attached to the auth_info created in the
01377                 negprot */
01378                 if (negprot_global_auth_context && negprot_global_auth_context->challenge_set_method 
01379                                 && negprot_global_auth_context->challenge_set_method->send_keepalive) {
01380 
01381                         negprot_global_auth_context->challenge_set_method->send_keepalive
01382                         (&negprot_global_auth_context->challenge_set_method->private_data);
01383                 }
01384 
01385                 last_keepalive_sent_time = t;
01386         }
01387 
01388         /* check for connection timeouts */
01389         allidle = conn_idle_all(t, deadtime);
01390 
01391         if (allidle && conn_num_open()>0) {
01392                 DEBUG(2,("Closing idle connection 2.\n"));
01393                 return False;
01394         }
01395 
01396         if(global_machine_password_needs_changing && 
01397                         /* for ADS we need to do a regular ADS password change, not a domain
01398                                         password change */
01399                         lp_security() == SEC_DOMAIN) {
01400 
01401                 unsigned char trust_passwd_hash[16];
01402                 time_t lct;
01403 
01404                 /*
01405                  * We're in domain level security, and the code that
01406                  * read the machine password flagged that the machine
01407                  * password needs changing.
01408                  */
01409 
01410                 /*
01411                  * First, open the machine password file with an exclusive lock.
01412                  */
01413 
01414                 if (secrets_lock_trust_account_password(lp_workgroup(), True) == False) {
01415                         DEBUG(0,("process: unable to lock the machine account password for \
01416 machine %s in domain %s.\n", global_myname(), lp_workgroup() ));
01417                         return True;
01418                 }
01419 
01420                 if(!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd_hash, &lct, NULL)) {
01421                         DEBUG(0,("process: unable to read the machine account password for \
01422 machine %s in domain %s.\n", global_myname(), lp_workgroup()));
01423                         secrets_lock_trust_account_password(lp_workgroup(), False);
01424                         return True;
01425                 }
01426 
01427                 /*
01428                  * Make sure someone else hasn't already done this.
01429                  */
01430 
01431                 if(t < lct + lp_machine_password_timeout()) {
01432                         global_machine_password_needs_changing = False;
01433                         secrets_lock_trust_account_password(lp_workgroup(), False);
01434                         return True;
01435                 }
01436 
01437                 /* always just contact the PDC here */
01438     
01439                 change_trust_account_password( lp_workgroup(), NULL);
01440                 global_machine_password_needs_changing = False;
01441                 secrets_lock_trust_account_password(lp_workgroup(), False);
01442         }
01443 
01444         /*
01445          * Check to see if we have any blocking locks
01446          * outstanding on the queue.
01447          */
01448         process_blocking_lock_queue();
01449 
01450         /* update printer queue caches if necessary */
01451   
01452         update_monitored_printq_cache();
01453   
01454         /*
01455          * Now we are root, check if the log files need pruning.
01456          * Force a log file check.
01457          */
01458         force_check_log_size();
01459         check_log_size();
01460 
01461         /* Send any queued printer notify message to interested smbd's. */
01462 
01463         print_notify_send_messages(0);
01464 
01465         /*
01466          * Modify the select timeout depending upon
01467          * what we have remaining in our queues.
01468          */
01469 
01470         *select_timeout = setup_select_timeout();
01471 
01472         return True;
01473 }
01474 
01475 /****************************************************************************
01476  Accessor functions for InBuffer, OutBuffer.
01477 ****************************************************************************/
01478 
01479 char *get_InBuffer(void)
01480 {
01481         return InBuffer;
01482 }
01483 
01484 char *get_OutBuffer(void)
01485 {
01486         return OutBuffer;
01487 }
01488 
01489 const int total_buffer_size = (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN);
01490 
01491 /****************************************************************************
01492  Allocate a new InBuffer. Returns the new and old ones.
01493 ****************************************************************************/
01494 
01495 static char *NewInBuffer(char **old_inbuf)
01496 {
01497         char *new_inbuf = (char *)SMB_MALLOC(total_buffer_size);
01498         if (!new_inbuf) {
01499                 return NULL;
01500         }
01501         if (old_inbuf) {
01502                 *old_inbuf = InBuffer;
01503         }
01504         InBuffer = new_inbuf;
01505 #if defined(DEVELOPER)
01506         clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size);
01507 #endif
01508         return InBuffer;
01509 }
01510 
01511 /****************************************************************************
01512  Allocate a new OutBuffer. Returns the new and old ones.
01513 ****************************************************************************/
01514 
01515 static char *NewOutBuffer(char **old_outbuf)
01516 {
01517         char *new_outbuf = (char *)SMB_MALLOC(total_buffer_size);
01518         if (!new_outbuf) {
01519                 return NULL;
01520         }
01521         if (old_outbuf) {
01522                 *old_outbuf = OutBuffer;
01523         }
01524         OutBuffer = new_outbuf;
01525 #if defined(DEVELOPER)
01526         clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer, total_buffer_size);
01527 #endif
01528         return OutBuffer;
01529 }
01530 
01531 /****************************************************************************
01532  Process commands from the client
01533 ****************************************************************************/
01534 
01535 void smbd_process(void)
01536 {
01537         time_t last_timeout_processing_time = time(NULL);
01538         unsigned int num_smbs = 0;
01539 
01540         /* Allocate the primary Inbut/Output buffers. */
01541 
01542         if ((NewInBuffer(NULL) == NULL) || (NewOutBuffer(NULL) == NULL)) 
01543                 return;
01544 
01545         max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
01546 
01547         while (True) {
01548                 int deadtime = lp_deadtime()*60;
01549                 int select_timeout = setup_select_timeout();
01550                 int num_echos;
01551 
01552                 if (deadtime <= 0)
01553                         deadtime = DEFAULT_SMBD_TIMEOUT;
01554 
01555                 errno = 0;      
01556                 
01557                 /* free up temporary memory */
01558                 lp_TALLOC_FREE();
01559                 main_loop_TALLOC_FREE();
01560 
01561                 /* Did someone ask for immediate checks on things like blocking locks ? */
01562                 if (select_timeout == 0) {
01563                         if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
01564                                 return;
01565                         num_smbs = 0; /* Reset smb counter. */
01566                 }
01567 
01568                 run_events(smbd_event_context(), 0, NULL, NULL);
01569 
01570 #if defined(DEVELOPER)
01571                 clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size);
01572 #endif
01573 
01574                 while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,select_timeout)) {
01575                         if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
01576                                 return;
01577                         num_smbs = 0; /* Reset smb counter. */
01578                 }
01579 
01580                 /*
01581                  * Ensure we do timeout processing if the SMB we just got was
01582                  * only an echo request. This allows us to set the select
01583                  * timeout in 'receive_message_or_smb()' to any value we like
01584                  * without worrying that the client will send echo requests
01585                  * faster than the select timeout, thus starving out the
01586                  * essential processing (change notify, blocking locks) that
01587                  * the timeout code does. JRA.
01588                  */ 
01589                 num_echos = smb_echo_count;
01590 
01591                 clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer, total_buffer_size);
01592 
01593                 process_smb(InBuffer, OutBuffer);
01594 
01595                 if (smb_echo_count != num_echos) {
01596                         if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
01597                                 return;
01598                         num_smbs = 0; /* Reset smb counter. */
01599                 }
01600 
01601                 num_smbs++;
01602 
01603                 /*
01604                  * If we are getting smb requests in a constant stream
01605                  * with no echos, make sure we attempt timeout processing
01606                  * every select_timeout milliseconds - but only check for this
01607                  * every 200 smb requests.
01608                  */
01609                 
01610                 if ((num_smbs % 200) == 0) {
01611                         time_t new_check_time = time(NULL);
01612                         if(new_check_time - last_timeout_processing_time >= (select_timeout/1000)) {
01613                                 if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
01614                                         return;
01615                                 num_smbs = 0; /* Reset smb counter. */
01616                                 last_timeout_processing_time = new_check_time; /* Reset time. */
01617                         }
01618                 }
01619 
01620                 /* The timeout_processing function isn't run nearly
01621                    often enough to implement 'max log size' without
01622                    overrunning the size of the file by many megabytes.
01623                    This is especially true if we are running at debug
01624                    level 10.  Checking every 50 SMBs is a nice
01625                    tradeoff of performance vs log file size overrun. */
01626 
01627                 if ((num_smbs % 50) == 0 && need_to_check_log_size()) {
01628                         change_to_root_user();
01629                         check_log_size();
01630                 }
01631         }
01632 }

Sambaに対してSat Aug 29 21:23:25 2009に生成されました。  doxygen 1.4.7