X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fwinbindd%2Fwinbindd_dual.c;h=993166d82d91991646effe62e11a625b027eaefb;hb=b4384b7f0ecf3b47dd60acaf77636b679e3adc05;hp=931ec6787a72c24e8b803d1f4420abbf413412cc;hpb=10f0c785c70b89e76f3a9cd3b319262affc9447e;p=samba.git diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 931ec6787a7..993166d82d9 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -29,54 +29,56 @@ #include "includes.h" #include "winbindd.h" -#include "../../nsswitch/libwbclient/wbc_async.h" -#include "librpc/gen_ndr/messaging.h" +#include "rpc_client/rpc_client.h" +#include "nsswitch/wb_reqtrans.h" #include "secrets.h" +#include "../lib/util/select.h" +#include "../libcli/security/security.h" +#include "system/select.h" +#include "messages.h" +#include "../lib/util/tevent_unix.h" +#include "lib/param/loadparm.h" +#include "lib/util/sys_rw.h" +#include "lib/util/sys_rw_data.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND extern bool override_logfile; -extern struct winbindd_methods cache_methods; + +static struct winbindd_child *winbindd_children = NULL; /* Read some data from a client connection */ -static NTSTATUS child_read_request(struct winbindd_cli_state *state) +static NTSTATUS child_read_request(int sock, struct winbindd_request *wreq) { NTSTATUS status; - /* Read data */ - - status = read_data(state->sock, (char *)state->request, - sizeof(*state->request)); - + status = read_data_ntstatus(sock, (char *)wreq, sizeof(*wreq)); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("child_read_request: read_data failed: %s\n", nt_errstr(status))); return status; } - if (state->request->extra_len == 0) { - state->request->extra_data.data = NULL; + if (wreq->extra_len == 0) { + wreq->extra_data.data = NULL; return NT_STATUS_OK; } - DEBUG(10, ("Need to read %d extra bytes\n", (int)state->request->extra_len)); - - state->request->extra_data.data = - SMB_MALLOC_ARRAY(char, state->request->extra_len + 1); + DEBUG(10, ("Need to read %d extra bytes\n", (int)wreq->extra_len)); - if (state->request->extra_data.data == NULL) { + wreq->extra_data.data = SMB_MALLOC_ARRAY(char, wreq->extra_len + 1); + if (wreq->extra_data.data == NULL) { DEBUG(0, ("malloc failed\n")); return NT_STATUS_NO_MEMORY; } /* Ensure null termination */ - state->request->extra_data.data[state->request->extra_len] = '\0'; - - status= read_data(state->sock, state->request->extra_data.data, - state->request->extra_len); + wreq->extra_data.data[wreq->extra_len] = '\0'; + status = read_data_ntstatus(sock, wreq->extra_data.data, + wreq->extra_len); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Could not read extra data: %s\n", nt_errstr(status))); @@ -84,6 +86,31 @@ static NTSTATUS child_read_request(struct winbindd_cli_state *state) return status; } +static NTSTATUS child_write_response(int sock, struct winbindd_response *wrsp) +{ + struct iovec iov[2]; + int iov_count; + + iov[0].iov_base = (void *)wrsp; + iov[0].iov_len = sizeof(struct winbindd_response); + iov_count = 1; + + if (wrsp->length > sizeof(struct winbindd_response)) { + iov[1].iov_base = (void *)wrsp->extra_data.data; + iov[1].iov_len = wrsp->length-iov[0].iov_len; + iov_count = 2; + } + + DEBUG(10, ("Writing %d bytes to parent\n", (int)wrsp->length)); + + if (write_data_iov(sock, iov, iov_count) != wrsp->length) { + DEBUG(0, ("Could not write result\n")); + return NT_STATUS_INVALID_HANDLE; + } + + return NT_STATUS_OK; +} + /* * Do winbind child async request. This is not simply wb_simple_trans. We have * to do the queueing ourselves because while a request is queued, the child @@ -92,6 +119,7 @@ static NTSTATUS child_read_request(struct winbindd_cli_state *state) struct wb_child_request_state { struct tevent_context *ev; + struct tevent_req *subreq; struct winbindd_child *child; struct winbindd_request *request; struct winbindd_response *response; @@ -103,6 +131,9 @@ static void wb_child_request_trigger(struct tevent_req *req, void *private_data); static void wb_child_request_done(struct tevent_req *subreq); +static void wb_child_request_cleanup(struct tevent_req *req, + enum tevent_req_state req_state); + struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct winbindd_child *child, @@ -123,9 +154,12 @@ struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx, if (!tevent_queue_add(child->queue, ev, req, wb_child_request_trigger, NULL)) { - tevent_req_nomem(NULL, req); + tevent_req_oom(req); return tevent_req_post(req, ev); } + + tevent_req_set_cleanup_fn(req, wb_child_request_cleanup); + return req; } @@ -136,23 +170,20 @@ static void wb_child_request_trigger(struct tevent_req *req, req, struct wb_child_request_state); struct tevent_req *subreq; - if ((state->child->pid == 0) && (!fork_domain_child(state->child))) { + if ((state->child->sock == -1) && (!fork_domain_child(state->child))) { tevent_req_error(req, errno); return; } - subreq = wb_simple_trans_send(state, winbind_event_context(), NULL, + subreq = wb_simple_trans_send(state, server_event_context(), NULL, state->child->sock, state->request); if (tevent_req_nomem(subreq, req)) { return; } - tevent_req_set_callback(subreq, wb_child_request_done, req); - if (!tevent_req_set_endtime(req, state->ev, - timeval_current_ofs(300, 0))) { - tevent_req_nomem(NULL, req); - return; - } + state->subreq = subreq; + tevent_req_set_callback(subreq, wb_child_request_done, req); + tevent_req_set_endtime(req, state->ev, timeval_current_ofs(300, 0)); } static void wb_child_request_done(struct tevent_req *subreq) @@ -164,7 +195,10 @@ static void wb_child_request_done(struct tevent_req *subreq) int ret, err; ret = wb_simple_trans_recv(subreq, state, &state->response, &err); - TALLOC_FREE(subreq); + /* Freeing the subrequest is deferred until the cleanup function, + * which has to know whether a subrequest exists, and consequently + * decide whether to shut down the pipe to the child process. + */ if (ret == -1) { tevent_req_error(req, err); return; @@ -185,9 +219,74 @@ int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, return 0; } +static void wb_child_request_cleanup(struct tevent_req *req, + enum tevent_req_state req_state) +{ + struct wb_child_request_state *state = + tevent_req_data(req, struct wb_child_request_state); + + if (state->subreq == NULL) { + /* nothing to cleanup */ + return; + } + + TALLOC_FREE(state->subreq); + + if (req_state == TEVENT_REQ_DONE) { + /* transmitted request and got response */ + return; + } + + /* + * Failed to transmit and receive response, or request + * cancelled while being serviced. + * The basic parent/child communication broke, close + * our socket + */ + close(state->child->sock); + state->child->sock = -1; + DLIST_REMOVE(winbindd_children, state->child); +} + +struct winbindd_child *choose_domain_child(struct winbindd_domain *domain) +{ + struct winbindd_child *shortest = &domain->children[0]; + struct winbindd_child *current; + int i; + + for (i=0; ichildren[i]; + current_len = tevent_queue_length(current->queue); + + if (current_len == 0) { + /* idle child */ + return current; + } + + shortest_len = tevent_queue_length(shortest->queue); + + if (current_len < shortest_len) { + shortest = current; + } + } + + return shortest; +} + +struct dcerpc_binding_handle *dom_child_handle(struct winbindd_domain *domain) +{ + struct winbindd_child *child; + + child = choose_domain_child(domain); + return child->binding_handle; +} + struct wb_domain_request_state { struct tevent_context *ev; struct winbindd_domain *domain; + struct winbindd_child *child; struct winbindd_request *request; struct winbindd_request *init_req; struct winbindd_response *response; @@ -211,8 +310,10 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx, return NULL; } + state->child = choose_domain_child(domain); + if (domain->initialized) { - subreq = wb_child_request_send(state, ev, &domain->child, + subreq = wb_child_request_send(state, ev, state->child, request); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); @@ -234,11 +335,10 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx, /* The primary domain has to find the DC name itself */ state->init_req->cmd = WINBINDD_INIT_CONNECTION; fstrcpy(state->init_req->domain_name, domain->name); - state->init_req->data.init_conn.is_primary = - domain->primary ? true : false; + state->init_req->data.init_conn.is_primary = domain->primary; fstrcpy(state->init_req->data.init_conn.dcname, ""); - subreq = wb_child_request_send(state, ev, &domain->child, + subreq = wb_child_request_send(state, ev, state->child, state->init_req); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); @@ -259,7 +359,7 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx, state->init_req->cmd = WINBINDD_GETDCNAME; fstrcpy(state->init_req->domain_name, domain->name); - subreq = wb_child_request_send(state, ev, &domain->child, request); + subreq = wb_child_request_send(state, ev, state->child, request); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -290,7 +390,7 @@ static void wb_domain_request_gotdc(struct tevent_req *subreq) TALLOC_FREE(response); - subreq = wb_child_request_send(state, state->ev, &state->domain->child, + subreq = wb_child_request_send(state, state->ev, state->child, state->init_req); if (tevent_req_nomem(subreq, req)) { return; @@ -321,8 +421,26 @@ static void wb_domain_request_initialized(struct tevent_req *subreq) tevent_req_error(req, EINVAL); return; } - fstrcpy(state->domain->name, response->data.domain_info.name); - fstrcpy(state->domain->alt_name, response->data.domain_info.alt_name); + + talloc_free(state->domain->name); + state->domain->name = talloc_strdup(state->domain, + response->data.domain_info.name); + if (state->domain->name == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + + if (response->data.domain_info.alt_name[0] != '\0') { + talloc_free(state->domain->alt_name); + + state->domain->alt_name = talloc_strdup(state->domain, + response->data.domain_info.alt_name); + if (state->domain->alt_name == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + } + state->domain->native_mode = response->data.domain_info.native_mode; state->domain->active_directory = response->data.domain_info.active_directory; @@ -330,7 +448,7 @@ static void wb_domain_request_initialized(struct tevent_req *subreq) TALLOC_FREE(response); - subreq = wb_child_request_send(state, state->ev, &state->domain->child, + subreq = wb_child_request_send(state, state->ev, state->child, state->request); if (tevent_req_nomem(subreq, req)) { return; @@ -395,7 +513,7 @@ static void child_process_request(struct winbindd_child *child, } } - DEBUG(1 ,("child_process_request: unknown request fn number %d\n", + DEBUG(1, ("child_process_request: unknown request fn number %d\n", (int)state->request->cmd)); state->response->result = WINBINDD_ERROR; } @@ -408,10 +526,10 @@ void setup_child(struct winbindd_domain *domain, struct winbindd_child *child, if (logprefix && logname) { char *logbase = NULL; - if (*lp_logfile()) { + if (*lp_logfile(talloc_tos())) { char *end = NULL; - if (asprintf(&logbase, "%s", lp_logfile()) < 0) { + if (asprintf(&logbase, "%s", lp_logfile(talloc_tos())) < 0) { smb_panic("Internal error: asprintf failed"); } @@ -436,6 +554,7 @@ void setup_child(struct winbindd_domain *domain, struct winbindd_child *child, "logname == NULL"); } + child->sock = -1; child->domain = domain; child->table = table; child->queue = tevent_queue_create(NULL, "winbind_child"); @@ -444,8 +563,6 @@ void setup_child(struct winbindd_domain *domain, struct winbindd_child *child, SMB_ASSERT(child->binding_handle != NULL); } -static struct winbindd_child *winbindd_children = NULL; - void winbind_child_died(pid_t pid) { struct winbindd_child *child; @@ -464,10 +581,12 @@ void winbind_child_died(pid_t pid) /* This will be re-added in fork_domain_child() */ DLIST_REMOVE(winbindd_children, child); - - close(child->sock); - child->sock = -1; child->pid = 0; + + if (child->sock != -1) { + close(child->sock); + child->sock = -1; + } } /* Ensure any negative cache entries with the netbios or realm names are removed. */ @@ -475,7 +594,7 @@ void winbind_child_died(pid_t pid) void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain) { flush_negative_conn_cache_for_domain(domain->name); - if (*domain->alt_name) { + if (domain->alt_name != NULL) { flush_negative_conn_cache_for_domain(domain->alt_name); } } @@ -559,11 +678,11 @@ void winbind_msg_offline(struct messaging_context *msg_ctx, we only set it online / offline for that domain. */ DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n", - (unsigned int)child->pid, domain->name )); + (unsigned int)child->pid, child->domain->name )); messaging_send_buf(msg_ctx, pid_to_procid(child->pid), MSG_WINBIND_OFFLINE, - (uint8 *)child->domain->name, + (const uint8_t *)child->domain->name, strlen(child->domain->name)+1); } } @@ -612,7 +731,7 @@ void winbind_msg_online(struct messaging_context *msg_ctx, messaging_send_buf(msg_ctx, pid_to_procid(idmap->pid), MSG_WINBIND_ONLINE, - (uint8 *)domain->name, + (const uint8_t *)domain->name, strlen(domain->name)+1); } } @@ -637,7 +756,7 @@ void winbind_msg_online(struct messaging_context *msg_ctx, messaging_send_buf(msg_ctx, pid_to_procid(child->pid), MSG_WINBIND_ONLINE, - (uint8 *)child->domain->name, + (const uint8_t *)child->domain->name, strlen(child->domain->name)+1); } } @@ -699,7 +818,7 @@ void winbind_msg_onlinestatus(struct messaging_context *msg_ctx, } messaging_send_buf(msg_ctx, *sender, MSG_WINBIND_ONLINESTATUS, - (uint8 *)message, strlen(message) + 1); + (const uint8_t *)message, strlen(message) + 1); talloc_destroy(mem_ctx); } @@ -714,7 +833,7 @@ void winbind_msg_dump_event_list(struct messaging_context *msg_ctx, DEBUG(10,("winbind_msg_dump_event_list received\n")); - dump_event_list(winbind_event_context()); + DBG_WARNING("dump event list no longer implemented\n"); for (child = winbindd_children; child != NULL; child = child->next) { @@ -776,7 +895,7 @@ void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx, messaging_send_buf(msg_ctx, *sender, MSG_WINBIND_DUMP_DOMAIN_LIST, - (uint8_t *)message, strlen(message) + 1); + (const uint8_t *)message, strlen(message) + 1); talloc_destroy(mem_ctx); @@ -810,15 +929,14 @@ void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx, talloc_destroy(mem_ctx); } -static void account_lockout_policy_handler(struct event_context *ctx, - struct timed_event *te, +static void account_lockout_policy_handler(struct tevent_context *ctx, + struct tevent_timer *te, struct timeval now, void *private_data) { struct winbindd_child *child = (struct winbindd_child *)private_data; TALLOC_CTX *mem_ctx = NULL; - struct winbindd_methods *methods; struct samr_DomInfo12 lockout_policy; NTSTATUS result; @@ -834,13 +952,12 @@ static void account_lockout_policy_handler(struct event_context *ctx, return; } - methods = child->domain->methods; - mem_ctx = talloc_init("account_lockout_policy_handler ctx"); if (!mem_ctx) { result = NT_STATUS_NO_MEMORY; } else { - result = methods->lockout_policy(child->domain, mem_ctx, &lockout_policy); + result = wb_cache_lockout_policy(child->domain, mem_ctx, + &lockout_policy); } TALLOC_FREE(mem_ctx); @@ -849,7 +966,7 @@ static void account_lockout_policy_handler(struct event_context *ctx, nt_errstr(result))); } - child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL, + child->lockout_policy_event = tevent_add_timer(server_event_context(), NULL, timeval_current_ofs(3600, 0), account_lockout_policy_handler, child); @@ -927,15 +1044,16 @@ static bool calculate_next_machine_pwd_change(const char *domain, return true; } -static void machine_password_change_handler(struct event_context *ctx, - struct timed_event *te, +static void machine_password_change_handler(struct tevent_context *ctx, + struct tevent_timer *te, struct timeval now, void *private_data) { + struct messaging_context *msg_ctx = server_messaging_context(); struct winbindd_child *child = (struct winbindd_child *)private_data; struct rpc_pipe_client *netlogon_pipe = NULL; - TALLOC_CTX *frame; + struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL; NTSTATUS result; struct timeval next_change; @@ -964,7 +1082,9 @@ static void machine_password_change_handler(struct event_context *ctx, return; } - result = cm_connect_netlogon(child->domain, &netlogon_pipe); + result = cm_connect_netlogon_secure(child->domain, + &netlogon_pipe, + &netlogon_creds_ctx); if (!NT_STATUS_IS_OK(result)) { DEBUG(10,("machine_password_change_handler: " "failed to connect netlogon pipe: %s\n", @@ -972,15 +1092,15 @@ static void machine_password_change_handler(struct event_context *ctx, return; } - frame = talloc_stackframe(); - - result = trust_pw_find_change_and_store_it(netlogon_pipe, - frame, - child->domain->name); - TALLOC_FREE(frame); + result = trust_pw_change(netlogon_creds_ctx, + msg_ctx, + netlogon_pipe->binding_handle, + child->domain->name, + child->domain->dcname, + false); /* force */ DEBUG(10, ("machine_password_change_handler: " - "trust_pw_find_change_and_store_it returned %s\n", + "trust_pw_change returned %s\n", nt_errstr(result))); if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) { @@ -989,7 +1109,7 @@ static void machine_password_change_handler(struct event_context *ctx, "password was changed and we didn't know it. " "Killing connections to domain %s\n", child->domain->name)); - TALLOC_FREE(child->domain->conn.netlogon_pipe); + invalidate_cm_connection(child->domain); } if (!calculate_next_machine_pwd_change(child->domain->name, @@ -1011,7 +1131,7 @@ static void machine_password_change_handler(struct event_context *ctx, } done: - child->machine_password_change_event = event_add_timed(winbind_event_context(), NULL, + child->machine_password_change_event = tevent_add_timer(server_event_context(), NULL, next_change, machine_password_change_handler, child); @@ -1120,24 +1240,23 @@ static void child_msg_dump_event_list(struct messaging_context *msg, DATA_BLOB *data) { DEBUG(5,("child_msg_dump_event_list received\n")); - - dump_event_list(winbind_event_context()); + DBG_WARNING("dump_event_list no longer implemented\n"); } -bool winbindd_reinit_after_fork(const char *logfilename) +NTSTATUS winbindd_reinit_after_fork(const struct winbindd_child *myself, + const char *logfilename) { struct winbindd_domain *domain; struct winbindd_child *cl; NTSTATUS status; status = reinit_after_fork( - winbind_messaging_context(), - winbind_event_context(), - procid_self(), - true); + server_messaging_context(), + server_event_context(), + true, NULL); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("reinit_after_fork() failed\n")); - return false; + return status; } close_conns_after_fork(); @@ -1148,32 +1267,37 @@ bool winbindd_reinit_after_fork(const char *logfilename) } if (!winbindd_setup_sig_term_handler(false)) - return false; + return NT_STATUS_NO_MEMORY; if (!winbindd_setup_sig_hup_handler(override_logfile ? NULL : logfilename)) - return false; + return NT_STATUS_NO_MEMORY; /* Stop zombies in children */ CatchChild(); /* Don't handle the same messages as our parent. */ - messaging_deregister(winbind_messaging_context(), + messaging_deregister(server_messaging_context(), MSG_SMB_CONF_UPDATED, NULL); - messaging_deregister(winbind_messaging_context(), + messaging_deregister(server_messaging_context(), MSG_SHUTDOWN, NULL); - messaging_deregister(winbind_messaging_context(), + messaging_deregister(server_messaging_context(), MSG_WINBIND_OFFLINE, NULL); - messaging_deregister(winbind_messaging_context(), + messaging_deregister(server_messaging_context(), MSG_WINBIND_ONLINE, NULL); - messaging_deregister(winbind_messaging_context(), + messaging_deregister(server_messaging_context(), MSG_WINBIND_ONLINESTATUS, NULL); - messaging_deregister(winbind_messaging_context(), + messaging_deregister(server_messaging_context(), MSG_DUMP_EVENT_LIST, NULL); - messaging_deregister(winbind_messaging_context(), + messaging_deregister(server_messaging_context(), MSG_WINBIND_DUMP_DOMAIN_LIST, NULL); - messaging_deregister(winbind_messaging_context(), + messaging_deregister(server_messaging_context(), MSG_DEBUG, NULL); + messaging_deregister(server_messaging_context(), + MSG_WINBIND_DOMAIN_OFFLINE, NULL); + messaging_deregister(server_messaging_context(), + MSG_WINBIND_DOMAIN_ONLINE, NULL); + /* We have destroyed all events in the winbindd_event_context * in reinit_after_fork(), so clean out all possible pending * event pointers. */ @@ -1199,6 +1323,14 @@ bool winbindd_reinit_after_fork(const char *logfilename) * go through the parent. */ cl->pid = (pid_t)0; + + /* + * Close service sockets to all other children + */ + if ((cl != myself) && (cl->sock != -1)) { + close(cl->sock); + cl->sock = -1; + } } /* * This is a little tricky, children must not @@ -1219,7 +1351,7 @@ bool winbindd_reinit_after_fork(const char *logfilename) cl = idmap_child(); cl->pid = (pid_t)0; - return true; + return NT_STATUS_OK; } /* @@ -1232,13 +1364,55 @@ struct winbindd_domain *wb_child_domain(void) return child_domain; } +struct child_handler_state { + struct winbindd_child *child; + struct winbindd_cli_state cli; +}; + +static void child_handler(struct tevent_context *ev, struct tevent_fd *fde, + uint16_t flags, void *private_data) +{ + struct child_handler_state *state = + (struct child_handler_state *)private_data; + NTSTATUS status; + + /* fetch a request from the main daemon */ + status = child_read_request(state->cli.sock, state->cli.request); + + if (!NT_STATUS_IS_OK(status)) { + /* we lost contact with our parent */ + _exit(0); + } + + DEBUG(4,("child daemon request %d\n", + (int)state->cli.request->cmd)); + + ZERO_STRUCTP(state->cli.response); + state->cli.request->null_term = '\0'; + state->cli.mem_ctx = talloc_tos(); + child_process_request(state->child, &state->cli); + + DEBUG(4, ("Finished processing child request %d\n", + (int)state->cli.request->cmd)); + + SAFE_FREE(state->cli.request->extra_data.data); + + status = child_write_response(state->cli.sock, state->cli.response); + if (!NT_STATUS_IS_OK(status)) { + exit(1); + } +} + static bool fork_domain_child(struct winbindd_child *child) { int fdpair[2]; - struct winbindd_cli_state state; + struct child_handler_state state; struct winbindd_request request; struct winbindd_response response; struct winbindd_domain *primary_domain = NULL; + NTSTATUS status; + ssize_t nwritten; + struct tevent_fd *fde; if (child->domain) { DEBUG(10, ("fork_domain_child called for domain '%s'\n", @@ -1254,20 +1428,41 @@ static bool fork_domain_child(struct winbindd_child *child) } ZERO_STRUCT(state); - state.pid = sys_getpid(); - state.request = &request; - state.response = &response; + state.child = child; + state.cli.pid = getpid(); + state.cli.request = &request; + state.cli.response = &response; - child->pid = sys_fork(); + child->pid = fork(); if (child->pid == -1) { DEBUG(0, ("Could not fork: %s\n", strerror(errno))); + close(fdpair[0]); + close(fdpair[1]); return False; } if (child->pid != 0) { /* Parent */ + ssize_t nread; + close(fdpair[0]); + + nread = sys_read(fdpair[1], &status, sizeof(status)); + if (nread != sizeof(status)) { + DEBUG(1, ("fork_domain_child: Could not read child status: " + "nread=%d, error=%s\n", (int)nread, + strerror(errno))); + close(fdpair[1]); + return false; + } + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("fork_domain_child: Child status is %s\n", + nt_errstr(status))); + close(fdpair[1]); + return false; + } + child->next = child->prev = NULL; DLIST_ADD(winbindd_children, child); child->sock = fdpair[1]; @@ -1277,24 +1472,45 @@ static bool fork_domain_child(struct winbindd_child *child) /* Child */ child_domain = child->domain; - DEBUG(10, ("Child process %d\n", (int)sys_getpid())); + DEBUG(10, ("Child process %d\n", (int)getpid())); - state.sock = fdpair[0]; + state.cli.sock = fdpair[0]; close(fdpair[1]); - if (!winbindd_reinit_after_fork(child->logfilename)) { + status = winbindd_reinit_after_fork(child, child->logfilename); + + nwritten = sys_write(state.cli.sock, &status, sizeof(status)); + if (nwritten != sizeof(status)) { + DEBUG(1, ("fork_domain_child: Could not write status: " + "nwritten=%d, error=%s\n", (int)nwritten, + strerror(errno))); _exit(0); } + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("winbindd_reinit_after_fork failed: %s\n", + nt_errstr(status))); + _exit(0); + } + + if (child_domain != NULL) { + setproctitle("domain child [%s]", child_domain->name); + } else if (child == idmap_child()) { + setproctitle("idmap child"); + } /* Handle online/offline messages. */ - messaging_register(winbind_messaging_context(), NULL, + messaging_register(server_messaging_context(), NULL, MSG_WINBIND_OFFLINE, child_msg_offline); - messaging_register(winbind_messaging_context(), NULL, + messaging_register(server_messaging_context(), NULL, MSG_WINBIND_ONLINE, child_msg_online); - messaging_register(winbind_messaging_context(), NULL, + messaging_register(server_messaging_context(), NULL, MSG_DUMP_EVENT_LIST, child_msg_dump_event_list); - messaging_register(winbind_messaging_context(), NULL, + messaging_register(server_messaging_context(), NULL, MSG_DEBUG, debug_message); + messaging_register(server_messaging_context(), NULL, + MSG_WINBIND_IP_DROPPED, + winbind_msg_ip_dropped); + primary_domain = find_our_domain(); @@ -1346,8 +1562,8 @@ static bool fork_domain_child(struct winbindd_child *child) set_domain_online_request(primary_domain); } - child->lockout_policy_event = event_add_timed( - winbind_event_context(), NULL, timeval_zero(), + child->lockout_policy_event = tevent_add_timer( + server_event_context(), NULL, timeval_zero(), account_lockout_policy_handler, child); } @@ -1360,34 +1576,32 @@ static bool fork_domain_child(struct winbindd_child *child) if (calculate_next_machine_pwd_change(child->domain->name, &next_change)) { - child->machine_password_change_event = event_add_timed( - winbind_event_context(), NULL, next_change, + child->machine_password_change_event = tevent_add_timer( + server_event_context(), NULL, next_change, machine_password_change_handler, child); } } + fde = tevent_add_fd(server_event_context(), NULL, state.cli.sock, + TEVENT_FD_READ, child_handler, &state); + if (fde == NULL) { + DEBUG(1, ("tevent_add_fd failed\n")); + _exit(1); + } + while (1) { int ret; - fd_set r_fds; - fd_set w_fds; - int maxfd; - struct timeval t; - struct timeval *tp; - struct timeval now; TALLOC_CTX *frame = talloc_stackframe(); - struct iovec iov[2]; - int iov_count; - NTSTATUS status; - if (run_events(winbind_event_context(), 0, NULL, NULL)) { - TALLOC_FREE(frame); - continue; + ret = tevent_loop_once(server_event_context()); + if (ret != 0) { + DEBUG(1, ("tevent_loop_once failed: %s\n", + strerror(errno))); + _exit(1); } - GetTimeOfDay(&now); - if (child->domain && child->domain->startup && (time_mono(NULL) > child->domain->startup_time + 30)) { /* No longer in "startup" mode. */ @@ -1396,93 +1610,24 @@ static bool fork_domain_child(struct winbindd_child *child) child->domain->startup = False; } - FD_ZERO(&r_fds); - FD_ZERO(&w_fds); - FD_SET(state.sock, &r_fds); - maxfd = state.sock; - - /* - * Initialize this high as event_add_to_select_args() - * uses a timeval_min() on this and next_event. Fix - * from Roel van Meer . - */ - t.tv_sec = 999999; - t.tv_usec = 0; - - event_add_to_select_args(winbind_event_context(), &now, - &r_fds, &w_fds, &t, &maxfd); - tp = get_timed_events_timeout(winbind_event_context(), &t); - if (tp) { - DEBUG(11,("select will use timeout of %u.%u seconds\n", - (unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec )); - } - - ret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, tp); - - if (run_events(winbind_event_context(), ret, &r_fds, &w_fds)) { - /* We got a signal - continue. */ - TALLOC_FREE(frame); - continue; - } - - if (ret == 0) { - DEBUG(11,("nothing is ready yet, continue\n")); - TALLOC_FREE(frame); - continue; - } - - if (ret == -1 && errno == EINTR) { - /* We got a signal - continue. */ - TALLOC_FREE(frame); - continue; - } - - if (ret == -1 && errno != EINTR) { - DEBUG(0,("select error occured\n")); - TALLOC_FREE(frame); - perror("select"); - _exit(1); - } - - /* fetch a request from the main daemon */ - status = child_read_request(&state); - - if (!NT_STATUS_IS_OK(status)) { - /* we lost contact with our parent */ - _exit(0); - } - - DEBUG(4,("child daemon request %d\n", (int)state.request->cmd)); - - ZERO_STRUCTP(state.response); - state.request->null_term = '\0'; - state.mem_ctx = frame; - child_process_request(child, &state); - - DEBUG(4, ("Finished processing child request %d\n", - (int)state.request->cmd)); - - SAFE_FREE(state.request->extra_data.data); + TALLOC_FREE(frame); + } +} - iov[0].iov_base = (void *)state.response; - iov[0].iov_len = sizeof(struct winbindd_response); - iov_count = 1; +void winbind_msg_ip_dropped_parent(struct messaging_context *msg_ctx, + void *private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data) +{ + struct winbindd_child *child; - if (state.response->length > sizeof(struct winbindd_response)) { - iov[1].iov_base = - (void *)state.response->extra_data.data; - iov[1].iov_len = state.response->length-iov[0].iov_len; - iov_count = 2; - } + winbind_msg_ip_dropped(msg_ctx, private_data, msg_type, + server_id, data); - DEBUG(10, ("Writing %d bytes to parent\n", - (int)state.response->length)); - if (write_data_iov(state.sock, iov, iov_count) != - state.response->length) { - DEBUG(0, ("Could not write result\n")); - exit(1); - } - TALLOC_FREE(frame); + for (child = winbindd_children; child != NULL; child = child->next) { + messaging_send_buf(msg_ctx, pid_to_procid(child->pid), + msg_type, data->data, data->length); } }