From 80795afb5aab79c16d28cf443da0b2d4e41240e3 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 14 May 2010 16:21:32 +1000 Subject: [PATCH] s3compat-only s3:winbindd Move more parts of winbindd.c into winbindd_event.c This allows another attempt at where to attach s3compat into source3/winbindd Andrew Bartlett Signed-off-by: Stefan Metzmacher --- source3/winbindd/winbindd.c | 337 +---------------------------- source3/winbindd/winbindd_event.c | 347 ++++++++++++++++++++++++++++++ source3/winbindd/winbindd_proto.h | 13 +- source3/winbindd/winbindd_util.c | 2 +- 4 files changed, 365 insertions(+), 334 deletions(-) create mode 100644 source3/winbindd/winbindd_event.c diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index 9c0a1fb921a..97ca4d1cbb8 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -36,9 +36,6 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND -static bool client_is_idle(struct winbindd_cli_state *state); -static void remove_client(struct winbindd_cli_state *state); - static bool opt_nocache = False; static bool interactive = False; @@ -550,7 +547,7 @@ static struct winbindd_async_dispatch_table async_priv_table[] = { static void wb_request_done(struct tevent_req *req); -static void process_request(struct winbindd_cli_state *state) +void wb_process_request(struct winbindd_cli_state *state) { struct winbindd_dispatch_table *table = dispatch_table; struct winbindd_async_dispatch_table *atable; @@ -588,13 +585,13 @@ static void process_request(struct winbindd_cli_state *state) state->cmd_name = atable->cmd_name; state->recv_fn = atable->recv_req; - DEBUG(10, ("process_request: Handling async request %d:%s\n", + DEBUG(10, ("wb_process_request: Handling async request %d:%s\n", (int)state->pid, state->cmd_name)); req = atable->send_req(state->mem_ctx, winbind_event_context(), state, state->request); if (req == NULL) { - DEBUG(0, ("process_request: atable->send failed for " + DEBUG(0, ("wb_process_request: atable->send failed for " "%s\n", atable->cmd_name)); request_error(state); return; @@ -607,7 +604,7 @@ static void process_request(struct winbindd_cli_state *state) struct winbindd_response); if (state->response == NULL) { DEBUG(10, ("talloc failed\n")); - remove_client(state); + winbindd_remove_client(state); return; } state->response->result = WINBINDD_PENDING; @@ -615,7 +612,7 @@ static void process_request(struct winbindd_cli_state *state) for (table = dispatch_table; table->fn; table++) { if (state->request->cmd == table->cmd) { - DEBUG(10,("process_request: request fn %s\n", + DEBUG(10,("wb_process_request: request fn %s\n", table->winbindd_cmd_name )); state->cmd_name = table->winbindd_cmd_name; table->fn(state); @@ -624,7 +621,7 @@ static void process_request(struct winbindd_cli_state *state) } if (!table->fn) { - DEBUG(10,("process_request: unknown request fn number %d\n", + DEBUG(10,("wb_process_request: unknown request fn number %d\n", (int)state->request->cmd )); request_error(state); } @@ -641,7 +638,7 @@ static void wb_request_done(struct tevent_req *req) if (state->response == NULL) { DEBUG(0, ("wb_request_done[%d:%s]: talloc_zero failed - removing client\n", (int)state->pid, state->cmd_name)); - remove_client(state); + winbindd_remove_client(state); return; } state->response->result = WINBINDD_PENDING; @@ -660,74 +657,6 @@ static void wb_request_done(struct tevent_req *req) request_ok(state); } -/* - * This is the main event loop of winbind requests. It goes through a - * state-machine of 3 read/write requests, 4 if you have extra data to send. - * - * An idle winbind client has a read request of 4 bytes outstanding, - * finalizing function is request_len_recv, checking the length. request_recv - * then processes the packet. The processing function then at some point has - * to call request_finished which schedules sending the response. - */ - -static void request_finished(struct winbindd_cli_state *state); - -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 tevent_req *req; - - TALLOC_FREE(state->request); - - req = wb_resp_write_send(state, winbind_event_context(), - state->out_queue, state->sock, - state->response); - if (req == NULL) { - DEBUG(10,("request_finished[%d:%s]: wb_resp_write_send() failed\n", - (int)state->pid, state->cmd_name)); - remove_client(state); - return; - } - tevent_req_set_callback(req, winbind_client_response_written, state); -} - -static void winbind_client_response_written(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_resp_write_recv(req, &err); - TALLOC_FREE(req); - if (ret == -1) { - close(state->sock); - state->sock = -1; - DEBUG(2, ("Could not write response[%d:%s] to client: %s\n", - (int)state->pid, state->cmd_name, strerror(err))); - remove_client(state); - return; - } - - DEBUG(10,("winbind_client_response_written[%d:%s]: delivered response " - "to client\n", (int)state->pid, state->cmd_name)); - - TALLOC_FREE(state->mem_ctx); - state->response = NULL; - state->cmd_name = "no request"; - state->recv_fn = NULL; - - req = wb_req_read_send(state, winbind_event_context(), state->sock, - WINBINDD_MAX_EXTRA_DATA); - if (req == NULL) { - remove_client(state); - return; - } - 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); @@ -742,258 +671,6 @@ void request_ok(struct winbindd_cli_state *state) request_finished(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; - - /* Accept connection */ - - len = sizeof(sunaddr); - - do { - sock = accept(listen_sock, (struct sockaddr *)(void *)&sunaddr, - &len); - } while (sock == -1 && errno == EINTR); - - if (sock == -1) - return; - - DEBUG(6,("accepted socket %d\n", sock)); - - /* Create new connection structure */ - - if ((state = TALLOC_ZERO_P(NULL, struct winbindd_cli_state)) == NULL) { - close(sock); - return; - } - - 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; - - 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) -{ - char c = 0; - int nwritten; - - /* It's a dead client - hold a funeral */ - - if (state == NULL) { - return; - } - - 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))); - } - - /* Close socket */ - - close(state->sock); - state->sock = -1; - } - - TALLOC_FREE(state->mem_ctx); - - /* Remove from list and free */ - - winbindd_remove_client(state); - TALLOC_FREE(state); -} - -/* Is a client idle? */ - -static bool client_is_idle(struct winbindd_cli_state *state) { - return (state->response == NULL && - !state->pwent_state && !state->grent_state); -} - -/* Shutdown client connection which has been idle for the longest time */ - -static bool remove_idle_client(void) -{ - struct winbindd_cli_state *state, *remove_state = NULL; - time_t last_access = 0; - int nidle = 0; - - for (state = winbindd_client_list(); state; state = state->next) { - if (client_is_idle(state)) { - nidle++; - if (!last_access || state->last_access < last_access) { - last_access = state->last_access; - remove_state = state; - } - } - } - - if (remove_state) { - DEBUG(5,("Found %d idle client connections, shutting down sock %d, pid %u\n", - nidle, remove_state->sock, (unsigned int)remove_state->pid)); - remove_client(remove_state); - return True; - } - - return False; -} - -struct winbindd_listen_state { - bool privileged; - int fd; -}; - -static void winbindd_listen_fde_handler(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, - void *private_data) -{ - struct winbindd_listen_state *s = talloc_get_type_abort(private_data, - struct winbindd_listen_state); - - while (winbindd_num_clients() > lp_winbind_max_clients() - 1) { - DEBUG(5,("winbindd: Exceeding %d client " - "connections, removing idle " - "connection.\n", lp_winbind_max_clients())); - if (!remove_idle_client()) { - DEBUG(0,("winbindd: Exceeding %d " - "client connections, no idle " - "connection found\n", - lp_winbind_max_clients())); - break; - } - } - new_connection(s->fd, s->privileged); -} - -/* - * Winbindd socket accessor functions - */ - -const char *get_winbind_pipe_dir(void) -{ - return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR); -} - -char *get_winbind_priv_pipe_dir(void) -{ - return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR); -} - -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); - if (!pub_state) { - goto failed; - } - - pub_state->privileged = false; - pub_state->fd = create_pipe_sock( - get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755); - if (pub_state->fd == -1) { - goto failed; - } - - 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(fde); - - priv_state = talloc(winbind_event_context(), - struct winbindd_listen_state); - if (!priv_state) { - goto failed; - } - - priv_state->privileged = true; - priv_state->fd = create_pipe_sock( - get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750); - if (priv_state->fd == -1) { - goto failed; - } - - 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(fde); - - return true; -failed: - TALLOC_FREE(pub_state); - TALLOC_FREE(priv_state); - return false; -} - bool winbindd_use_idmap_cache(void) { return !opt_nocache; diff --git a/source3/winbindd/winbindd_event.c b/source3/winbindd/winbindd_event.c new file mode 100644 index 00000000000..aa41e33b154 --- /dev/null +++ b/source3/winbindd/winbindd_event.c @@ -0,0 +1,347 @@ +/* + Unix SMB/CIFS implementation. + + Winbind daemon for ntdom nss module + + Copyright (C) by Tim Potter 2000-2002 + Copyright (C) Andrew Tridgell 2002 + Copyright (C) Jelmer Vernooij 2003 + Copyright (C) Volker Lendecke 2004 + Copyright (C) Andrew Bartlett 2010 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "winbindd.h" +#include "../../nsswitch/libwbclient/wbc_async.h" + +/* + * This is the main event loop of winbind requests. It goes through a + * state-machine of 3 read/write requests, 4 if you have extra data to send. + * + * An idle winbind client has a read request of 4 bytes outstanding, + * finalizing function is request_len_recv, checking the length. request_recv + * then processes the packet. The processing function then at some point has + * to call request_finished which schedules sending the response. + */ + +static void winbind_client_request_read(struct tevent_req *req); +static void winbind_client_response_written(struct tevent_req *req); + +void request_finished(struct winbindd_cli_state *state) +{ + struct tevent_req *req; + + TALLOC_FREE(state->request); + + req = wb_resp_write_send(state, winbind_event_context(), + state->out_queue, state->sock, + state->response); + if (req == NULL) { + DEBUG(10,("request_finished[%d:%s]: wb_resp_write_send() failed\n", + (int)state->pid, state->cmd_name)); + winbindd_remove_client(state); + return; + } + tevent_req_set_callback(req, winbind_client_response_written, state); +} + +static void winbind_client_response_written(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_resp_write_recv(req, &err); + TALLOC_FREE(req); + if (ret == -1) { + close(state->sock); + state->sock = -1; + DEBUG(2, ("Could not write response[%d:%s] to client: %s\n", + (int)state->pid, state->cmd_name, strerror(err))); + winbindd_remove_client(state); + return; + } + + DEBUG(10,("winbind_client_response_written[%d:%s]: delivered response " + "to client\n", (int)state->pid, state->cmd_name)); + + TALLOC_FREE(state->mem_ctx); + state->response = NULL; + state->cmd_name = "no request"; + state->recv_fn = NULL; + + req = wb_req_read_send(state, winbind_event_context(), state->sock, + WINBINDD_MAX_EXTRA_DATA); + if (req == NULL) { + winbindd_remove_client(state); + return; + } + tevent_req_set_callback(req, winbind_client_request_read, 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; + + /* Accept connection */ + + len = sizeof(sunaddr); + + do { + sock = accept(listen_sock, (struct sockaddr *)(void *)&sunaddr, + &len); + } while (sock == -1 && errno == EINTR); + + if (sock == -1) + return; + + DEBUG(6,("accepted socket %d\n", sock)); + + /* Create new connection structure */ + + if ((state = TALLOC_ZERO_P(NULL, struct winbindd_cli_state)) == NULL) { + close(sock); + return; + } + + 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; + + 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; + winbindd_remove_client(state); + return; + } + wb_process_request(state); +} + +/* Remove a client connection from client connection list */ + +void winbindd_remove_client(struct winbindd_cli_state *state) +{ + char c = 0; + int nwritten; + + /* It's a dead client - hold a funeral */ + + if (state == NULL) { + return; + } + + 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))); + } + + /* Close socket */ + + close(state->sock); + state->sock = -1; + } + + TALLOC_FREE(state->mem_ctx); + + /* Remove from list and free */ + + winbindd_remove_client_from_list(state); + TALLOC_FREE(state); +} + +/* Is a client idle? */ + +bool client_is_idle(struct winbindd_cli_state *state) { + return (state->response == NULL && + !state->pwent_state && !state->grent_state); +} + +/* Shutdown client connection which has been idle for the longest time */ + +static bool remove_idle_client(void) +{ + struct winbindd_cli_state *state, *remove_state = NULL; + time_t last_access = 0; + int nidle = 0; + + for (state = winbindd_client_list(); state; state = state->next) { + if (client_is_idle(state)) { + nidle++; + if (!last_access || state->last_access < last_access) { + last_access = state->last_access; + remove_state = state; + } + } + } + + if (remove_state) { + DEBUG(5,("Found %d idle client connections, shutting down sock %d, pid %u\n", + nidle, remove_state->sock, (unsigned int)remove_state->pid)); + winbindd_remove_client(remove_state); + return True; + } + + return False; +} + +struct winbindd_listen_state { + bool privileged; + int fd; +}; + +static void winbindd_listen_fde_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, + void *private_data) +{ + struct winbindd_listen_state *s = talloc_get_type_abort(private_data, + struct winbindd_listen_state); + + while (winbindd_num_clients() > lp_winbind_max_clients() - 1) { + DEBUG(5,("winbindd: Exceeding %d client " + "connections, removing idle " + "connection.\n", lp_winbind_max_clients())); + if (!remove_idle_client()) { + DEBUG(0,("winbindd: Exceeding %d " + "client connections, no idle " + "connection found\n", + lp_winbind_max_clients())); + break; + } + } + new_connection(s->fd, s->privileged); +} + +/* + * Winbindd socket accessor functions + */ + +const char *get_winbind_pipe_dir(void) +{ + return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR); +} + +char *get_winbind_priv_pipe_dir(void) +{ + return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR); +} + +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); + if (!pub_state) { + goto failed; + } + + pub_state->privileged = false; + pub_state->fd = create_pipe_sock( + get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755); + if (pub_state->fd == -1) { + goto failed; + } + + 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(fde); + + priv_state = talloc(winbind_event_context(), + struct winbindd_listen_state); + if (!priv_state) { + goto failed; + } + + priv_state->privileged = true; + priv_state->fd = create_pipe_sock( + get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750); + if (priv_state->fd == -1) { + goto failed; + } + + 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(fde); + + return true; +failed: + TALLOC_FREE(pub_state); + TALLOC_FREE(priv_state); + return false; +} + diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index f43c08f4171..55dbd54ae88 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -40,8 +40,17 @@ void debug_nt_user_token(int dbg_class, int dbg_lev, struct security_token *toke void debug_unix_user_token(int dbg_class, int dbg_lev, uid_t uid, gid_t gid, int n_groups, gid_t *groups); +/* The following definitions come from winbindd/winbindd_event.c */ +const char *get_winbind_pipe_dir(void); +char *get_winbind_priv_pipe_dir(void); +bool winbindd_setup_listeners(void); +void request_finished(struct winbindd_cli_state *state); +void winbindd_remove_client(struct winbindd_cli_state *state); +bool client_is_idle(struct winbindd_cli_state *state); + /* The following definitions come from winbindd/winbindd.c */ struct messaging_context *winbind_messaging_context(void); +void wb_process_request(struct winbindd_cli_state *state); void request_error(struct winbindd_cli_state *state); void request_ok(struct winbindd_cli_state *state); bool winbindd_setup_sig_term_handler(bool parent); @@ -49,8 +58,6 @@ bool winbindd_setup_sig_hup_handler(const char *lfile); bool winbindd_use_idmap_cache(void); bool winbindd_use_cache(void); void winbindd_register_handlers(void); -const char *get_winbind_pipe_dir(void); -char *get_winbind_priv_pipe_dir(void); int main(int argc, char **argv, char **envp); /* The following definitions come from winbindd/winbindd_ads.c */ @@ -402,7 +409,7 @@ char *fill_domain_username_talloc(TALLOC_CTX *ctx, bool can_assume); struct winbindd_cli_state *winbindd_client_list(void); void winbindd_add_client(struct winbindd_cli_state *cli); -void winbindd_remove_client(struct winbindd_cli_state *cli); +void winbindd_remove_client_from_list(struct winbindd_cli_state *cli); int winbindd_num_clients(void); NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index 14be0e26fa2..5a4f55cd6fa 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -1051,7 +1051,7 @@ void winbindd_add_client(struct winbindd_cli_state *cli) /* Remove a client from the list */ -void winbindd_remove_client(struct winbindd_cli_state *cli) +void winbindd_remove_client_from_list(struct winbindd_cli_state *cli) { DLIST_REMOVE(_client_list, cli); _num_clients--; -- 2.34.1