From f6c883b4b00f4cd751cd312a27bddffb3be9c059 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 3 Oct 2008 14:18:35 -0700 Subject: Simply our main loop processing. A lot :-). Correctly use events for all the previous "special" cases. A step on the way to adding signals to the events and being able to merge the S3 event system with the S4 one. Jeremy. --- source3/auth/auth_domain.c | 65 +++++++++++++++ source3/include/proto.h | 3 +- source3/lib/dummysmbd.c | 15 ++++ source3/printing/notify.c | 26 ++++++ source3/smbd/process.c | 193 +++------------------------------------------ source3/smbd/reply.c | 3 - source3/smbd/server.c | 31 ++++++++ 7 files changed, 148 insertions(+), 188 deletions(-) diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c index c25e62ab80..f11dbe60ee 100644 --- a/source3/auth/auth_domain.c +++ b/source3/auth/auth_domain.c @@ -26,6 +26,71 @@ extern bool global_machine_password_needs_changing; static struct named_mutex *mutex; +/* + * Change machine password (called from main loop + * idle timeout. Must be done as root. + */ + +void attempt_machine_password_change(void) +{ + unsigned char trust_passwd_hash[16]; + time_t lct; + void *lock; + + if (!global_machine_password_needs_changing) { + return; + } + + if (lp_security() != SEC_DOMAIN) { + return; + } + + /* + * We're in domain level security, and the code that + * read the machine password flagged that the machine + * password needs changing. + */ + + /* + * First, open the machine password file with an exclusive lock. + */ + + lock = secrets_get_trust_account_lock(NULL, lp_workgroup()); + + if (lock == NULL) { + DEBUG(0,("attempt_machine_password_change: unable to lock " + "the machine account password for machine %s in " + "domain %s.\n", + global_myname(), lp_workgroup() )); + return; + } + + if(!secrets_fetch_trust_account_password(lp_workgroup(), + trust_passwd_hash, &lct, NULL)) { + DEBUG(0,("attempt_machine_password_change: unable to read the " + "machine account password for %s in domain %s.\n", + global_myname(), lp_workgroup())); + TALLOC_FREE(lock); + return; + } + + /* + * Make sure someone else hasn't already done this. + */ + + if(time(NULL) < lct + lp_machine_password_timeout()) { + global_machine_password_needs_changing = false; + TALLOC_FREE(lock); + return; + } + + /* always just contact the PDC here */ + + change_trust_account_password( lp_workgroup(), NULL); + global_machine_password_needs_changing = false; + TALLOC_FREE(lock); +} + /** * Connect to a remote server for (inter)domain security authenticaion. * diff --git a/source3/include/proto.h b/source3/include/proto.h index 2ccf3b15f7..6799106217 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -43,7 +43,8 @@ bool password_ok(const char *smb_name, DATA_BLOB password_blob); /* The following definitions come from auth/auth_domain.c */ -NTSTATUS auth_domain_init(void) ; +void attempt_machine_password_change(void); +NTSTATUS auth_domain_init(void); /* The following definitions come from auth/auth_ntlmssp.c */ diff --git a/source3/lib/dummysmbd.c b/source3/lib/dummysmbd.c index dbe886e3d1..5c624bdebf 100644 --- a/source3/lib/dummysmbd.c +++ b/source3/lib/dummysmbd.c @@ -51,3 +51,18 @@ NTSTATUS can_delete_directory(struct connection_struct *conn, { return NT_STATUS_OK; } + +bool change_to_root_user(void) +{ + return false; +} + +struct event_context *smbd_event_context(void) +{ + return NULL; +} + +struct messaging_context *smbd_messaging_context(void) +{ + return NULL; +} diff --git a/source3/printing/notify.c b/source3/printing/notify.c index 23df17c389..f6599c413d 100644 --- a/source3/printing/notify.c +++ b/source3/printing/notify.c @@ -34,6 +34,7 @@ static struct notify_queue { size_t buflen; } *notify_queue_head = NULL; +static struct timed_event *notify_event; static bool create_send_ctx(void) { @@ -214,6 +215,22 @@ void print_notify_send_messages(struct messaging_context *msg_ctx, num_messages = 0; } +/******************************************************************* + Event handler to send the messages. +*******************************************************************/ + +static void print_notify_event_send_messages(struct event_context *event_ctx, + struct timed_event *te, + const struct timeval *now, + void *private_data) +{ + /* Remove this timed event handler. */ + TALLOC_FREE(notify_event); + + change_to_root_user(); + print_notify_send_messages(smbd_messaging_context(), 0); +} + /********************************************************************** deep copy a SPOOLSS_NOTIFY_MSG structure using a TALLOC_CTX *********************************************************************/ @@ -304,6 +321,15 @@ to notify_queue_head\n", msg->type, msg->field, msg->printer)); DLIST_ADD_END(notify_queue_head, pnqueue, struct notify_queue *); num_messages++; + + if (smbd_event_context()) { + /* Add an event for 1 second's time to send this queue. */ + notify_event = event_add_timed(smbd_event_context(), NULL, + timeval_current_ofs(1,0), + "print_notify", + print_notify_event_send_messages, NULL); + } + } static void send_notify_field_values(const char *sharename, uint32 type, diff --git a/source3/smbd/process.c b/source3/smbd/process.c index b2d19e11e3..32629fd392 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -706,7 +706,7 @@ The timeout is in milliseconds ****************************************************************************/ static NTSTATUS receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer, - size_t *buffer_len, int timeout, + size_t *buffer_len, size_t *p_unread, bool *p_encrypted) { fd_set r_fds, w_fds; @@ -720,13 +720,8 @@ static NTSTATUS receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer, again: - if (timeout >= 0) { - to.tv_sec = timeout / 1000; - to.tv_usec = (timeout % 1000) * 1000; - } else { - to.tv_sec = SMBD_SELECT_TIMEOUT; - to.tv_usec = 0; - } + to.tv_sec = SMBD_SELECT_TIMEOUT; + to.tv_usec = 0; /* * Note that this call must be before processing any SMB @@ -869,7 +864,7 @@ static NTSTATUS receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer, /* Did we timeout ? */ if (selrtn == 0) { - return NT_STATUS_IO_TIMEOUT; + goto again; } /* @@ -1836,23 +1831,6 @@ void chain_reply(struct smb_request *req) return; } -/**************************************************************************** - Setup the needed select timeout in milliseconds. -****************************************************************************/ - -static int setup_select_timeout(void) -{ - int select_timeout; - - select_timeout = SMBD_SELECT_TIMEOUT*1000; - - if (print_notify_messages_pending()) { - select_timeout = MIN(select_timeout, 1000); - } - - return select_timeout; -} - /**************************************************************************** Check if services need reloading. ****************************************************************************/ @@ -1906,114 +1884,19 @@ void check_reload(time_t t) } } -/**************************************************************************** - Process any timeout housekeeping. Return False if the caller should exit. -****************************************************************************/ - -static void timeout_processing(int *select_timeout, - time_t *last_timeout_processing_time) -{ - time_t t; - - *last_timeout_processing_time = t = time(NULL); - - /* become root again if waiting */ - change_to_root_user(); - - /* check if we need to reload services */ - check_reload(t); - - if(global_machine_password_needs_changing && - /* for ADS we need to do a regular ADS password change, not a domain - password change */ - lp_security() == SEC_DOMAIN) { - - unsigned char trust_passwd_hash[16]; - time_t lct; - void *lock; - - /* - * We're in domain level security, and the code that - * read the machine password flagged that the machine - * password needs changing. - */ - - /* - * First, open the machine password file with an exclusive lock. - */ - - lock = secrets_get_trust_account_lock(NULL, lp_workgroup()); - - if (lock == NULL) { - DEBUG(0,("process: unable to lock the machine account password for \ -machine %s in domain %s.\n", global_myname(), lp_workgroup() )); - return; - } - - if(!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd_hash, &lct, NULL)) { - DEBUG(0,("process: unable to read the machine account password for \ -machine %s in domain %s.\n", global_myname(), lp_workgroup())); - TALLOC_FREE(lock); - return; - } - - /* - * Make sure someone else hasn't already done this. - */ - - if(t < lct + lp_machine_password_timeout()) { - global_machine_password_needs_changing = False; - TALLOC_FREE(lock); - return; - } - - /* always just contact the PDC here */ - - change_trust_account_password( lp_workgroup(), NULL); - global_machine_password_needs_changing = False; - TALLOC_FREE(lock); - } - - /* update printer queue caches if necessary */ - - update_monitored_printq_cache(); - - /* - * Now we are root, check if the log files need pruning. - * Force a log file check. - */ - force_check_log_size(); - check_log_size(); - - /* Send any queued printer notify message to interested smbd's. */ - - print_notify_send_messages(smbd_messaging_context(), 0); - - /* - * Modify the select timeout depending upon - * what we have remaining in our queues. - */ - - *select_timeout = setup_select_timeout(); - - return; -} - /**************************************************************************** Process commands from the client ****************************************************************************/ void smbd_process(void) { - time_t last_timeout_processing_time = time(NULL); unsigned int num_smbs = 0; size_t unread_bytes = 0; max_recv = MIN(lp_maxxmit(),BUFFER_SIZE); while (True) { - int select_timeout = setup_select_timeout(); - int num_echos; + NTSTATUS status; char *inbuf = NULL; size_t inbuf_len = 0; bool encrypted = false; @@ -2021,82 +1904,24 @@ void smbd_process(void) errno = 0; - /* Did someone ask for immediate checks on things like blocking locks ? */ - if (select_timeout == 0) { - timeout_processing(&select_timeout, - &last_timeout_processing_time); - num_smbs = 0; /* Reset smb counter. */ - } - run_events(smbd_event_context(), 0, NULL, NULL); - while (True) { - NTSTATUS status; - - status = receive_message_or_smb( - talloc_tos(), &inbuf, &inbuf_len, - select_timeout, &unread_bytes, &encrypted); - - if (NT_STATUS_IS_OK(status)) { - break; - } - - if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { - timeout_processing( - &select_timeout, - &last_timeout_processing_time); - continue; - } + status = receive_message_or_smb( + talloc_tos(), &inbuf, &inbuf_len, + &unread_bytes, &encrypted); + if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("receive_message_or_smb failed: %s, " "exiting\n", nt_errstr(status))); return; - - num_smbs = 0; /* Reset smb counter. */ } - - /* - * Ensure we do timeout processing if the SMB we just got was - * only an echo request. This allows us to set the select - * timeout in 'receive_message_or_smb()' to any value we like - * without worrying that the client will send echo requests - * faster than the select timeout, thus starving out the - * essential processing (change notify, blocking locks) that - * the timeout code does. JRA. - */ - num_echos = smb_echo_count; - process_smb(inbuf, inbuf_len, unread_bytes, encrypted); TALLOC_FREE(inbuf); - if (smb_echo_count != num_echos) { - timeout_processing(&select_timeout, - &last_timeout_processing_time); - num_smbs = 0; /* Reset smb counter. */ - } - num_smbs++; - /* - * If we are getting smb requests in a constant stream - * with no echos, make sure we attempt timeout processing - * every select_timeout milliseconds - but only check for this - * every 200 smb requests. - */ - - if ((num_smbs % 200) == 0) { - time_t new_check_time = time(NULL); - if(new_check_time - last_timeout_processing_time >= (select_timeout/1000)) { - timeout_processing( - &select_timeout, - &last_timeout_processing_time); - num_smbs = 0; /* Reset smb counter. */ - last_timeout_processing_time = new_check_time; /* Reset time. */ - } - } - /* The timeout_processing function isn't run nearly often enough to implement 'max log size' without overrunning the size of the file by many megabytes. diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 8bfa28faea..0226d314f7 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -29,7 +29,6 @@ /* look in server.c for some explanation of these variables */ extern enum protocol_types Protocol; extern int max_recv; -unsigned int smb_echo_count = 0; extern uint32 global_client_caps; extern bool global_encrypted_passwords_negotiated; @@ -4611,8 +4610,6 @@ void reply_echo(struct smb_request *req) TALLOC_FREE(req->outbuf); - smb_echo_count++; - END_PROFILE(SMBecho); return; } diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 53116f3d98..69a483e4fc 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -1067,6 +1067,30 @@ static bool deadtime_fn(const struct timeval *now, void *private_data) return True; } +/* + * Do the recurring log file and smb.conf reload checks. + */ + +static bool housekeeping_fn(const struct timeval *now, void *private_data) +{ + change_to_root_user(); + + /* update printer queue caches if necessary */ + update_monitored_printq_cache(); + + /* check if we need to reload services */ + check_reload(time(NULL)); + + /* Change machine password if neccessary. */ + attempt_machine_password_change(); + + /* + * Force a log file check. + */ + force_check_log_size(); + check_log_size(); + return true; +} /**************************************************************************** main program. @@ -1426,6 +1450,13 @@ extern void build_options(bool screen); exit(1); } + if (!(event_add_idle(smbd_event_context(), NULL, + timeval_set(SMBD_SELECT_TIMEOUT, 0), + "housekeeping", housekeeping_fn, NULL))) { + DEBUG(0, ("Could not add housekeeping event\n")); + exit(1); + } + #ifdef CLUSTER_SUPPORT if (lp_clustering()) { -- cgit