X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source3%2Fwinbindd%2Fwinbindd.c;h=e4df27b45e6f4bd4a7f7098c00acb324a4ee7579;hb=2238260aa3f85cdb0057dae437f454c8c54d08f7;hp=66271068d26e493e9e622208c6182d87c61ff80c;hpb=27c6eca04c4c1bb40ff36f3a08748e2f45770aa8;p=ira%2Fwip.git diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index 66271068d26..e4df27b45e6 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -24,10 +24,13 @@ #include "includes.h" #include "winbindd.h" +#include "../../nsswitch/libwbclient/wbc_async.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND +static void remove_client(struct winbindd_cli_state *state); + static bool opt_nocache = False; static bool interactive = False; @@ -48,7 +51,7 @@ struct messaging_context *winbind_messaging_context(void) static struct messaging_context *ctx; if (ctx == NULL) { - ctx = messaging_init(NULL, server_id_self(), + ctx = messaging_init(NULL, procid_self(), winbind_event_context()); } if (ctx == NULL) { @@ -138,6 +141,29 @@ static void flush_caches(void) } } +static void flush_caches_noinit(void) +{ + /* + * We need to invalidate cached user list entries on a SIGHUP + * otherwise cached access denied errors due to restrict anonymous + * hang around until the sequence number changes. + * NB + * Skip uninitialized domains when flush cache. + * If domain is not initialized, it means it is never + * used or never become online. look, wcache_invalidate_cache() + * -> get_cache() -> init_dc_connection(). It causes a lot of traffic + * for unused domains and large traffic for primay domain's DC if there + * are many domains.. + */ + + if (!wcache_invalidate_cache_noinit()) { + DEBUG(0, ("invalidating the cache failed; revalidate the cache\n")); + if (!winbindd_cache_validate_and_initialize()) { + exit(1); + } + } +} + /* Handle the signal by unlinking socket and exiting */ static void terminate(bool is_parent) @@ -160,6 +186,8 @@ static void terminate(bool is_parent) trustdom_cache_shutdown(); + gencache_stabilize(); + #if 0 if (interactive) { TALLOC_CTX *mem_ctx = talloc_init("end_description"); @@ -170,6 +198,10 @@ static void terminate(bool is_parent) } #endif + if (is_parent) { + pidfile_unlink(); + } + exit(0); } @@ -245,7 +277,7 @@ static void winbindd_sig_hup_handler(struct tevent_context *ev, const char *file = (const char *)private_data; DEBUG(1,("Reloading services after SIGHUP\n")); - flush_caches(); + flush_caches_noinit(); reload_services_file(file); } @@ -416,32 +448,6 @@ static struct winbindd_dispatch_table { const char *winbindd_cmd_name; } dispatch_table[] = { - /* User functions */ - - { WINBINDD_GETPWNAM, winbindd_getpwnam, "GETPWNAM" }, - { WINBINDD_GETPWUID, winbindd_getpwuid, "GETPWUID" }, - { WINBINDD_GETPWSID, winbindd_getpwsid, "GETPWSID" }, - - { WINBINDD_SETPWENT, winbindd_setpwent, "SETPWENT" }, - { WINBINDD_ENDPWENT, winbindd_endpwent, "ENDPWENT" }, - { WINBINDD_GETPWENT, winbindd_getpwent, "GETPWENT" }, - - { WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" }, - { WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" }, - { WINBINDD_GETUSERDOMGROUPS, winbindd_getuserdomgroups, - "GETUSERDOMGROUPS" }, - { WINBINDD_GETSIDALIASES, winbindd_getsidaliases, - "LOOKUPUSERALIASES" }, - - /* Group functions */ - - { WINBINDD_GETGRNAM, winbindd_getgrnam, "GETGRNAM" }, - { WINBINDD_GETGRGID, winbindd_getgrgid, "GETGRGID" }, - { WINBINDD_SETGRENT, winbindd_setgrent, "SETGRENT" }, - { WINBINDD_ENDGRENT, winbindd_endgrent, "ENDGRENT" }, - { WINBINDD_GETGRENT, winbindd_getgrent, "GETGRENT" }, - { WINBINDD_GETGRLST, winbindd_getgrent, "GETGRLST" }, - /* PAM auth functions */ { WINBINDD_PAM_AUTH, winbindd_pam_auth, "PAM_AUTH" }, @@ -452,34 +458,11 @@ static struct winbindd_dispatch_table { /* Enumeration functions */ - { WINBINDD_LIST_USERS, winbindd_list_users, "LIST_USERS" }, - { WINBINDD_LIST_GROUPS, winbindd_list_groups, "LIST_GROUPS" }, { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains, "LIST_TRUSTDOM" }, - { WINBINDD_SHOW_SEQUENCE, winbindd_show_sequence, "SHOW_SEQUENCE" }, - - /* SID related functions */ - - { WINBINDD_LOOKUPSID, winbindd_lookupsid, "LOOKUPSID" }, - { WINBINDD_LOOKUPNAME, winbindd_lookupname, "LOOKUPNAME" }, - { WINBINDD_LOOKUPRIDS, winbindd_lookuprids, "LOOKUPRIDS" }, - - /* Lookup related functions */ - - { WINBINDD_SID_TO_UID, winbindd_sid_to_uid, "SID_TO_UID" }, - { WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" }, - { WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" }, - { WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" }, - { WINBINDD_ALLOCATE_UID, winbindd_allocate_uid, "ALLOCATE_UID" }, - { WINBINDD_ALLOCATE_GID, winbindd_allocate_gid, "ALLOCATE_GID" }, - { WINBINDD_SET_MAPPING, winbindd_set_mapping, "SET_MAPPING" }, - { WINBINDD_REMOVE_MAPPING, winbindd_remove_mapping, "REMOVE_MAPPING" }, - { WINBINDD_SET_HWM, winbindd_set_hwm, "SET_HWMS" }, /* Miscellaneous */ - { WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" }, - { WINBINDD_PING, winbindd_ping, "PING" }, { WINBINDD_INFO, winbindd_info, "INFO" }, { WINBINDD_INTERFACE_VERSION, winbindd_interface_version, "INTERFACE_VERSION" }, @@ -488,11 +471,10 @@ static struct winbindd_dispatch_table { { WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" }, { WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir, "WINBINDD_PRIV_PIPE_DIR" }, - { WINBINDD_GETDCNAME, winbindd_getdcname, "GETDCNAME" }, - { WINBINDD_DSGETDCNAME, winbindd_dsgetdcname, "DSGETDCNAME" }, /* Credential cache access */ { WINBINDD_CCACHE_NTLMAUTH, winbindd_ccache_ntlm_auth, "NTLMAUTH" }, + { WINBINDD_CCACHE_SAVE, winbindd_ccache_save, "CCACHE_SAVE" }, /* WINS functions */ @@ -504,151 +486,197 @@ static struct winbindd_dispatch_table { { WINBINDD_NUM_CMDS, NULL, "NONE" } }; -static void process_request(struct winbindd_cli_state *state) -{ - struct winbindd_dispatch_table *table = dispatch_table; +struct winbindd_async_dispatch_table { + enum winbindd_cmd cmd; + const char *cmd_name; + struct tevent_req *(*send_req)(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_cli_state *cli, + struct winbindd_request *request); + NTSTATUS (*recv_req)(struct tevent_req *req, + struct winbindd_response *presp); +}; - /* Free response data - we may be interrupted and receive another - command before being able to send this data off. */ +static struct winbindd_async_dispatch_table async_nonpriv_table[] = { + { WINBINDD_PING, "PING", + wb_ping_send, wb_ping_recv }, + { WINBINDD_LOOKUPSID, "LOOKUPSID", + winbindd_lookupsid_send, winbindd_lookupsid_recv }, + { WINBINDD_LOOKUPNAME, "LOOKUPNAME", + winbindd_lookupname_send, winbindd_lookupname_recv }, + { WINBINDD_SID_TO_UID, "SID_TO_UID", + winbindd_sid_to_uid_send, winbindd_sid_to_uid_recv }, + { WINBINDD_SID_TO_GID, "SID_TO_GID", + winbindd_sid_to_gid_send, winbindd_sid_to_gid_recv }, + { WINBINDD_UID_TO_SID, "UID_TO_SID", + winbindd_uid_to_sid_send, winbindd_uid_to_sid_recv }, + { WINBINDD_GID_TO_SID, "GID_TO_SID", + winbindd_gid_to_sid_send, winbindd_gid_to_sid_recv }, + { WINBINDD_GETPWSID, "GETPWSID", + winbindd_getpwsid_send, winbindd_getpwsid_recv }, + { WINBINDD_GETPWNAM, "GETPWNAM", + winbindd_getpwnam_send, winbindd_getpwnam_recv }, + { WINBINDD_GETPWUID, "GETPWUID", + winbindd_getpwuid_send, winbindd_getpwuid_recv }, + { WINBINDD_GETSIDALIASES, "GETSIDALIASES", + winbindd_getsidaliases_send, winbindd_getsidaliases_recv }, + { WINBINDD_GETUSERDOMGROUPS, "GETUSERDOMGROUPS", + winbindd_getuserdomgroups_send, winbindd_getuserdomgroups_recv }, + { WINBINDD_GETGROUPS, "GETGROUPS", + winbindd_getgroups_send, winbindd_getgroups_recv }, + { WINBINDD_SHOW_SEQUENCE, "SHOW_SEQUENCE", + winbindd_show_sequence_send, winbindd_show_sequence_recv }, + { WINBINDD_GETGRGID, "GETGRGID", + winbindd_getgrgid_send, winbindd_getgrgid_recv }, + { WINBINDD_GETGRNAM, "GETGRNAM", + winbindd_getgrnam_send, winbindd_getgrnam_recv }, + { WINBINDD_GETUSERSIDS, "GETUSERSIDS", + winbindd_getusersids_send, winbindd_getusersids_recv }, + { WINBINDD_LOOKUPRIDS, "LOOKUPRIDS", + winbindd_lookuprids_send, winbindd_lookuprids_recv }, + { WINBINDD_SETPWENT, "SETPWENT", + winbindd_setpwent_send, winbindd_setpwent_recv }, + { WINBINDD_GETPWENT, "GETPWENT", + winbindd_getpwent_send, winbindd_getpwent_recv }, + { WINBINDD_ENDPWENT, "ENDPWENT", + winbindd_endpwent_send, winbindd_endpwent_recv }, + { WINBINDD_DSGETDCNAME, "DSGETDCNAME", + winbindd_dsgetdcname_send, winbindd_dsgetdcname_recv }, + { WINBINDD_GETDCNAME, "GETDCNAME", + winbindd_getdcname_send, winbindd_getdcname_recv }, + { WINBINDD_SETGRENT, "SETGRENT", + winbindd_setgrent_send, winbindd_setgrent_recv }, + { WINBINDD_GETGRENT, "GETGRENT", + winbindd_getgrent_send, winbindd_getgrent_recv }, + { WINBINDD_ENDGRENT, "ENDGRENT", + winbindd_endgrent_send, winbindd_endgrent_recv }, + { WINBINDD_LIST_USERS, "LIST_USERS", + winbindd_list_users_send, winbindd_list_users_recv }, + { WINBINDD_LIST_GROUPS, "LIST_GROUPS", + winbindd_list_groups_send, winbindd_list_groups_recv }, + { WINBINDD_CHECK_MACHACC, "CHECK_MACHACC", + winbindd_check_machine_acct_send, winbindd_check_machine_acct_recv }, + { WINBINDD_PING_DC, "PING_DC", + winbindd_ping_dc_send, winbindd_ping_dc_recv }, + + { 0, NULL, NULL, NULL } +}; - SAFE_FREE(state->response.extra_data.data); +static struct winbindd_async_dispatch_table async_priv_table[] = { + { WINBINDD_ALLOCATE_UID, "ALLOCATE_UID", + winbindd_allocate_uid_send, winbindd_allocate_uid_recv }, + { WINBINDD_ALLOCATE_GID, "ALLOCATE_GID", + winbindd_allocate_gid_send, winbindd_allocate_gid_recv }, + { WINBINDD_SET_MAPPING, "SET_MAPPING", + winbindd_set_mapping_send, winbindd_set_mapping_recv }, + { WINBINDD_REMOVE_MAPPING, "SET_MAPPING", + winbindd_remove_mapping_send, winbindd_remove_mapping_recv }, + { WINBINDD_SET_HWM, "SET_HWM", + winbindd_set_hwm_send, winbindd_set_hwm_recv }, + { WINBINDD_CHANGE_MACHACC, "CHANGE_MACHACC", + winbindd_change_machine_acct_send, winbindd_change_machine_acct_recv }, + + { 0, NULL, NULL, NULL } +}; - ZERO_STRUCT(state->response); +static void wb_request_done(struct tevent_req *req); - state->response.result = WINBINDD_PENDING; - state->response.length = sizeof(struct winbindd_response); +static void process_request(struct winbindd_cli_state *state) +{ + struct winbindd_dispatch_table *table = dispatch_table; + struct winbindd_async_dispatch_table *atable; state->mem_ctx = talloc_init("winbind request"); if (state->mem_ctx == NULL) return; /* Remember who asked us. */ - state->pid = state->request.pid; + state->pid = state->request->pid; /* Process command */ - for (table = dispatch_table; table->fn; table++) { - if (state->request.cmd == table->cmd) { - DEBUG(10,("process_request: request fn %s\n", - table->winbindd_cmd_name )); - table->fn(state); + for (atable = async_nonpriv_table; atable->send_req; atable += 1) { + if (state->request->cmd == atable->cmd) { break; } } - if (!table->fn) { - DEBUG(10,("process_request: unknown request fn number %d\n", - (int)state->request.cmd )); - request_error(state); - } -} - -/* - * A list of file descriptors being monitored by select in the main processing - * loop. winbindd_fd_event->handler is called whenever the socket is readable/writable. - */ - -static struct winbindd_fd_event *fd_events = NULL; - -void add_fd_event(struct winbindd_fd_event *ev) -{ - struct winbindd_fd_event *match; - - /* only add unique winbindd_fd_event structs */ - - for (match=fd_events; match; match=match->next ) { -#ifdef DEVELOPER - SMB_ASSERT( match != ev ); -#else - if ( match == ev ) - return; -#endif + if ((atable->send_req == NULL) && state->privileged) { + for (atable = async_priv_table; atable->send_req; + atable += 1) { + if (state->request->cmd == atable->cmd) { + break; + } + } } - DLIST_ADD(fd_events, ev); -} - -void remove_fd_event(struct winbindd_fd_event *ev) -{ - DLIST_REMOVE(fd_events, ev); -} - -/* - * Handler for winbindd_fd_events to complete a read/write request, set up by - * setup_async_read/setup_async_write. - */ - -static void rw_callback(struct winbindd_fd_event *event, int flags) -{ - size_t todo; - ssize_t done = 0; - - todo = event->length - event->done; + if (atable->send_req != NULL) { + struct tevent_req *req; - if (event->flags & EVENT_FD_WRITE) { - SMB_ASSERT(flags == EVENT_FD_WRITE); - done = sys_write(event->fd, - &((char *)event->data)[event->done], - todo); + DEBUG(10, ("process_request: Handling async request %s\n", + atable->cmd_name)); - if (done <= 0) { - event->flags = 0; - event->finished(event->private_data, False); + req = atable->send_req(state->mem_ctx, winbind_event_context(), + state, state->request); + if (req == NULL) { + DEBUG(0, ("process_request: atable->send failed for " + "%s\n", atable->cmd_name)); + request_error(state); return; } + tevent_req_set_callback(req, wb_request_done, state); + state->recv_fn = atable->recv_req; + return; } - if (event->flags & EVENT_FD_READ) { - SMB_ASSERT(flags == EVENT_FD_READ); - done = sys_read(event->fd, &((char *)event->data)[event->done], - todo); + state->response = talloc_zero(state->mem_ctx, + struct winbindd_response); + if (state->response == NULL) { + DEBUG(10, ("talloc failed\n")); + remove_client(state); + return; + } + state->response->result = WINBINDD_PENDING; + state->response->length = sizeof(struct winbindd_response); - if (done <= 0) { - event->flags = 0; - event->finished(event->private_data, False); - return; + for (table = dispatch_table; table->fn; table++) { + if (state->request->cmd == table->cmd) { + DEBUG(10,("process_request: request fn %s\n", + table->winbindd_cmd_name )); + table->fn(state); + break; } } - event->done += done; - - if (event->done == event->length) { - event->flags = 0; - event->finished(event->private_data, True); + if (!table->fn) { + DEBUG(10,("process_request: unknown request fn number %d\n", + (int)state->request->cmd )); + request_error(state); } } -/* - * Request an async read/write on a winbindd_fd_event structure. (*finished) is called - * when the request is completed or an error had occurred. - */ - -void setup_async_read(struct winbindd_fd_event *event, void *data, size_t length, - void (*finished)(void *private_data, bool success), - void *private_data) +static void wb_request_done(struct tevent_req *req) { - SMB_ASSERT(event->flags == 0); - event->data = data; - event->length = length; - event->done = 0; - event->handler = rw_callback; - event->finished = finished; - event->private_data = private_data; - event->flags = EVENT_FD_READ; -} + struct winbindd_cli_state *state = tevent_req_callback_data( + req, struct winbindd_cli_state); + NTSTATUS status; -void setup_async_write(struct winbindd_fd_event *event, void *data, size_t length, - void (*finished)(void *private_data, bool success), - void *private_data) -{ - SMB_ASSERT(event->flags == 0); - event->data = data; - event->length = length; - event->done = 0; - event->handler = rw_callback; - event->finished = finished; - event->private_data = private_data; - event->flags = EVENT_FD_WRITE; + state->response = talloc_zero(state, struct winbindd_response); + if (state->response == NULL) { + remove_client(state); + return; + } + state->response->result = WINBINDD_PENDING; + state->response->length = sizeof(struct winbindd_response); + + status = state->recv_fn(req, state->response); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("returning %s\n", nt_errstr(status))); + request_error(state); + return; + } + request_ok(state); } /* @@ -661,158 +689,78 @@ void setup_async_write(struct winbindd_fd_event *event, void *data, size_t lengt * to call request_finished which schedules sending the response. */ -static void request_len_recv(void *private_data, bool success); -static void request_recv(void *private_data, bool success); -static void request_main_recv(void *private_data, bool success); static void request_finished(struct winbindd_cli_state *state); -static void response_main_sent(void *private_data, bool success); -static void response_extra_sent(void *private_data, bool success); -static void response_extra_sent(void *private_data, bool success) +static void winbind_client_request_read(struct tevent_req *req); +static void winbind_client_response_written(struct tevent_req *req); + +static void request_finished(struct winbindd_cli_state *state) { - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); + struct tevent_req *req; - TALLOC_FREE(state->mem_ctx); + TALLOC_FREE(state->request); - if (!success) { - state->finished = True; + req = wb_resp_write_send(state, winbind_event_context(), + state->out_queue, state->sock, + state->response); + if (req == NULL) { + remove_client(state); return; } - - SAFE_FREE(state->response.extra_data.data); - - setup_async_read(&state->fd_event, &state->request, sizeof(uint32), - request_len_recv, state); + tevent_req_set_callback(req, winbind_client_response_written, state); } -static void response_main_sent(void *private_data, bool success) +static void winbind_client_response_written(struct tevent_req *req) { - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); - - if (!success) { - state->finished = True; + struct winbindd_cli_state *state = tevent_req_callback_data( + req, struct winbindd_cli_state); + ssize_t ret; + int err; + + ret = wb_resp_write_recv(req, &err); + TALLOC_FREE(req); + if (ret == -1) { + close(state->sock); + state->sock = -1; + DEBUG(2, ("Could not write response to client: %s\n", + strerror(err))); + remove_client(state); return; } - if (state->response.length == sizeof(state->response)) { - TALLOC_FREE(state->mem_ctx); + TALLOC_FREE(state->mem_ctx); + state->response = NULL; - setup_async_read(&state->fd_event, &state->request, - sizeof(uint32), request_len_recv, state); + req = wb_req_read_send(state, winbind_event_context(), state->sock, + WINBINDD_MAX_EXTRA_DATA); + if (req == NULL) { + remove_client(state); return; } - - setup_async_write(&state->fd_event, state->response.extra_data.data, - state->response.length - sizeof(state->response), - response_extra_sent, state); -} - -static void request_finished(struct winbindd_cli_state *state) -{ - /* Make sure request.extra_data is freed when finish processing a request */ - SAFE_FREE(state->request.extra_data.data); - setup_async_write(&state->fd_event, &state->response, - sizeof(state->response), response_main_sent, state); + tevent_req_set_callback(req, winbind_client_request_read, state); } void request_error(struct winbindd_cli_state *state) { - SMB_ASSERT(state->response.result == WINBINDD_PENDING); - state->response.result = WINBINDD_ERROR; + SMB_ASSERT(state->response->result == WINBINDD_PENDING); + state->response->result = WINBINDD_ERROR; request_finished(state); } void request_ok(struct winbindd_cli_state *state) { - SMB_ASSERT(state->response.result == WINBINDD_PENDING); - state->response.result = WINBINDD_OK; + SMB_ASSERT(state->response->result == WINBINDD_PENDING); + state->response->result = WINBINDD_OK; request_finished(state); } -static void request_len_recv(void *private_data, bool success) -{ - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); - - if (!success) { - state->finished = True; - return; - } - - if (*(uint32 *)(&state->request) != sizeof(state->request)) { - DEBUG(0,("request_len_recv: Invalid request size received: %d (expected %u)\n", - *(uint32_t *)(&state->request), (uint32_t)sizeof(state->request))); - state->finished = True; - return; - } - - setup_async_read(&state->fd_event, (uint32 *)(&state->request)+1, - sizeof(state->request) - sizeof(uint32), - request_main_recv, state); -} - -static void request_main_recv(void *private_data, bool success) -{ - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); - - if (!success) { - state->finished = True; - return; - } - - if (state->request.extra_len == 0) { - state->request.extra_data.data = NULL; - request_recv(state, True); - return; - } - - if ((!state->privileged) && - (state->request.extra_len > WINBINDD_MAX_EXTRA_DATA)) { - DEBUG(3, ("Got request with %d bytes extra data on " - "unprivileged socket\n", (int)state->request.extra_len)); - state->request.extra_data.data = NULL; - state->finished = True; - return; - } - - state->request.extra_data.data = - SMB_MALLOC_ARRAY(char, state->request.extra_len + 1); - - if (state->request.extra_data.data == NULL) { - DEBUG(0, ("malloc failed\n")); - state->finished = True; - return; - } - - /* Ensure null termination */ - state->request.extra_data.data[state->request.extra_len] = '\0'; - - setup_async_read(&state->fd_event, state->request.extra_data.data, - state->request.extra_len, request_recv, state); -} - -static void request_recv(void *private_data, bool success) -{ - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); - - if (!success) { - state->finished = True; - return; - } - - process_request(state); -} - /* Process a new connection by adding it to the client connection list */ static void new_connection(int listen_sock, bool privileged) { struct sockaddr_un sunaddr; struct winbindd_cli_state *state; + struct tevent_req *req; socklen_t len; int sock; @@ -821,7 +769,8 @@ static void new_connection(int listen_sock, bool privileged) len = sizeof(sunaddr); do { - sock = accept(listen_sock, (struct sockaddr *)&sunaddr, &len); + sock = accept(listen_sock, (struct sockaddr *)(void *)&sunaddr, + &len); } while (sock == -1 && errno == EINTR); if (sock == -1) @@ -838,22 +787,56 @@ static void new_connection(int listen_sock, bool privileged) state->sock = sock; + state->out_queue = tevent_queue_create(state, "winbind client reply"); + if (state->out_queue == NULL) { + close(sock); + TALLOC_FREE(state); + return; + } + state->last_access = time(NULL); state->privileged = privileged; - state->fd_event.fd = state->sock; - state->fd_event.flags = 0; - add_fd_event(&state->fd_event); - - setup_async_read(&state->fd_event, &state->request, sizeof(uint32), - request_len_recv, state); + req = wb_req_read_send(state, winbind_event_context(), state->sock, + WINBINDD_MAX_EXTRA_DATA); + if (req == NULL) { + TALLOC_FREE(state); + close(sock); + return; + } + tevent_req_set_callback(req, winbind_client_request_read, state); /* Add to connection list */ winbindd_add_client(state); } +static void winbind_client_request_read(struct tevent_req *req) +{ + struct winbindd_cli_state *state = tevent_req_callback_data( + req, struct winbindd_cli_state); + ssize_t ret; + int err; + + ret = wb_req_read_recv(req, state, &state->request, &err); + TALLOC_FREE(req); + if (ret == -1) { + if (err == EPIPE) { + DEBUG(6, ("closing socket %d, client exited\n", + state->sock)); + } else { + DEBUG(2, ("Could not read client request from fd %d: " + "%s\n", state->sock, strerror(err))); + } + close(state->sock); + state->sock = -1; + remove_client(state); + return; + } + process_request(state); +} + /* Remove a client connection from client connection list */ static void remove_client(struct winbindd_cli_state *state) @@ -867,31 +850,22 @@ static void remove_client(struct winbindd_cli_state *state) return; } - /* tell client, we are closing ... */ - nwritten = write(state->sock, &c, sizeof(c)); - if (nwritten == -1) { - DEBUG(2, ("final write to client failed: %s\n", - strerror(errno))); - } - - /* Close socket */ - - close(state->sock); - - /* Free any getent state */ - - free_getent_state(state->getpwent_state); - free_getent_state(state->getgrent_state); + if (state->sock != -1) { + /* tell client, we are closing ... */ + nwritten = write(state->sock, &c, sizeof(c)); + if (nwritten == -1) { + DEBUG(2, ("final write to client failed: %s\n", + strerror(errno))); + } - /* We may have some extra data that was not freed if the client was - killed unexpectedly */ + /* Close socket */ - SAFE_FREE(state->response.extra_data.data); + close(state->sock); + state->sock = -1; + } TALLOC_FREE(state->mem_ctx); - remove_fd_event(&state->fd_event); - /* Remove from list and free */ winbindd_remove_client(state); @@ -907,8 +881,8 @@ static bool remove_idle_client(void) int nidle = 0; for (state = winbindd_client_list(); state; state = state->next) { - if (state->response.result != WINBINDD_PENDING && - !state->getpwent_state && !state->getgrent_state) { + if (state->response == NULL && + !state->pwent_state && !state->grent_state) { nidle++; if (!last_access || state->last_access < last_access) { last_access = state->last_access; @@ -930,7 +904,6 @@ static bool remove_idle_client(void) struct winbindd_listen_state { bool privileged; int fd; - struct tevent_fd *fde; }; static void winbindd_listen_fde_handler(struct tevent_context *ev, @@ -955,8 +928,6 @@ static void winbindd_listen_fde_handler(struct tevent_context *ev, break; } } - - /* new, non-privileged connection */ new_connection(s->fd, s->privileged); } @@ -964,6 +935,7 @@ static bool winbindd_setup_listeners(void) { struct winbindd_listen_state *pub_state = NULL; struct winbindd_listen_state *priv_state = NULL; + struct tevent_fd *fde; pub_state = talloc(winbind_event_context(), struct winbindd_listen_state); @@ -977,16 +949,14 @@ static bool winbindd_setup_listeners(void) goto failed; } - pub_state->fde = tevent_add_fd(winbind_event_context(), - pub_state, pub_state->fd, - TEVENT_FD_READ, - winbindd_listen_fde_handler, - pub_state); - if (!pub_state->fde) { + fde = tevent_add_fd(winbind_event_context(), pub_state, pub_state->fd, + TEVENT_FD_READ, winbindd_listen_fde_handler, + pub_state); + if (fde == NULL) { close(pub_state->fd); goto failed; } - tevent_fd_set_auto_close(pub_state->fde); + tevent_fd_set_auto_close(fde); priv_state = talloc(winbind_event_context(), struct winbindd_listen_state); @@ -1000,16 +970,14 @@ static bool winbindd_setup_listeners(void) goto failed; } - priv_state->fde = tevent_add_fd(winbind_event_context(), - priv_state, priv_state->fd, - TEVENT_FD_READ, - winbindd_listen_fde_handler, - priv_state); - if (!priv_state->fde) { + fde = tevent_add_fd(winbind_event_context(), priv_state, + priv_state->fd, TEVENT_FD_READ, + winbindd_listen_fde_handler, priv_state); + if (fde == NULL) { close(priv_state->fd); goto failed; } - tevent_fd_set_auto_close(priv_state->fde); + tevent_fd_set_auto_close(fde); return true; failed: @@ -1018,98 +986,6 @@ failed: return false; } -/* Process incoming clients on listen_sock. We use a tricky non-blocking, - non-forking, non-threaded model which allows us to handle many - simultaneous connections while remaining impervious to many denial of - service attacks. */ - -static void process_loop(void) -{ - struct winbindd_fd_event *ev; - fd_set r_fds, w_fds; - int maxfd = 0, selret; - struct timeval timeout, ev_timeout; - - run_events(winbind_event_context(), 0, NULL, NULL); - - /* Initialise fd lists for select() */ - - FD_ZERO(&r_fds); - FD_ZERO(&w_fds); - - timeout.tv_sec = WINBINDD_ESTABLISH_LOOP; - timeout.tv_usec = 0; - - /* Check for any event timeouts. */ - { - struct timeval now; - GetTimeOfDay(&now); - - event_add_to_select_args(winbind_event_context(), &now, - &r_fds, &w_fds, &ev_timeout, &maxfd); - } - if (get_timed_events_timeout(winbind_event_context(), &ev_timeout)) { - timeout = timeval_min(&timeout, &ev_timeout); - } - - for (ev = fd_events; ev; ev = ev->next) { - if (ev->flags & EVENT_FD_READ) { - FD_SET(ev->fd, &r_fds); - maxfd = MAX(ev->fd, maxfd); - } - if (ev->flags & EVENT_FD_WRITE) { - FD_SET(ev->fd, &w_fds); - maxfd = MAX(ev->fd, maxfd); - } - } - - /* Call select */ - - selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout); - - if (selret == 0) { - goto no_fds_ready; - } - - if (selret == -1) { - if (errno == EINTR) { - goto no_fds_ready; - } - - /* Select error, something is badly wrong */ - - perror("select"); - exit(1); - } - - /* selret > 0 */ - - run_events(winbind_event_context(), selret, &r_fds, &w_fds); - - ev = fd_events; - while (ev != NULL) { - struct winbindd_fd_event *next = ev->next; - int flags = 0; - if (FD_ISSET(ev->fd, &r_fds)) - flags |= EVENT_FD_READ; - if (FD_ISSET(ev->fd, &w_fds)) - flags |= EVENT_FD_WRITE; - if (flags) - ev->handler(ev, flags); - ev = next; - } - - return; - - no_fds_ready: - - run_events(winbind_event_context(), selret, &r_fds, &w_fds); - -#if 0 - winbindd_check_cache_size(time(NULL)); -#endif -} - bool winbindd_use_idmap_cache(void) { return !opt_nocache; @@ -1148,6 +1024,7 @@ int main(int argc, char **argv, char **envp) poptContext pc; int opt; TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_timer *te; /* glibc (?) likes to print "User defined signal 1" and exit if a SIGUSR[12] is received before a handler is installed */ @@ -1308,8 +1185,9 @@ int main(int argc, char **argv, char **envp) * winbindd-specific resources we must free yet. JRA. */ - if (!reinit_after_fork(winbind_messaging_context(), - winbind_event_context(), false)) { + if (!NT_STATUS_IS_OK(reinit_after_fork(winbind_messaging_context(), + winbind_event_context(), + false))) { DEBUG(0,("reinit_after_fork() failed\n")); exit(1); } @@ -1393,32 +1271,24 @@ int main(int argc, char **argv, char **envp) exit(1); } + te = tevent_add_timer(winbind_event_context(), NULL, timeval_zero(), + rescan_trusted_domains, NULL); + if (te == NULL) { + DEBUG(0, ("Could not trigger rescan_trusted_domains()\n")); + exit(1); + } + TALLOC_FREE(frame); /* Loop waiting for requests */ while (1) { - struct winbindd_cli_state *state; - frame = talloc_stackframe(); - /* refresh the trusted domain cache */ - - rescan_trusted_domains(); - - /* Dispose of client connection if it is marked as - finished */ - state = winbindd_client_list(); - while (state) { - struct winbindd_cli_state *next = state->next; - - if (state->finished) { - remove_client(state); - } - - state = next; + if (tevent_loop_once(winbind_event_context()) == -1) { + DEBUG(1, ("tevent_loop_once() failed: %s\n", + strerror(errno))); + return 1; } - process_loop(); - TALLOC_FREE(frame); }