Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Winbind child daemons
5 :
6 : Copyright (C) Andrew Tridgell 2002
7 : Copyright (C) Volker Lendecke 2004,2005
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : /*
24 : * We fork a child per domain to be able to act non-blocking in the main
25 : * winbind daemon. A domain controller thousands of miles away being being
26 : * slow replying with a 10.000 user list should not hold up netlogon calls
27 : * that can be handled locally.
28 : */
29 :
30 : #include "includes.h"
31 : #include "winbindd.h"
32 : #include "rpc_client/rpc_client.h"
33 : #include "nsswitch/wb_reqtrans.h"
34 : #include "secrets.h"
35 : #include "../lib/util/select.h"
36 : #include "winbindd_traceid.h"
37 : #include "../libcli/security/security.h"
38 : #include "system/select.h"
39 : #include "messages.h"
40 : #include "../lib/util/tevent_unix.h"
41 : #include "lib/param/loadparm.h"
42 : #include "lib/util/sys_rw.h"
43 : #include "lib/util/sys_rw_data.h"
44 : #include "passdb.h"
45 : #include "lib/util/string_wrappers.h"
46 : #include "lib/global_contexts.h"
47 : #include "idmap.h"
48 : #include "libcli/auth/netlogon_creds_cli.h"
49 : #include "../lib/util/pidfile.h"
50 : #include "librpc/gen_ndr/ndr_winbind_c.h"
51 : #include "lib/util/util_process.h"
52 :
53 : #undef DBGC_CLASS
54 : #define DBGC_CLASS DBGC_WINBIND
55 :
56 107 : static void forall_domain_children(bool (*fn)(struct winbindd_child *c,
57 : void *private_data),
58 : void *private_data)
59 : {
60 0 : struct winbindd_domain *d;
61 :
62 351 : for (d = domain_list(); d != NULL; d = d->next) {
63 : int i;
64 :
65 488 : for (i = 0; i < talloc_array_length(d->children); i++) {
66 244 : struct winbindd_child *c = &d->children[i];
67 0 : bool ok;
68 :
69 244 : if (c->pid == 0) {
70 30 : continue;
71 : }
72 :
73 214 : ok = fn(c, private_data);
74 214 : if (!ok) {
75 0 : return;
76 : }
77 : }
78 : }
79 : }
80 :
81 103 : static void forall_children(bool (*fn)(struct winbindd_child *c,
82 : void *private_data),
83 : void *private_data)
84 : {
85 0 : struct winbindd_child *c;
86 0 : bool ok;
87 :
88 103 : c = idmap_child();
89 103 : if (c->pid != 0) {
90 103 : ok = fn(c, private_data);
91 103 : if (!ok) {
92 0 : return;
93 : }
94 : }
95 :
96 103 : c = locator_child();
97 103 : if (c->pid != 0) {
98 0 : ok = fn(c, private_data);
99 0 : if (!ok) {
100 0 : return;
101 : }
102 : }
103 :
104 103 : forall_domain_children(fn, private_data);
105 : }
106 :
107 : /* Read some data from a client connection */
108 :
109 0 : static NTSTATUS child_read_request(int sock, struct winbindd_request *wreq)
110 : {
111 0 : NTSTATUS status;
112 :
113 0 : status = read_data_ntstatus(sock, (char *)wreq, sizeof(*wreq));
114 0 : if (!NT_STATUS_IS_OK(status)) {
115 0 : DEBUG(3, ("child_read_request: read_data failed: %s\n",
116 : nt_errstr(status)));
117 0 : return status;
118 : }
119 :
120 0 : if (wreq->extra_len == 0) {
121 0 : wreq->extra_data.data = NULL;
122 0 : return NT_STATUS_OK;
123 : }
124 :
125 0 : DEBUG(10, ("Need to read %d extra bytes\n", (int)wreq->extra_len));
126 :
127 0 : wreq->extra_data.data = SMB_MALLOC_ARRAY(char, wreq->extra_len + 1);
128 0 : if (wreq->extra_data.data == NULL) {
129 0 : DEBUG(0, ("malloc failed\n"));
130 0 : return NT_STATUS_NO_MEMORY;
131 : }
132 :
133 : /* Ensure null termination */
134 0 : wreq->extra_data.data[wreq->extra_len] = '\0';
135 :
136 0 : status = read_data_ntstatus(sock, wreq->extra_data.data,
137 0 : wreq->extra_len);
138 0 : if (!NT_STATUS_IS_OK(status)) {
139 0 : DEBUG(0, ("Could not read extra data: %s\n",
140 : nt_errstr(status)));
141 : }
142 0 : return status;
143 : }
144 :
145 0 : static NTSTATUS child_write_response(int sock, struct winbindd_response *wrsp)
146 : {
147 0 : struct iovec iov[2];
148 0 : int iov_count;
149 :
150 0 : iov[0].iov_base = (void *)wrsp;
151 0 : iov[0].iov_len = sizeof(struct winbindd_response);
152 0 : iov_count = 1;
153 :
154 0 : if (wrsp->length > sizeof(struct winbindd_response)) {
155 0 : iov[1].iov_base = (void *)wrsp->extra_data.data;
156 0 : iov[1].iov_len = wrsp->length-iov[0].iov_len;
157 0 : iov_count = 2;
158 : }
159 :
160 0 : DEBUG(10, ("Writing %d bytes to parent\n", (int)wrsp->length));
161 :
162 0 : if (write_data_iov(sock, iov, iov_count) != wrsp->length) {
163 0 : DEBUG(0, ("Could not write result\n"));
164 0 : return NT_STATUS_INVALID_HANDLE;
165 : }
166 :
167 0 : return NT_STATUS_OK;
168 : }
169 :
170 : /*
171 : * Do winbind child async request. This is not simply wb_simple_trans. We have
172 : * to do the queueing ourselves because while a request is queued, the child
173 : * might have crashed, and we have to re-fork it in the _trigger function.
174 : */
175 :
176 : struct wb_child_request_state {
177 : struct tevent_context *ev;
178 : struct tevent_req *queue_subreq;
179 : struct tevent_req *subreq;
180 : struct winbindd_child *child;
181 : struct winbindd_request *request;
182 : struct winbindd_response *response;
183 : };
184 :
185 : static bool fork_domain_child(struct winbindd_child *child);
186 :
187 : static void wb_child_request_waited(struct tevent_req *subreq);
188 : static void wb_child_request_done(struct tevent_req *subreq);
189 : static void wb_child_request_orphaned(struct tevent_req *subreq);
190 :
191 : static void wb_child_request_cleanup(struct tevent_req *req,
192 : enum tevent_req_state req_state);
193 :
194 125056 : struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx,
195 : struct tevent_context *ev,
196 : struct winbindd_child *child,
197 : struct winbindd_request *request)
198 : {
199 0 : struct tevent_req *req;
200 0 : struct wb_child_request_state *state;
201 0 : struct tevent_req *subreq;
202 :
203 125056 : req = tevent_req_create(mem_ctx, &state,
204 : struct wb_child_request_state);
205 125056 : if (req == NULL) {
206 0 : return NULL;
207 : }
208 :
209 125056 : state->ev = ev;
210 125056 : state->child = child;
211 :
212 : /*
213 : * We have to make a copy of "request", because our caller
214 : * might drop us via talloc_free().
215 : *
216 : * The talloc_move() magic in wb_child_request_cleanup() keeps
217 : * all the requests, but if we are sitting deep within
218 : * writev_send() down to the client, we have given it the
219 : * pointer to "request". As our caller lost interest, it will
220 : * just free "request", while writev_send still references it.
221 : */
222 :
223 125056 : state->request = talloc_memdup(state, request, sizeof(*request));
224 125056 : if (tevent_req_nomem(state->request, req)) {
225 0 : return tevent_req_post(req, ev);
226 : }
227 :
228 125056 : state->request->traceid = debug_traceid_get();
229 :
230 125056 : if (request->extra_data.data != NULL) {
231 125056 : state->request->extra_data.data = talloc_memdup(
232 : state->request,
233 : request->extra_data.data,
234 : request->extra_len);
235 125056 : if (tevent_req_nomem(state->request->extra_data.data, req)) {
236 0 : return tevent_req_post(req, ev);
237 : }
238 : }
239 :
240 125056 : subreq = tevent_queue_wait_send(state, ev, child->queue);
241 125056 : if (tevent_req_nomem(subreq, req)) {
242 0 : return tevent_req_post(req, ev);
243 : }
244 125056 : tevent_req_set_callback(subreq, wb_child_request_waited, req);
245 125056 : state->queue_subreq = subreq;
246 :
247 125056 : tevent_req_set_cleanup_fn(req, wb_child_request_cleanup);
248 :
249 125056 : return req;
250 : }
251 :
252 125056 : static void wb_child_request_waited(struct tevent_req *subreq)
253 : {
254 125056 : struct tevent_req *req = tevent_req_callback_data(
255 : subreq, struct tevent_req);
256 125056 : struct wb_child_request_state *state = tevent_req_data(
257 : req, struct wb_child_request_state);
258 0 : bool ok;
259 :
260 125056 : ok = tevent_queue_wait_recv(subreq);
261 125056 : if (!ok) {
262 0 : tevent_req_oom(req);
263 0 : return;
264 : }
265 : /*
266 : * We need to keep state->queue_subreq
267 : * in order to block the queue.
268 : */
269 125056 : subreq = NULL;
270 :
271 125056 : if ((state->child->sock == -1) && (!fork_domain_child(state->child))) {
272 0 : tevent_req_error(req, errno);
273 0 : return;
274 : }
275 :
276 125056 : tevent_fd_set_flags(state->child->monitor_fde, 0);
277 :
278 125056 : subreq = wb_simple_trans_send(state, global_event_context(), NULL,
279 125056 : state->child->sock, state->request);
280 125056 : if (tevent_req_nomem(subreq, req)) {
281 0 : return;
282 : }
283 :
284 125056 : state->subreq = subreq;
285 125056 : tevent_req_set_callback(subreq, wb_child_request_done, req);
286 125056 : tevent_req_set_endtime(req, state->ev, timeval_current_ofs(300, 0));
287 : }
288 :
289 125056 : static void wb_child_request_done(struct tevent_req *subreq)
290 : {
291 125056 : struct tevent_req *req = tevent_req_callback_data(
292 : subreq, struct tevent_req);
293 125056 : struct wb_child_request_state *state = tevent_req_data(
294 : req, struct wb_child_request_state);
295 0 : int ret, err;
296 :
297 125056 : ret = wb_simple_trans_recv(subreq, state, &state->response, &err);
298 : /* Freeing the subrequest is deferred until the cleanup function,
299 : * which has to know whether a subrequest exists, and consequently
300 : * decide whether to shut down the pipe to the child process.
301 : */
302 125056 : if (ret == -1) {
303 0 : tevent_req_error(req, err);
304 0 : return;
305 : }
306 125056 : tevent_req_done(req);
307 : }
308 :
309 0 : static void wb_child_request_orphaned(struct tevent_req *subreq)
310 : {
311 0 : struct winbindd_child *child =
312 0 : (struct winbindd_child *)tevent_req_callback_data_void(subreq);
313 :
314 0 : DBG_WARNING("cleanup orphaned subreq[%p]\n", subreq);
315 0 : TALLOC_FREE(subreq);
316 :
317 0 : if (child->domain != NULL) {
318 : /*
319 : * If the child is attached to a domain,
320 : * we need to make sure the domain queue
321 : * can move forward, after the orphaned
322 : * request is done.
323 : */
324 0 : tevent_queue_start(child->domain->queue);
325 : }
326 0 : }
327 :
328 125056 : int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
329 : struct winbindd_response **presponse, int *err)
330 : {
331 125056 : struct wb_child_request_state *state = tevent_req_data(
332 : req, struct wb_child_request_state);
333 :
334 125056 : if (tevent_req_is_unix_error(req, err)) {
335 0 : return -1;
336 : }
337 125056 : *presponse = talloc_move(mem_ctx, &state->response);
338 125056 : return 0;
339 : }
340 :
341 250112 : static void wb_child_request_cleanup(struct tevent_req *req,
342 : enum tevent_req_state req_state)
343 : {
344 0 : struct wb_child_request_state *state =
345 250112 : tevent_req_data(req, struct wb_child_request_state);
346 :
347 250112 : if (state->subreq == NULL) {
348 : /* nothing to cleanup */
349 125056 : return;
350 : }
351 :
352 125056 : if (req_state == TEVENT_REQ_RECEIVED) {
353 0 : struct tevent_req *subreq = NULL;
354 :
355 : /*
356 : * Our caller gave up, but we need to keep
357 : * the low level request (wb_simple_trans)
358 : * in order to maintain the parent child protocol.
359 : *
360 : * We also need to keep the child queue blocked
361 : * until we got the response from the child.
362 : */
363 :
364 0 : subreq = talloc_move(state->child->queue, &state->subreq);
365 0 : talloc_move(subreq, &state->queue_subreq);
366 0 : talloc_move(subreq, &state->request);
367 0 : tevent_req_set_callback(subreq,
368 : wb_child_request_orphaned,
369 : state->child);
370 :
371 0 : DBG_WARNING("keep orphaned subreq[%p]\n", subreq);
372 0 : return;
373 : }
374 :
375 125056 : TALLOC_FREE(state->subreq);
376 125056 : TALLOC_FREE(state->queue_subreq);
377 :
378 125056 : tevent_fd_set_flags(state->child->monitor_fde, TEVENT_FD_READ);
379 :
380 125056 : if (state->child->domain != NULL) {
381 : /*
382 : * If the child is attached to a domain,
383 : * we need to make sure the domain queue
384 : * can move forward, after the request
385 : * is done.
386 : */
387 22758 : tevent_queue_start(state->child->domain->queue);
388 : }
389 :
390 125056 : if (req_state == TEVENT_REQ_DONE) {
391 : /* transmitted request and got response */
392 125056 : return;
393 : }
394 :
395 : /*
396 : * Failed to transmit and receive response, or request
397 : * cancelled while being serviced.
398 : * The basic parent/child communication broke, close
399 : * our socket
400 : */
401 0 : TALLOC_FREE(state->child->monitor_fde);
402 0 : close(state->child->sock);
403 0 : state->child->sock = -1;
404 : }
405 :
406 0 : static void child_socket_readable(struct tevent_context *ev,
407 : struct tevent_fd *fde,
408 : uint16_t flags,
409 : void *private_data)
410 : {
411 0 : struct winbindd_child *child = private_data;
412 :
413 0 : if ((flags & TEVENT_FD_READ) == 0) {
414 0 : return;
415 : }
416 :
417 0 : TALLOC_FREE(child->monitor_fde);
418 :
419 : /*
420 : * We're only active when there is no outstanding child
421 : * request. Arriving here means the child closed its socket,
422 : * it died. Do the same here.
423 : */
424 :
425 0 : SMB_ASSERT(child->sock != -1);
426 :
427 0 : close(child->sock);
428 0 : child->sock = -1;
429 : }
430 :
431 22670 : static struct winbindd_child *choose_domain_child(struct winbindd_domain *domain)
432 : {
433 22670 : struct winbindd_child *shortest = &domain->children[0];
434 0 : struct winbindd_child *current;
435 0 : int i;
436 :
437 22673 : for (i=0; i<talloc_array_length(domain->children); i++) {
438 0 : size_t shortest_len, current_len;
439 :
440 22670 : current = &domain->children[i];
441 22670 : current_len = tevent_queue_length(current->queue);
442 :
443 22670 : if (current_len == 0) {
444 : /* idle child */
445 22667 : return current;
446 : }
447 :
448 3 : shortest_len = tevent_queue_length(shortest->queue);
449 :
450 3 : if (current_len < shortest_len) {
451 0 : shortest = current;
452 : }
453 : }
454 :
455 3 : return shortest;
456 : }
457 :
458 125274 : struct dcerpc_binding_handle *dom_child_handle(struct winbindd_domain *domain)
459 : {
460 125274 : return domain->binding_handle;
461 : }
462 :
463 : struct wb_domain_request_state {
464 : struct tevent_context *ev;
465 : struct tevent_queue_entry *queue_entry;
466 : struct winbindd_domain *domain;
467 : struct winbindd_child *child;
468 : struct winbindd_request *request;
469 : struct winbindd_request *init_req;
470 : struct winbindd_response *response;
471 : struct tevent_req *pending_subreq;
472 : struct wbint_InitConnection r;
473 : };
474 :
475 45334 : static void wb_domain_request_cleanup(struct tevent_req *req,
476 : enum tevent_req_state req_state)
477 : {
478 45334 : struct wb_domain_request_state *state = tevent_req_data(
479 : req, struct wb_domain_request_state);
480 :
481 : /*
482 : * If we're completely done or got a failure.
483 : * we should remove ourself from the domain queue,
484 : * after removing the child subreq from the child queue
485 : * and give the next one in the queue the chance
486 : * to check for an idle child.
487 : */
488 45334 : TALLOC_FREE(state->pending_subreq);
489 45334 : TALLOC_FREE(state->queue_entry);
490 45334 : tevent_queue_start(state->domain->queue);
491 45334 : }
492 :
493 : static void wb_domain_request_trigger(struct tevent_req *req,
494 : void *private_data);
495 : static void wb_domain_request_gotdc(struct tevent_req *subreq);
496 : static void wb_domain_request_initialized(struct tevent_req *subreq);
497 : static void wb_domain_request_done(struct tevent_req *subreq);
498 :
499 22667 : struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
500 : struct tevent_context *ev,
501 : struct winbindd_domain *domain,
502 : struct winbindd_request *request)
503 : {
504 0 : struct tevent_req *req;
505 0 : struct wb_domain_request_state *state;
506 :
507 22667 : req = tevent_req_create(mem_ctx, &state,
508 : struct wb_domain_request_state);
509 22667 : if (req == NULL) {
510 0 : return NULL;
511 : }
512 :
513 22667 : state->domain = domain;
514 22667 : state->ev = ev;
515 22667 : state->request = request;
516 :
517 22667 : tevent_req_set_cleanup_fn(req, wb_domain_request_cleanup);
518 :
519 22667 : state->queue_entry = tevent_queue_add_entry(
520 : domain->queue, state->ev, req,
521 0 : wb_domain_request_trigger, NULL);
522 22667 : if (tevent_req_nomem(state->queue_entry, req)) {
523 0 : return tevent_req_post(req, ev);
524 : }
525 :
526 22667 : return req;
527 : }
528 :
529 22670 : static void wb_domain_request_trigger(struct tevent_req *req,
530 : void *private_data)
531 : {
532 22670 : struct wb_domain_request_state *state = tevent_req_data(
533 : req, struct wb_domain_request_state);
534 22670 : struct winbindd_domain *domain = state->domain;
535 22670 : struct tevent_req *subreq = NULL;
536 0 : size_t shortest_queue_length;
537 :
538 22670 : state->child = choose_domain_child(domain);
539 22670 : shortest_queue_length = tevent_queue_length(state->child->queue);
540 22670 : if (shortest_queue_length > 0) {
541 : /*
542 : * All children are busy, we need to stop
543 : * the queue and untrigger our own queue
544 : * entry. Once a pending request
545 : * is done it calls tevent_queue_start
546 : * and we get retriggered.
547 : */
548 3 : state->child = NULL;
549 3 : tevent_queue_stop(state->domain->queue);
550 3 : tevent_queue_entry_untrigger(state->queue_entry);
551 3 : return;
552 : }
553 :
554 22667 : if (domain->initialized) {
555 22576 : subreq = wb_child_request_send(state, state->ev, state->child,
556 : state->request);
557 22576 : if (tevent_req_nomem(subreq, req)) {
558 0 : return;
559 : }
560 22576 : tevent_req_set_callback(subreq, wb_domain_request_done, req);
561 22576 : state->pending_subreq = subreq;
562 :
563 : /*
564 : * Once the domain is initialized and
565 : * once we placed our real request into the child queue,
566 : * we can remove ourself from the domain queue
567 : * and give the next one in the queue the chance
568 : * to check for an idle child.
569 : */
570 22576 : TALLOC_FREE(state->queue_entry);
571 22576 : return;
572 : }
573 :
574 91 : state->init_req = talloc_zero(state, struct winbindd_request);
575 91 : if (tevent_req_nomem(state->init_req, req)) {
576 0 : return;
577 : }
578 :
579 91 : if (IS_DC || domain->primary || domain->internal) {
580 : /* The primary domain has to find the DC name itself */
581 87 : state->r.in.dcname = talloc_strdup(state, "");
582 87 : if (tevent_req_nomem(state->r.in.dcname, req)) {
583 0 : return;
584 : }
585 :
586 87 : subreq = dcerpc_wbint_InitConnection_r_send(state,
587 : state->ev,
588 87 : state->child->binding_handle,
589 : &state->r);
590 87 : if (tevent_req_nomem(subreq, req)) {
591 0 : return;
592 : }
593 87 : tevent_req_set_callback(subreq, wb_domain_request_initialized,
594 : req);
595 87 : state->pending_subreq = subreq;
596 87 : return;
597 : }
598 :
599 : /*
600 : * This is *not* the primary domain,
601 : * let's ask our DC about a DC name.
602 : *
603 : * We prefer getting a dns name in dc_unc,
604 : * which is indicated by DS_RETURN_DNS_NAME.
605 : * For NT4 domains we still get the netbios name.
606 : */
607 4 : subreq = wb_dsgetdcname_send(state, state->ev,
608 4 : state->domain->name,
609 : NULL, /* domain_guid */
610 : NULL, /* site_name */
611 : DS_RETURN_DNS_NAME); /* flags */
612 4 : if (tevent_req_nomem(subreq, req)) {
613 0 : return;
614 : }
615 4 : tevent_req_set_callback(subreq, wb_domain_request_gotdc, req);
616 4 : state->pending_subreq = subreq;
617 4 : return;
618 : }
619 :
620 4 : static void wb_domain_request_gotdc(struct tevent_req *subreq)
621 : {
622 4 : struct tevent_req *req = tevent_req_callback_data(
623 : subreq, struct tevent_req);
624 4 : struct wb_domain_request_state *state = tevent_req_data(
625 : req, struct wb_domain_request_state);
626 4 : struct netr_DsRGetDCNameInfo *dcinfo = NULL;
627 0 : NTSTATUS status;
628 4 : const char *dcname = NULL;
629 :
630 4 : state->pending_subreq = NULL;
631 :
632 4 : status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
633 4 : TALLOC_FREE(subreq);
634 4 : if (tevent_req_nterror(req, status)) {
635 0 : return;
636 : }
637 4 : dcname = dcinfo->dc_unc;
638 12 : while (dcname != NULL && *dcname == '\\') {
639 8 : dcname++;
640 : }
641 :
642 4 : state->r.in.dcname = talloc_strdup(state, dcname);
643 4 : if (tevent_req_nomem(state->r.in.dcname, req)) {
644 0 : return;
645 : }
646 :
647 4 : TALLOC_FREE(dcinfo);
648 :
649 4 : subreq = dcerpc_wbint_InitConnection_r_send(state,
650 : state->ev,
651 4 : state->child->binding_handle,
652 : &state->r);
653 4 : if (tevent_req_nomem(subreq, req)) {
654 0 : return;
655 : }
656 4 : tevent_req_set_callback(subreq, wb_domain_request_initialized, req);
657 4 : state->pending_subreq = subreq;
658 : }
659 :
660 91 : static void wb_domain_request_initialized(struct tevent_req *subreq)
661 : {
662 91 : struct tevent_req *req = tevent_req_callback_data(
663 : subreq, struct tevent_req);
664 91 : struct wb_domain_request_state *state = tevent_req_data(
665 : req, struct wb_domain_request_state);
666 0 : NTSTATUS status;
667 :
668 91 : state->pending_subreq = NULL;
669 :
670 91 : status = dcerpc_wbint_InitConnection_r_recv(subreq, state);
671 91 : TALLOC_FREE(subreq);
672 91 : if (NT_STATUS_IS_ERR(status)) {
673 0 : tevent_req_error(req, map_errno_from_nt_status(status));
674 0 : return;
675 : }
676 :
677 91 : status = state->r.out.result;
678 91 : if (NT_STATUS_IS_ERR(status)) {
679 0 : tevent_req_error(req, map_errno_from_nt_status(status));
680 0 : return;
681 : }
682 :
683 91 : state->domain->sid = *state->r.out.sid;
684 :
685 91 : talloc_free(state->domain->name);
686 91 : state->domain->name = talloc_strdup(state->domain, *state->r.out.name);
687 91 : if (state->domain->name == NULL) {
688 0 : tevent_req_error(req, ENOMEM);
689 0 : return;
690 : }
691 :
692 91 : if (*state->r.out.alt_name != NULL &&
693 35 : strlen(*state->r.out.alt_name) > 0) {
694 32 : talloc_free(state->domain->alt_name);
695 :
696 64 : state->domain->alt_name = talloc_strdup(state->domain,
697 32 : *state->r.out.alt_name);
698 32 : if (state->domain->alt_name == NULL) {
699 0 : tevent_req_error(req, ENOMEM);
700 0 : return;
701 : }
702 : }
703 :
704 91 : state->domain->native_mode =
705 91 : (*state->r.out.flags & WB_DOMINFO_DOMAIN_NATIVE);
706 91 : state->domain->active_directory =
707 91 : (*state->r.out.flags & WB_DOMINFO_DOMAIN_AD);
708 91 : state->domain->initialized = true;
709 :
710 91 : subreq = wb_child_request_send(state, state->ev, state->child,
711 : state->request);
712 91 : if (tevent_req_nomem(subreq, req)) {
713 0 : return;
714 : }
715 91 : tevent_req_set_callback(subreq, wb_domain_request_done, req);
716 91 : state->pending_subreq = subreq;
717 :
718 : /*
719 : * Once the domain is initialized and
720 : * once we placed our real request into the child queue,
721 : * we can remove ourself from the domain queue
722 : * and give the next one in the queue the chance
723 : * to check for an idle child.
724 : */
725 91 : TALLOC_FREE(state->queue_entry);
726 : }
727 :
728 22667 : static void wb_domain_request_done(struct tevent_req *subreq)
729 : {
730 22667 : struct tevent_req *req = tevent_req_callback_data(
731 : subreq, struct tevent_req);
732 22667 : struct wb_domain_request_state *state = tevent_req_data(
733 : req, struct wb_domain_request_state);
734 0 : int ret, err;
735 :
736 22667 : state->pending_subreq = NULL;
737 :
738 22667 : ret = wb_child_request_recv(subreq, talloc_tos(), &state->response,
739 : &err);
740 22667 : TALLOC_FREE(subreq);
741 22667 : if (ret == -1) {
742 0 : tevent_req_error(req, err);
743 0 : return;
744 : }
745 22667 : tevent_req_done(req);
746 : }
747 :
748 22667 : int wb_domain_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
749 : struct winbindd_response **presponse, int *err)
750 : {
751 22667 : struct wb_domain_request_state *state = tevent_req_data(
752 : req, struct wb_domain_request_state);
753 :
754 22667 : if (tevent_req_is_unix_error(req, err)) {
755 0 : return -1;
756 : }
757 22667 : *presponse = talloc_move(mem_ctx, &state->response);
758 22667 : return 0;
759 : }
760 :
761 0 : static void child_process_request(struct winbindd_child *child,
762 : struct winbindd_cli_state *state)
763 : {
764 0 : struct winbindd_domain *domain = child->domain;
765 :
766 : /* Free response data - we may be interrupted and receive another
767 : command before being able to send this data off. */
768 :
769 0 : state->response->result = WINBINDD_ERROR;
770 0 : state->response->length = sizeof(struct winbindd_response);
771 :
772 : /* as all requests in the child are sync, we can use talloc_tos() */
773 0 : state->mem_ctx = talloc_tos();
774 :
775 : /* Process command */
776 0 : state->response->result = winbindd_dual_ndrcmd(domain, state);
777 0 : }
778 :
779 203 : void setup_child(struct winbindd_domain *domain, struct winbindd_child *child,
780 : const char *logprefix,
781 : const char *logname)
782 : {
783 0 : const struct loadparm_substitution *lp_sub =
784 203 : loadparm_s3_global_substitution();
785 :
786 406 : if (logprefix && logname) {
787 203 : char *logbase = NULL;
788 :
789 203 : if (*lp_logfile(talloc_tos(), lp_sub)) {
790 203 : char *end = NULL;
791 :
792 203 : if (asprintf(&logbase, "%s", lp_logfile(talloc_tos(), lp_sub)) < 0) {
793 0 : smb_panic("Internal error: asprintf failed");
794 : }
795 :
796 203 : if ((end = strrchr_m(logbase, '/'))) {
797 203 : *end = '\0';
798 : }
799 : } else {
800 0 : if (asprintf(&logbase, "%s", get_dyn_LOGFILEBASE()) < 0) {
801 0 : smb_panic("Internal error: asprintf failed");
802 : }
803 : }
804 :
805 203 : if (asprintf(&child->logfilename, "%s/%s-%s",
806 : logbase, logprefix, logname) < 0) {
807 0 : SAFE_FREE(logbase);
808 0 : smb_panic("Internal error: asprintf failed");
809 : }
810 :
811 203 : SAFE_FREE(logbase);
812 : } else {
813 0 : smb_panic("Internal error: logprefix == NULL && "
814 : "logname == NULL");
815 : }
816 :
817 203 : child->pid = 0;
818 203 : child->sock = -1;
819 203 : child->domain = domain;
820 203 : child->queue = tevent_queue_create(NULL, "winbind_child");
821 203 : SMB_ASSERT(child->queue != NULL);
822 :
823 203 : child->binding_handle = wbint_binding_handle(NULL, NULL, child);
824 203 : SMB_ASSERT(child->binding_handle != NULL);
825 203 : }
826 :
827 : struct winbind_child_died_state {
828 : pid_t pid;
829 : struct winbindd_child *child;
830 : };
831 :
832 63 : static bool winbind_child_died_fn(struct winbindd_child *child,
833 : void *private_data)
834 : {
835 63 : struct winbind_child_died_state *state = private_data;
836 :
837 63 : if (child->pid == state->pid) {
838 0 : state->child = child;
839 0 : return false;
840 : }
841 63 : return true;
842 : }
843 :
844 21 : void winbind_child_died(pid_t pid)
845 : {
846 21 : struct winbind_child_died_state state = { .pid = pid };
847 :
848 21 : forall_children(winbind_child_died_fn, &state);
849 :
850 21 : if (state.child == NULL) {
851 21 : DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
852 21 : return;
853 : }
854 :
855 0 : state.child->pid = 0;
856 : }
857 :
858 : /* Ensure any negative cache entries with the netbios or realm names are removed. */
859 :
860 45 : void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
861 : {
862 45 : flush_negative_conn_cache_for_domain(domain->name);
863 45 : if (domain->alt_name != NULL) {
864 45 : flush_negative_conn_cache_for_domain(domain->alt_name);
865 : }
866 45 : }
867 :
868 : /*
869 : * Parent winbindd process sets its own debug level first and then
870 : * sends a message to all the winbindd children to adjust their debug
871 : * level to that of parents.
872 : */
873 :
874 : struct winbind_msg_relay_state {
875 : struct messaging_context *msg_ctx;
876 : uint32_t msg_type;
877 : DATA_BLOB *data;
878 : };
879 :
880 246 : static bool winbind_msg_relay_fn(struct winbindd_child *child,
881 : void *private_data)
882 : {
883 246 : struct winbind_msg_relay_state *state = private_data;
884 :
885 246 : DBG_DEBUG("sending message to pid %u.\n",
886 : (unsigned int)child->pid);
887 :
888 246 : messaging_send(state->msg_ctx, pid_to_procid(child->pid),
889 246 : state->msg_type, state->data);
890 246 : return true;
891 : }
892 :
893 0 : void winbind_msg_debug(struct messaging_context *msg_ctx,
894 : void *private_data,
895 : uint32_t msg_type,
896 : struct server_id server_id,
897 : DATA_BLOB *data)
898 : {
899 0 : struct winbind_msg_relay_state state = {
900 : .msg_ctx = msg_ctx, .msg_type = msg_type, .data = data
901 : };
902 :
903 0 : DEBUG(10,("winbind_msg_debug: got debug message.\n"));
904 :
905 0 : debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data);
906 :
907 0 : forall_children(winbind_msg_relay_fn, &state);
908 0 : }
909 :
910 0 : void winbind_disconnect_dc_parent(struct messaging_context *msg_ctx,
911 : void *private_data,
912 : uint32_t msg_type,
913 : struct server_id server_id,
914 : DATA_BLOB *data)
915 : {
916 0 : struct winbind_msg_relay_state state = {
917 : .msg_ctx = msg_ctx, .msg_type = msg_type, .data = data
918 : };
919 :
920 0 : DBG_DEBUG("Got disconnect_dc message\n");
921 :
922 0 : forall_children(winbind_msg_relay_fn, &state);
923 0 : }
924 :
925 0 : static bool winbindd_child_msg_filter(struct messaging_rec *rec,
926 : void *private_data)
927 : {
928 0 : struct winbindd_child *child = talloc_get_type_abort(private_data,
929 : struct winbindd_child);
930 :
931 0 : if (rec->msg_type == MSG_SMB_CONF_UPDATED) {
932 0 : DBG_DEBUG("Got reload-config message\n");
933 0 : winbindd_reload_services_file(child->logfilename);
934 : }
935 :
936 0 : return false;
937 : }
938 :
939 : /* React on 'smbcontrol winbindd reload-config' in the same way as on SIGHUP*/
940 82 : void winbindd_msg_reload_services_parent(struct messaging_context *msg,
941 : void *private_data,
942 : uint32_t msg_type,
943 : struct server_id server_id,
944 : DATA_BLOB *data)
945 : {
946 82 : struct winbind_msg_relay_state state = {
947 : .msg_ctx = msg,
948 : .msg_type = msg_type,
949 : .data = data,
950 : };
951 :
952 82 : DBG_DEBUG("Got reload-config message\n");
953 :
954 : /* Flush various caches */
955 82 : winbindd_flush_caches();
956 :
957 82 : winbindd_reload_services_file((const char *)private_data);
958 :
959 : /* Set tevent_thread_call_depth_set_callback according to debug level */
960 82 : if (lp_winbind_debug_traceid() && debuglevel_get() > 1) {
961 0 : tevent_thread_call_depth_set_callback(winbind_call_flow, NULL);
962 : } else {
963 82 : tevent_thread_call_depth_set_callback(NULL, NULL);
964 : }
965 :
966 82 : forall_children(winbind_msg_relay_fn, &state);
967 82 : }
968 :
969 : /* Set our domains as offline and forward the offline message to our children. */
970 :
971 : struct winbind_msg_on_offline_state {
972 : struct messaging_context *msg_ctx;
973 : uint32_t msg_type;
974 : };
975 :
976 8 : static bool winbind_msg_on_offline_fn(struct winbindd_child *child,
977 : void *private_data)
978 : {
979 8 : struct winbind_msg_on_offline_state *state = private_data;
980 :
981 8 : if (child->domain->internal) {
982 4 : return true;
983 : }
984 :
985 : /*
986 : * Each winbindd child should only process requests for one
987 : * domain - make sure we only set it online / offline for that
988 : * domain.
989 : */
990 4 : DBG_DEBUG("sending message to pid %u for domain %s.\n",
991 : (unsigned int)child->pid, child->domain->name);
992 :
993 4 : messaging_send_buf(state->msg_ctx,
994 : pid_to_procid(child->pid),
995 : state->msg_type,
996 4 : (const uint8_t *)child->domain->name,
997 4 : strlen(child->domain->name)+1);
998 :
999 4 : return true;
1000 : }
1001 :
1002 4 : void winbind_msg_offline(struct messaging_context *msg_ctx,
1003 : void *private_data,
1004 : uint32_t msg_type,
1005 : struct server_id server_id,
1006 : DATA_BLOB *data)
1007 : {
1008 4 : struct winbind_msg_on_offline_state state = {
1009 : .msg_ctx = msg_ctx,
1010 : .msg_type = MSG_WINBIND_OFFLINE,
1011 : };
1012 0 : struct winbindd_domain *domain;
1013 :
1014 4 : DEBUG(10,("winbind_msg_offline: got offline message.\n"));
1015 :
1016 4 : if (!lp_winbind_offline_logon()) {
1017 0 : DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
1018 0 : return;
1019 : }
1020 :
1021 : /* Set our global state as offline. */
1022 4 : if (!set_global_winbindd_state_offline()) {
1023 0 : DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
1024 0 : return;
1025 : }
1026 :
1027 : /* Set all our domains as offline. */
1028 16 : for (domain = domain_list(); domain; domain = domain->next) {
1029 12 : if (domain->internal) {
1030 8 : continue;
1031 : }
1032 4 : DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
1033 4 : domain->online = false;
1034 : }
1035 :
1036 4 : forall_domain_children(winbind_msg_on_offline_fn, &state);
1037 : }
1038 :
1039 : /* Set our domains as online and forward the online message to our children. */
1040 :
1041 0 : void winbind_msg_online(struct messaging_context *msg_ctx,
1042 : void *private_data,
1043 : uint32_t msg_type,
1044 : struct server_id server_id,
1045 : DATA_BLOB *data)
1046 : {
1047 0 : struct winbind_msg_on_offline_state state = {
1048 : .msg_ctx = msg_ctx,
1049 : .msg_type = MSG_WINBIND_ONLINE,
1050 : };
1051 :
1052 0 : DEBUG(10,("winbind_msg_online: got online message.\n"));
1053 :
1054 0 : if (!lp_winbind_offline_logon()) {
1055 0 : DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
1056 0 : return;
1057 : }
1058 :
1059 : /* Set our global state as online. */
1060 0 : set_global_winbindd_state_online();
1061 :
1062 0 : smb_nscd_flush_user_cache();
1063 0 : smb_nscd_flush_group_cache();
1064 :
1065 : /* Tell all our child domains to go online online. */
1066 0 : forall_domain_children(winbind_msg_on_offline_fn, &state);
1067 : }
1068 :
1069 0 : static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
1070 : {
1071 0 : struct winbindd_domain *domain;
1072 0 : char *buf = NULL;
1073 :
1074 0 : if ((buf = talloc_asprintf(mem_ctx, "global:%s ",
1075 0 : get_global_winbindd_state_offline() ?
1076 : "Offline":"Online")) == NULL) {
1077 0 : return NULL;
1078 : }
1079 :
1080 0 : for (domain = domain_list(); domain; domain = domain->next) {
1081 0 : if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ",
1082 : domain->name,
1083 0 : domain->online ?
1084 : "Online":"Offline")) == NULL) {
1085 0 : return NULL;
1086 : }
1087 : }
1088 :
1089 0 : buf = talloc_asprintf_append_buffer(buf, "\n");
1090 :
1091 0 : DEBUG(5,("collect_onlinestatus: %s", buf));
1092 :
1093 0 : return buf;
1094 : }
1095 :
1096 0 : void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
1097 : void *private_data,
1098 : uint32_t msg_type,
1099 : struct server_id server_id,
1100 : DATA_BLOB *data)
1101 : {
1102 0 : TALLOC_CTX *mem_ctx;
1103 0 : const char *message;
1104 :
1105 0 : DEBUG(5,("winbind_msg_onlinestatus received.\n"));
1106 :
1107 0 : mem_ctx = talloc_init("winbind_msg_onlinestatus");
1108 0 : if (mem_ctx == NULL) {
1109 0 : return;
1110 : }
1111 :
1112 0 : message = collect_onlinestatus(mem_ctx);
1113 0 : if (message == NULL) {
1114 0 : talloc_destroy(mem_ctx);
1115 0 : return;
1116 : }
1117 :
1118 0 : messaging_send_buf(msg_ctx, server_id, MSG_WINBIND_ONLINESTATUS,
1119 0 : (const uint8_t *)message, strlen(message) + 1);
1120 :
1121 0 : talloc_destroy(mem_ctx);
1122 : }
1123 :
1124 0 : void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
1125 : void *private_data,
1126 : uint32_t msg_type,
1127 : struct server_id server_id,
1128 : DATA_BLOB *data)
1129 : {
1130 0 : TALLOC_CTX *mem_ctx;
1131 0 : const char *message = NULL;
1132 0 : const char *domain = NULL;
1133 0 : char *s = NULL;
1134 0 : NTSTATUS status;
1135 0 : struct winbindd_domain *dom = NULL;
1136 :
1137 0 : DEBUG(5,("winbind_msg_dump_domain_list received.\n"));
1138 :
1139 0 : mem_ctx = talloc_init("winbind_msg_dump_domain_list");
1140 0 : if (!mem_ctx) {
1141 0 : return;
1142 : }
1143 :
1144 0 : if (data->length > 0) {
1145 0 : domain = (const char *)data->data;
1146 : }
1147 :
1148 0 : if (domain) {
1149 :
1150 0 : DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n",
1151 : domain));
1152 :
1153 0 : message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain,
1154 : find_domain_from_name_noinit(domain));
1155 0 : if (!message) {
1156 0 : talloc_destroy(mem_ctx);
1157 0 : return;
1158 : }
1159 :
1160 0 : messaging_send_buf(msg_ctx, server_id,
1161 : MSG_WINBIND_DUMP_DOMAIN_LIST,
1162 0 : (const uint8_t *)message, strlen(message) + 1);
1163 :
1164 0 : talloc_destroy(mem_ctx);
1165 :
1166 0 : return;
1167 : }
1168 :
1169 0 : DEBUG(5,("winbind_msg_dump_domain_list all domains\n"));
1170 :
1171 0 : for (dom = domain_list(); dom; dom=dom->next) {
1172 0 : message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, dom);
1173 0 : if (!message) {
1174 0 : talloc_destroy(mem_ctx);
1175 0 : return;
1176 : }
1177 :
1178 0 : s = talloc_asprintf_append(s, "%s\n", message);
1179 0 : if (!s) {
1180 0 : talloc_destroy(mem_ctx);
1181 0 : return;
1182 : }
1183 : }
1184 :
1185 0 : status = messaging_send_buf(msg_ctx, server_id,
1186 : MSG_WINBIND_DUMP_DOMAIN_LIST,
1187 0 : (uint8_t *)s, strlen(s) + 1);
1188 0 : if (!NT_STATUS_IS_OK(status)) {
1189 0 : DEBUG(0,("failed to send message: %s\n",
1190 : nt_errstr(status)));
1191 : }
1192 :
1193 0 : talloc_destroy(mem_ctx);
1194 : }
1195 :
1196 0 : static void account_lockout_policy_handler(struct tevent_context *ctx,
1197 : struct tevent_timer *te,
1198 : struct timeval now,
1199 : void *private_data)
1200 : {
1201 0 : struct winbindd_child *child =
1202 : (struct winbindd_child *)private_data;
1203 0 : TALLOC_CTX *mem_ctx = NULL;
1204 0 : struct samr_DomInfo12 lockout_policy;
1205 0 : NTSTATUS result;
1206 :
1207 0 : DEBUG(10,("account_lockout_policy_handler called\n"));
1208 :
1209 0 : TALLOC_FREE(child->lockout_policy_event);
1210 :
1211 0 : if ( !winbindd_can_contact_domain( child->domain ) ) {
1212 0 : DEBUG(10,("account_lockout_policy_handler: Removing myself since I "
1213 : "do not have an incoming trust to domain %s\n",
1214 : child->domain->name));
1215 :
1216 0 : return;
1217 : }
1218 :
1219 0 : mem_ctx = talloc_init("account_lockout_policy_handler ctx");
1220 0 : if (!mem_ctx) {
1221 0 : result = NT_STATUS_NO_MEMORY;
1222 : } else {
1223 0 : result = wb_cache_lockout_policy(child->domain, mem_ctx,
1224 : &lockout_policy);
1225 : }
1226 0 : TALLOC_FREE(mem_ctx);
1227 :
1228 0 : if (!NT_STATUS_IS_OK(result)) {
1229 0 : DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
1230 : nt_errstr(result)));
1231 : }
1232 :
1233 0 : child->lockout_policy_event = tevent_add_timer(global_event_context(), NULL,
1234 : timeval_current_ofs(3600, 0),
1235 : account_lockout_policy_handler,
1236 : child);
1237 : }
1238 :
1239 0 : static time_t get_machine_password_timeout(void)
1240 : {
1241 : /* until we have gpo support use lp setting */
1242 0 : return lp_machine_password_timeout();
1243 : }
1244 :
1245 0 : static bool calculate_next_machine_pwd_change(const char *domain,
1246 : struct timeval *t)
1247 : {
1248 0 : time_t pass_last_set_time;
1249 0 : time_t timeout;
1250 0 : time_t next_change;
1251 0 : struct timeval tv;
1252 0 : char *pw;
1253 :
1254 0 : pw = secrets_fetch_machine_password(domain,
1255 : &pass_last_set_time,
1256 : NULL);
1257 :
1258 0 : if (pw == NULL) {
1259 0 : DEBUG(0,("cannot fetch own machine password ????\n"));
1260 0 : return false;
1261 : }
1262 :
1263 0 : SAFE_FREE(pw);
1264 :
1265 0 : timeout = get_machine_password_timeout();
1266 0 : if (timeout == 0) {
1267 0 : DEBUG(10,("machine password never expires\n"));
1268 0 : return false;
1269 : }
1270 :
1271 0 : tv.tv_sec = pass_last_set_time;
1272 0 : DEBUG(10, ("password last changed %s\n",
1273 : timeval_string(talloc_tos(), &tv, false)));
1274 0 : tv.tv_sec += timeout;
1275 0 : DEBUGADD(10, ("password valid until %s\n",
1276 : timeval_string(talloc_tos(), &tv, false)));
1277 :
1278 0 : if (time(NULL) < (pass_last_set_time + timeout)) {
1279 0 : next_change = pass_last_set_time + timeout;
1280 0 : DEBUG(10,("machine password still valid until: %s\n",
1281 : http_timestring(talloc_tos(), next_change)));
1282 0 : *t = timeval_set(next_change, 0);
1283 :
1284 0 : if (lp_clustering()) {
1285 0 : uint8_t randbuf;
1286 : /*
1287 : * When having a cluster, we have several
1288 : * winbinds racing for the password change. In
1289 : * the machine_password_change_handler()
1290 : * function we check if someone else was
1291 : * faster when the event triggers. We add a
1292 : * 255-second random delay here, so that we
1293 : * don't run to change the password at the
1294 : * exact same moment.
1295 : */
1296 0 : generate_random_buffer(&randbuf, sizeof(randbuf));
1297 0 : DEBUG(10, ("adding %d seconds randomness\n",
1298 : (int)randbuf));
1299 0 : t->tv_sec += randbuf;
1300 : }
1301 0 : return true;
1302 : }
1303 :
1304 0 : DEBUG(10,("machine password expired, needs immediate change\n"));
1305 :
1306 0 : *t = timeval_zero();
1307 :
1308 0 : return true;
1309 : }
1310 :
1311 0 : static void machine_password_change_handler(struct tevent_context *ctx,
1312 : struct tevent_timer *te,
1313 : struct timeval now,
1314 : void *private_data)
1315 : {
1316 0 : struct messaging_context *msg_ctx = global_messaging_context();
1317 0 : struct winbindd_child *child =
1318 : (struct winbindd_child *)private_data;
1319 0 : struct rpc_pipe_client *netlogon_pipe = NULL;
1320 0 : struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1321 0 : NTSTATUS result;
1322 0 : struct timeval next_change;
1323 :
1324 0 : DEBUG(10,("machine_password_change_handler called\n"));
1325 :
1326 0 : TALLOC_FREE(child->machine_password_change_event);
1327 :
1328 0 : if (!calculate_next_machine_pwd_change(child->domain->name,
1329 : &next_change)) {
1330 0 : DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
1331 0 : return;
1332 : }
1333 :
1334 0 : DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
1335 : timeval_string(talloc_tos(), &next_change, false)));
1336 :
1337 0 : if (!timeval_expired(&next_change)) {
1338 0 : DEBUG(10, ("Someone else has already changed the pw\n"));
1339 0 : goto done;
1340 : }
1341 :
1342 0 : if (!winbindd_can_contact_domain(child->domain)) {
1343 0 : DEBUG(10,("machine_password_change_handler: Removing myself since I "
1344 : "do not have an incoming trust to domain %s\n",
1345 : child->domain->name));
1346 0 : return;
1347 : }
1348 :
1349 0 : result = cm_connect_netlogon_secure(child->domain,
1350 : &netlogon_pipe,
1351 : &netlogon_creds_ctx);
1352 0 : if (!NT_STATUS_IS_OK(result)) {
1353 0 : DEBUG(10,("machine_password_change_handler: "
1354 : "failed to connect netlogon pipe: %s\n",
1355 : nt_errstr(result)));
1356 0 : return;
1357 : }
1358 :
1359 0 : result = trust_pw_change(netlogon_creds_ctx,
1360 : msg_ctx,
1361 0 : netlogon_pipe->binding_handle,
1362 0 : child->domain->name,
1363 0 : child->domain->dcname,
1364 : false); /* force */
1365 :
1366 0 : DEBUG(10, ("machine_password_change_handler: "
1367 : "trust_pw_change returned %s\n",
1368 : nt_errstr(result)));
1369 :
1370 0 : if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1371 0 : DEBUG(3,("machine_password_change_handler: password set returned "
1372 : "ACCESS_DENIED. Maybe the trust account "
1373 : "password was changed and we didn't know it. "
1374 : "Killing connections to domain %s\n",
1375 : child->domain->name));
1376 0 : invalidate_cm_connection(child->domain);
1377 : }
1378 :
1379 0 : if (!calculate_next_machine_pwd_change(child->domain->name,
1380 : &next_change)) {
1381 0 : DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
1382 0 : return;
1383 : }
1384 :
1385 0 : DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
1386 : timeval_string(talloc_tos(), &next_change, false)));
1387 :
1388 0 : if (!NT_STATUS_IS_OK(result)) {
1389 0 : struct timeval tmp;
1390 : /*
1391 : * In case of failure, give the DC a minute to recover
1392 : */
1393 0 : tmp = timeval_current_ofs(60, 0);
1394 0 : next_change = timeval_max(&next_change, &tmp);
1395 : }
1396 :
1397 0 : done:
1398 0 : child->machine_password_change_event = tevent_add_timer(global_event_context(), NULL,
1399 : next_change,
1400 : machine_password_change_handler,
1401 : child);
1402 : }
1403 :
1404 : /* Deal with a request to go offline. */
1405 :
1406 0 : static void child_msg_offline(struct messaging_context *msg,
1407 : void *private_data,
1408 : uint32_t msg_type,
1409 : struct server_id server_id,
1410 : DATA_BLOB *data)
1411 : {
1412 0 : struct winbindd_domain *domain;
1413 0 : struct winbindd_domain *primary_domain = NULL;
1414 0 : const char *domainname = (const char *)data->data;
1415 :
1416 0 : if (data->data == NULL || data->length == 0) {
1417 0 : return;
1418 : }
1419 :
1420 0 : DEBUG(5,("child_msg_offline received for domain %s.\n", domainname));
1421 :
1422 0 : if (!lp_winbind_offline_logon()) {
1423 0 : DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
1424 0 : return;
1425 : }
1426 :
1427 0 : primary_domain = find_our_domain();
1428 :
1429 : /* Mark the requested domain offline. */
1430 :
1431 0 : for (domain = domain_list(); domain; domain = domain->next) {
1432 0 : if (domain->internal) {
1433 0 : continue;
1434 : }
1435 0 : if (strequal(domain->name, domainname)) {
1436 0 : DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name));
1437 0 : set_domain_offline(domain);
1438 : /* we are in the trusted domain, set the primary domain
1439 : * offline too */
1440 0 : if (domain != primary_domain) {
1441 0 : set_domain_offline(primary_domain);
1442 : }
1443 : }
1444 : }
1445 : }
1446 :
1447 : /* Deal with a request to go online. */
1448 :
1449 0 : static void child_msg_online(struct messaging_context *msg,
1450 : void *private_data,
1451 : uint32_t msg_type,
1452 : struct server_id server_id,
1453 : DATA_BLOB *data)
1454 : {
1455 0 : struct winbindd_domain *domain;
1456 0 : struct winbindd_domain *primary_domain = NULL;
1457 0 : const char *domainname = (const char *)data->data;
1458 :
1459 0 : if (data->data == NULL || data->length == 0) {
1460 0 : return;
1461 : }
1462 :
1463 0 : DEBUG(5,("child_msg_online received for domain %s.\n", domainname));
1464 :
1465 0 : if (!lp_winbind_offline_logon()) {
1466 0 : DEBUG(10,("child_msg_online: rejecting online message.\n"));
1467 0 : return;
1468 : }
1469 :
1470 0 : primary_domain = find_our_domain();
1471 :
1472 : /* Set our global state as online. */
1473 0 : set_global_winbindd_state_online();
1474 :
1475 : /* Try and mark everything online - delete any negative cache entries
1476 : to force a reconnect now. */
1477 :
1478 0 : for (domain = domain_list(); domain; domain = domain->next) {
1479 0 : if (domain->internal) {
1480 0 : continue;
1481 : }
1482 0 : if (strequal(domain->name, domainname)) {
1483 0 : DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name));
1484 0 : winbindd_flush_negative_conn_cache(domain);
1485 0 : set_domain_online_request(domain);
1486 :
1487 : /* we can be in trusted domain, which will contact primary domain
1488 : * we have to bring primary domain online in trusted domain process
1489 : * see, winbindd_dual_pam_auth() --> winbindd_dual_pam_auth_samlogon()
1490 : * --> contact_domain = find_our_domain()
1491 : * */
1492 0 : if (domain != primary_domain) {
1493 0 : winbindd_flush_negative_conn_cache(primary_domain);
1494 0 : set_domain_online_request(primary_domain);
1495 : }
1496 : }
1497 : }
1498 : }
1499 :
1500 : struct winbindd_reinit_after_fork_state {
1501 : const struct winbindd_child *myself;
1502 : };
1503 :
1504 0 : static bool winbindd_reinit_after_fork_fn(struct winbindd_child *child,
1505 : void *private_data)
1506 : {
1507 0 : struct winbindd_reinit_after_fork_state *state = private_data;
1508 :
1509 0 : if (child == state->myself) {
1510 0 : return true;
1511 : }
1512 :
1513 : /* Destroy all possible events in child list. */
1514 0 : TALLOC_FREE(child->lockout_policy_event);
1515 0 : TALLOC_FREE(child->machine_password_change_event);
1516 :
1517 : /*
1518 : * Children should never be able to send each other messages,
1519 : * all messages must go through the parent.
1520 : */
1521 0 : child->pid = (pid_t)0;
1522 :
1523 : /*
1524 : * Close service sockets to all other children
1525 : */
1526 0 : if (child->sock != -1) {
1527 0 : close(child->sock);
1528 0 : child->sock = -1;
1529 : }
1530 :
1531 0 : return true;
1532 : }
1533 :
1534 0 : NTSTATUS winbindd_reinit_after_fork(const struct winbindd_child *myself,
1535 : const char *logfilename)
1536 : {
1537 0 : struct winbindd_reinit_after_fork_state state = { .myself = myself };
1538 0 : struct winbindd_domain *domain;
1539 0 : NTSTATUS status;
1540 :
1541 0 : status = reinit_after_fork(
1542 : global_messaging_context(),
1543 : global_event_context(),
1544 : true);
1545 0 : if (!NT_STATUS_IS_OK(status)) {
1546 0 : DEBUG(0,("reinit_after_fork() failed\n"));
1547 0 : return status;
1548 : }
1549 0 : initialize_password_db(true, global_event_context());
1550 :
1551 0 : close_conns_after_fork();
1552 :
1553 0 : if (logfilename != NULL) {
1554 0 : lp_set_logfile(logfilename);
1555 0 : reopen_logs();
1556 : }
1557 :
1558 0 : if (!winbindd_setup_sig_term_handler(false)) {
1559 0 : return NT_STATUS_NO_MEMORY;
1560 : }
1561 :
1562 0 : if (!winbindd_setup_sig_hup_handler(logfilename)) {
1563 0 : return NT_STATUS_NO_MEMORY;
1564 : }
1565 :
1566 : /* Stop zombies in children */
1567 0 : CatchChild();
1568 :
1569 : /* Don't handle the same messages as our parent. */
1570 0 : messaging_deregister(global_messaging_context(),
1571 : MSG_SMB_CONF_UPDATED, NULL);
1572 0 : messaging_deregister(global_messaging_context(),
1573 : MSG_SHUTDOWN, NULL);
1574 0 : messaging_deregister(global_messaging_context(),
1575 : MSG_WINBIND_OFFLINE, NULL);
1576 0 : messaging_deregister(global_messaging_context(),
1577 : MSG_WINBIND_ONLINE, NULL);
1578 0 : messaging_deregister(global_messaging_context(),
1579 : MSG_WINBIND_ONLINESTATUS, NULL);
1580 0 : messaging_deregister(global_messaging_context(),
1581 : MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1582 0 : messaging_deregister(global_messaging_context(),
1583 : MSG_DEBUG, NULL);
1584 :
1585 0 : messaging_deregister(global_messaging_context(),
1586 : MSG_WINBIND_DOMAIN_OFFLINE, NULL);
1587 0 : messaging_deregister(global_messaging_context(),
1588 : MSG_WINBIND_DOMAIN_ONLINE, NULL);
1589 :
1590 : /* We have destroyed all events in the winbindd_event_context
1591 : * in reinit_after_fork(), so clean out all possible pending
1592 : * event pointers. */
1593 :
1594 : /* Deal with check_online_events. */
1595 :
1596 0 : for (domain = domain_list(); domain; domain = domain->next) {
1597 0 : TALLOC_FREE(domain->check_online_event);
1598 : }
1599 :
1600 : /* Ensure we're not handling a credential cache event inherited
1601 : * from our parent. */
1602 :
1603 0 : ccache_remove_all_after_fork();
1604 :
1605 0 : forall_children(winbindd_reinit_after_fork_fn, &state);
1606 :
1607 0 : return NT_STATUS_OK;
1608 : }
1609 :
1610 : /*
1611 : * In a child there will be only one domain, reference that here.
1612 : */
1613 : static struct winbindd_domain *child_domain;
1614 :
1615 57 : struct winbindd_domain *wb_child_domain(void)
1616 : {
1617 57 : return child_domain;
1618 : }
1619 :
1620 : struct child_handler_state {
1621 : struct winbindd_child *child;
1622 : struct winbindd_cli_state cli;
1623 : };
1624 :
1625 0 : static void child_handler(struct tevent_context *ev, struct tevent_fd *fde,
1626 : uint16_t flags, void *private_data)
1627 : {
1628 0 : struct child_handler_state *state =
1629 : (struct child_handler_state *)private_data;
1630 0 : NTSTATUS status;
1631 0 : uint64_t parent_traceid;
1632 :
1633 : /* fetch a request from the main daemon */
1634 0 : status = child_read_request(state->cli.sock, state->cli.request);
1635 :
1636 0 : if (!NT_STATUS_IS_OK(status)) {
1637 : /* we lost contact with our parent */
1638 0 : _exit(0);
1639 : }
1640 :
1641 : /* read traceid from request */
1642 0 : parent_traceid = state->cli.request->traceid;
1643 0 : debug_traceid_set(parent_traceid);
1644 :
1645 0 : DEBUG(4,("child daemon request %d\n",
1646 : (int)state->cli.request->cmd));
1647 :
1648 0 : ZERO_STRUCTP(state->cli.response);
1649 0 : state->cli.request->null_term = '\0';
1650 0 : state->cli.mem_ctx = talloc_tos();
1651 0 : child_process_request(state->child, &state->cli);
1652 :
1653 0 : DEBUG(4, ("Finished processing child request %d\n",
1654 : (int)state->cli.request->cmd));
1655 :
1656 0 : SAFE_FREE(state->cli.request->extra_data.data);
1657 :
1658 0 : status = child_write_response(state->cli.sock, state->cli.response);
1659 0 : if (!NT_STATUS_IS_OK(status)) {
1660 0 : exit(1);
1661 : }
1662 0 : }
1663 :
1664 132 : static bool fork_domain_child(struct winbindd_child *child)
1665 : {
1666 0 : int fdpair[2];
1667 0 : struct child_handler_state state;
1668 0 : struct winbindd_request request;
1669 0 : struct winbindd_response response;
1670 132 : struct winbindd_domain *primary_domain = NULL;
1671 0 : NTSTATUS status;
1672 0 : ssize_t nwritten;
1673 0 : struct tevent_fd *fde;
1674 132 : struct tevent_req *req = NULL;
1675 :
1676 132 : if (child->domain) {
1677 91 : DEBUG(10, ("fork_domain_child called for domain '%s'\n",
1678 : child->domain->name));
1679 : } else {
1680 41 : DEBUG(10, ("fork_domain_child called without domain.\n"));
1681 : }
1682 :
1683 132 : if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) {
1684 0 : DEBUG(0, ("Could not open child pipe: %s\n",
1685 : strerror(errno)));
1686 0 : return False;
1687 : }
1688 :
1689 132 : ZERO_STRUCT(state);
1690 132 : state.child = child;
1691 132 : state.cli.pid = getpid();
1692 132 : state.cli.request = &request;
1693 132 : state.cli.response = &response;
1694 :
1695 132 : child->pid = fork();
1696 :
1697 132 : if (child->pid == -1) {
1698 0 : DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
1699 0 : close(fdpair[0]);
1700 0 : close(fdpair[1]);
1701 0 : return False;
1702 : }
1703 :
1704 132 : if (child->pid != 0) {
1705 : /* Parent */
1706 0 : ssize_t nread;
1707 0 : int rc;
1708 :
1709 132 : close(fdpair[0]);
1710 :
1711 132 : nread = sys_read(fdpair[1], &status, sizeof(status));
1712 132 : if (nread != sizeof(status)) {
1713 0 : DEBUG(1, ("fork_domain_child: Could not read child status: "
1714 : "nread=%d, error=%s\n", (int)nread,
1715 : strerror(errno)));
1716 0 : close(fdpair[1]);
1717 0 : return false;
1718 : }
1719 132 : if (!NT_STATUS_IS_OK(status)) {
1720 0 : DEBUG(1, ("fork_domain_child: Child status is %s\n",
1721 : nt_errstr(status)));
1722 0 : close(fdpair[1]);
1723 0 : return false;
1724 : }
1725 :
1726 132 : child->monitor_fde = tevent_add_fd(global_event_context(),
1727 : global_event_context(),
1728 : fdpair[1],
1729 : TEVENT_FD_READ,
1730 : child_socket_readable,
1731 : child);
1732 132 : if (child->monitor_fde == NULL) {
1733 0 : DBG_WARNING("tevent_add_fd failed\n");
1734 0 : close(fdpair[1]);
1735 0 : return false;
1736 : }
1737 :
1738 132 : rc = set_blocking(fdpair[1], false);
1739 132 : if (rc < 0) {
1740 0 : close(fdpair[1]);
1741 0 : return false;
1742 : }
1743 :
1744 132 : child->sock = fdpair[1];
1745 :
1746 132 : return true;
1747 : }
1748 :
1749 : /* Child */
1750 0 : child_domain = child->domain;
1751 :
1752 0 : DEBUG(10, ("Child process %d\n", (int)getpid()));
1753 :
1754 0 : state.cli.sock = fdpair[0];
1755 0 : close(fdpair[1]);
1756 :
1757 : /* Reset traceid and deactivate call_depth tracking */
1758 0 : if (lp_winbind_debug_traceid()) {
1759 0 : debug_traceid_set(1);
1760 0 : tevent_thread_call_depth_set_callback(NULL, NULL);
1761 : }
1762 :
1763 0 : status = winbindd_reinit_after_fork(child, child->logfilename);
1764 :
1765 : /* setup callbacks again, one of them is removed in reinit_after_fork */
1766 0 : if (lp_winbind_debug_traceid()) {
1767 0 : winbind_debug_traceid_setup(global_event_context());
1768 : }
1769 :
1770 0 : nwritten = sys_write(state.cli.sock, &status, sizeof(status));
1771 0 : if (nwritten != sizeof(status)) {
1772 0 : DEBUG(1, ("fork_domain_child: Could not write status: "
1773 : "nwritten=%d, error=%s\n", (int)nwritten,
1774 : strerror(errno)));
1775 0 : _exit(0);
1776 : }
1777 0 : if (!NT_STATUS_IS_OK(status)) {
1778 0 : DEBUG(1, ("winbindd_reinit_after_fork failed: %s\n",
1779 : nt_errstr(status)));
1780 0 : _exit(0);
1781 : }
1782 :
1783 0 : if (child_domain != NULL) {
1784 0 : process_set_title("wb[%s]", "domain child [%s]", child_domain->name);
1785 0 : } else if (is_idmap_child(child)) {
1786 0 : process_set_title("wb-idmap", "idmap child");
1787 : }
1788 :
1789 : /* Handle online/offline messages. */
1790 0 : messaging_register(global_messaging_context(), NULL,
1791 : MSG_WINBIND_OFFLINE, child_msg_offline);
1792 0 : messaging_register(global_messaging_context(), NULL,
1793 : MSG_WINBIND_ONLINE, child_msg_online);
1794 0 : messaging_register(global_messaging_context(), NULL,
1795 : MSG_DEBUG, debug_message);
1796 0 : messaging_register(global_messaging_context(), NULL,
1797 : MSG_WINBIND_IP_DROPPED,
1798 : winbind_msg_ip_dropped);
1799 0 : messaging_register(global_messaging_context(), NULL,
1800 : MSG_WINBIND_DISCONNECT_DC,
1801 : winbind_msg_disconnect_dc);
1802 :
1803 0 : req = messaging_filtered_read_send(global_event_context(),
1804 : global_event_context(),
1805 : global_messaging_context(),
1806 : winbindd_child_msg_filter,
1807 : child);
1808 0 : if (req == NULL) {
1809 0 : DBG_ERR("messaging_filtered_read_send failed\n");
1810 0 : _exit(1);
1811 : }
1812 :
1813 0 : primary_domain = find_our_domain();
1814 :
1815 0 : if (primary_domain == NULL) {
1816 0 : smb_panic("no primary domain found");
1817 : }
1818 :
1819 : /* It doesn't matter if we allow cache login,
1820 : * try to bring domain online after fork. */
1821 0 : if ( child->domain ) {
1822 0 : child->domain->startup = True;
1823 0 : child->domain->startup_time = time_mono(NULL);
1824 : /* we can be in primary domain or in trusted domain
1825 : * If we are in trusted domain, set the primary domain
1826 : * in start-up mode */
1827 0 : if (!(child->domain->internal)) {
1828 0 : set_domain_online_request(child->domain);
1829 0 : if (!(child->domain->primary)) {
1830 0 : primary_domain->startup = True;
1831 0 : primary_domain->startup_time = time_mono(NULL);
1832 0 : set_domain_online_request(primary_domain);
1833 : }
1834 : }
1835 : }
1836 :
1837 : /* We might be in the idmap child...*/
1838 0 : if (child->domain && !(child->domain->internal) &&
1839 0 : lp_winbind_offline_logon()) {
1840 :
1841 0 : set_domain_online_request(child->domain);
1842 :
1843 0 : if (primary_domain && (primary_domain != child->domain)) {
1844 : /* We need to talk to the primary
1845 : * domain as well as the trusted
1846 : * domain inside a trusted domain
1847 : * child.
1848 : * See the code in :
1849 : * set_dc_type_and_flags_trustinfo()
1850 : * for details.
1851 : */
1852 0 : set_domain_online_request(primary_domain);
1853 : }
1854 :
1855 0 : child->lockout_policy_event = tevent_add_timer(
1856 : global_event_context(), NULL, timeval_zero(),
1857 : account_lockout_policy_handler,
1858 : child);
1859 : }
1860 :
1861 0 : if (child->domain && child->domain->primary &&
1862 0 : !USE_KERBEROS_KEYTAB &&
1863 0 : lp_server_role() == ROLE_DOMAIN_MEMBER) {
1864 :
1865 0 : struct timeval next_change;
1866 :
1867 0 : if (calculate_next_machine_pwd_change(child->domain->name,
1868 : &next_change)) {
1869 0 : child->machine_password_change_event = tevent_add_timer(
1870 : global_event_context(), NULL, next_change,
1871 : machine_password_change_handler,
1872 : child);
1873 : }
1874 : }
1875 :
1876 0 : fde = tevent_add_fd(global_event_context(), NULL, state.cli.sock,
1877 : TEVENT_FD_READ, child_handler, &state);
1878 0 : if (fde == NULL) {
1879 0 : DEBUG(1, ("tevent_add_fd failed\n"));
1880 0 : _exit(1);
1881 : }
1882 :
1883 0 : while (1) {
1884 :
1885 0 : int ret;
1886 0 : TALLOC_CTX *frame = talloc_stackframe();
1887 :
1888 0 : ret = tevent_loop_once(global_event_context());
1889 0 : if (ret != 0) {
1890 0 : DEBUG(1, ("tevent_loop_once failed: %s\n",
1891 : strerror(errno)));
1892 0 : _exit(1);
1893 : }
1894 :
1895 0 : if (child->domain && child->domain->startup &&
1896 0 : (time_mono(NULL) > child->domain->startup_time + 30)) {
1897 : /* No longer in "startup" mode. */
1898 0 : DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
1899 : child->domain->name ));
1900 0 : child->domain->startup = False;
1901 : }
1902 :
1903 0 : TALLOC_FREE(frame);
1904 : }
1905 : }
1906 :
1907 0 : void winbind_msg_ip_dropped_parent(struct messaging_context *msg_ctx,
1908 : void *private_data,
1909 : uint32_t msg_type,
1910 : struct server_id server_id,
1911 : DATA_BLOB *data)
1912 : {
1913 0 : struct winbind_msg_relay_state state = {
1914 : .msg_ctx = msg_ctx,
1915 : .msg_type = msg_type,
1916 : .data = data,
1917 : };
1918 :
1919 0 : winbind_msg_ip_dropped(msg_ctx, private_data, msg_type,
1920 : server_id, data);
1921 :
1922 0 : forall_children(winbind_msg_relay_fn, &state);
1923 0 : }
1924 :
1925 41 : void winbindd_terminate(bool is_parent)
1926 : {
1927 41 : if (is_parent) {
1928 : /* When parent goes away we should
1929 : * remove the socket file. Not so
1930 : * when children terminate.
1931 : */
1932 41 : char *path = NULL;
1933 :
1934 41 : if (asprintf(&path, "%s/%s",
1935 : lp_winbindd_socket_directory(), WINBINDD_SOCKET_NAME) > 0) {
1936 41 : unlink(path);
1937 41 : SAFE_FREE(path);
1938 : }
1939 : }
1940 :
1941 41 : idmap_close();
1942 :
1943 41 : netlogon_creds_cli_close_global_db();
1944 :
1945 : #if 0
1946 : if (interactive) {
1947 : TALLOC_CTX *mem_ctx = talloc_init("end_description");
1948 : char *description = talloc_describe_all(mem_ctx);
1949 :
1950 : DEBUG(3, ("tallocs left:\n%s\n", description));
1951 : talloc_destroy(mem_ctx);
1952 : }
1953 : #endif
1954 :
1955 41 : if (is_parent) {
1956 41 : pidfile_unlink(lp_pid_directory(), "winbindd");
1957 : }
1958 :
1959 41 : exit(0);
1960 : }
1961 :
1962 0 : static void winbindd_sig_term_handler(struct tevent_context *ev,
1963 : struct tevent_signal *se,
1964 : int signum,
1965 : int count,
1966 : void *siginfo,
1967 : void *private_data)
1968 : {
1969 0 : bool *p = talloc_get_type_abort(private_data, bool);
1970 0 : bool is_parent = *p;
1971 :
1972 0 : TALLOC_FREE(p);
1973 :
1974 0 : DEBUG(0,("Got sig[%d] terminate (is_parent=%d)\n",
1975 : signum, is_parent));
1976 0 : winbindd_terminate(is_parent);
1977 0 : }
1978 :
1979 41 : bool winbindd_setup_sig_term_handler(bool parent)
1980 : {
1981 0 : struct tevent_signal *se;
1982 0 : bool *is_parent;
1983 :
1984 41 : is_parent = talloc(global_event_context(), bool);
1985 41 : if (!is_parent) {
1986 0 : return false;
1987 : }
1988 :
1989 41 : *is_parent = parent;
1990 :
1991 41 : se = tevent_add_signal(global_event_context(),
1992 : is_parent,
1993 : SIGTERM, 0,
1994 : winbindd_sig_term_handler,
1995 : is_parent);
1996 41 : if (!se) {
1997 0 : DEBUG(0,("failed to setup SIGTERM handler\n"));
1998 0 : talloc_free(is_parent);
1999 0 : return false;
2000 : }
2001 :
2002 41 : se = tevent_add_signal(global_event_context(),
2003 : is_parent,
2004 : SIGINT, 0,
2005 : winbindd_sig_term_handler,
2006 : is_parent);
2007 41 : if (!se) {
2008 0 : DEBUG(0,("failed to setup SIGINT handler\n"));
2009 0 : talloc_free(is_parent);
2010 0 : return false;
2011 : }
2012 :
2013 41 : se = tevent_add_signal(global_event_context(),
2014 : is_parent,
2015 : SIGQUIT, 0,
2016 : winbindd_sig_term_handler,
2017 : is_parent);
2018 41 : if (!se) {
2019 0 : DEBUG(0,("failed to setup SIGINT handler\n"));
2020 0 : talloc_free(is_parent);
2021 0 : return false;
2022 : }
2023 :
2024 41 : return true;
2025 : }
2026 :
2027 0 : static void flush_caches_noinit(void)
2028 : {
2029 : /*
2030 : * We need to invalidate cached user list entries on a SIGHUP
2031 : * otherwise cached access denied errors due to restrict anonymous
2032 : * hang around until the sequence number changes.
2033 : * NB
2034 : * Skip uninitialized domains when flush cache.
2035 : * If domain is not initialized, it means it is never
2036 : * used or never become online. look, wcache_invalidate_cache()
2037 : * -> get_cache() -> init_dc_connection(). It causes a lot of traffic
2038 : * for unused domains and large traffic for primary domain's DC if there
2039 : * are many domains..
2040 : */
2041 :
2042 0 : if (!wcache_invalidate_cache_noinit()) {
2043 0 : DEBUG(0, ("invalidating the cache failed; revalidate the cache\n"));
2044 0 : if (!winbindd_cache_validate_and_initialize()) {
2045 0 : exit(1);
2046 : }
2047 : }
2048 0 : }
2049 :
2050 0 : static void winbindd_sig_hup_handler(struct tevent_context *ev,
2051 : struct tevent_signal *se,
2052 : int signum,
2053 : int count,
2054 : void *siginfo,
2055 : void *private_data)
2056 : {
2057 0 : const char *file = (const char *)private_data;
2058 :
2059 0 : DEBUG(1,("Reloading services after SIGHUP\n"));
2060 0 : flush_caches_noinit();
2061 0 : winbindd_reload_services_file(file);
2062 0 : }
2063 :
2064 41 : bool winbindd_setup_sig_hup_handler(const char *lfile)
2065 : {
2066 0 : struct tevent_signal *se;
2067 41 : char *file = NULL;
2068 :
2069 41 : if (lfile) {
2070 0 : file = talloc_strdup(global_event_context(),
2071 : lfile);
2072 0 : if (!file) {
2073 0 : return false;
2074 : }
2075 : }
2076 :
2077 41 : se = tevent_add_signal(global_event_context(),
2078 : global_event_context(),
2079 : SIGHUP, 0,
2080 : winbindd_sig_hup_handler,
2081 : file);
2082 41 : if (!se) {
2083 0 : return false;
2084 : }
2085 :
2086 41 : return true;
2087 : }
|