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 113 : 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 383 : for (d = domain_list(); d != NULL; d = d->next) {
63 : int i;
64 :
65 540 : for (i = 0; i < talloc_array_length(d->children); i++) {
66 270 : struct winbindd_child *c = &d->children[i];
67 0 : bool ok;
68 :
69 270 : if (c->pid == 0) {
70 36 : continue;
71 : }
72 :
73 234 : ok = fn(c, private_data);
74 234 : if (!ok) {
75 0 : return;
76 : }
77 : }
78 : }
79 : }
80 :
81 109 : 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 109 : c = idmap_child();
89 109 : if (c->pid != 0) {
90 109 : ok = fn(c, private_data);
91 109 : if (!ok) {
92 0 : return;
93 : }
94 : }
95 :
96 109 : c = locator_child();
97 109 : if (c->pid != 0) {
98 0 : ok = fn(c, private_data);
99 0 : if (!ok) {
100 0 : return;
101 : }
102 : }
103 :
104 109 : 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 132525 : 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 132525 : req = tevent_req_create(mem_ctx, &state,
204 : struct wb_child_request_state);
205 132525 : if (req == NULL) {
206 0 : return NULL;
207 : }
208 :
209 132525 : state->ev = ev;
210 132525 : 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 132525 : state->request = talloc_memdup(state, request, sizeof(*request));
224 132525 : if (tevent_req_nomem(state->request, req)) {
225 0 : return tevent_req_post(req, ev);
226 : }
227 :
228 132525 : state->request->traceid = debug_traceid_get();
229 :
230 132525 : if (request->extra_data.data != NULL) {
231 132525 : state->request->extra_data.data = talloc_memdup(
232 : state->request,
233 : request->extra_data.data,
234 : request->extra_len);
235 132525 : if (tevent_req_nomem(state->request->extra_data.data, req)) {
236 0 : return tevent_req_post(req, ev);
237 : }
238 : }
239 :
240 132525 : subreq = tevent_queue_wait_send(state, ev, child->queue);
241 132525 : if (tevent_req_nomem(subreq, req)) {
242 0 : return tevent_req_post(req, ev);
243 : }
244 132525 : tevent_req_set_callback(subreq, wb_child_request_waited, req);
245 132525 : state->queue_subreq = subreq;
246 :
247 132525 : tevent_req_set_cleanup_fn(req, wb_child_request_cleanup);
248 :
249 132525 : return req;
250 : }
251 :
252 132525 : static void wb_child_request_waited(struct tevent_req *subreq)
253 : {
254 132525 : struct tevent_req *req = tevent_req_callback_data(
255 : subreq, struct tevent_req);
256 132525 : struct wb_child_request_state *state = tevent_req_data(
257 : req, struct wb_child_request_state);
258 0 : bool ok;
259 :
260 132525 : ok = tevent_queue_wait_recv(subreq);
261 132525 : 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 132525 : subreq = NULL;
270 :
271 132525 : if ((state->child->sock == -1) && (!fork_domain_child(state->child))) {
272 0 : tevent_req_error(req, errno);
273 0 : return;
274 : }
275 :
276 132525 : tevent_fd_set_flags(state->child->monitor_fde, 0);
277 :
278 132525 : subreq = wb_simple_trans_send(state, global_event_context(), NULL,
279 132525 : state->child->sock, state->request);
280 132525 : if (tevent_req_nomem(subreq, req)) {
281 0 : return;
282 : }
283 :
284 132525 : state->subreq = subreq;
285 132525 : tevent_req_set_callback(subreq, wb_child_request_done, req);
286 132525 : tevent_req_set_endtime(req, state->ev, timeval_current_ofs(300, 0));
287 : }
288 :
289 132525 : static void wb_child_request_done(struct tevent_req *subreq)
290 : {
291 132525 : struct tevent_req *req = tevent_req_callback_data(
292 : subreq, struct tevent_req);
293 132525 : struct wb_child_request_state *state = tevent_req_data(
294 : req, struct wb_child_request_state);
295 0 : int ret, err;
296 :
297 132525 : 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 132525 : if (ret == -1) {
303 0 : tevent_req_error(req, err);
304 0 : return;
305 : }
306 132525 : 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 132525 : int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
329 : struct winbindd_response **presponse, int *err)
330 : {
331 132525 : struct wb_child_request_state *state = tevent_req_data(
332 : req, struct wb_child_request_state);
333 :
334 132525 : if (tevent_req_is_unix_error(req, err)) {
335 0 : return -1;
336 : }
337 132525 : *presponse = talloc_move(mem_ctx, &state->response);
338 132525 : return 0;
339 : }
340 :
341 265050 : 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 265050 : tevent_req_data(req, struct wb_child_request_state);
346 :
347 265050 : if (state->subreq == NULL) {
348 : /* nothing to cleanup */
349 132525 : return;
350 : }
351 :
352 132525 : 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 132525 : TALLOC_FREE(state->subreq);
376 132525 : TALLOC_FREE(state->queue_subreq);
377 :
378 132525 : tevent_fd_set_flags(state->child->monitor_fde, TEVENT_FD_READ);
379 :
380 132525 : 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 22795 : tevent_queue_start(state->child->domain->queue);
388 : }
389 :
390 132525 : if (req_state == TEVENT_REQ_DONE) {
391 : /* transmitted request and got response */
392 132525 : 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 22703 : static struct winbindd_child *choose_domain_child(struct winbindd_domain *domain)
432 : {
433 22703 : struct winbindd_child *shortest = &domain->children[0];
434 0 : struct winbindd_child *current;
435 0 : int i;
436 :
437 22714 : for (i=0; i<talloc_array_length(domain->children); i++) {
438 0 : size_t shortest_len, current_len;
439 :
440 22703 : current = &domain->children[i];
441 22703 : current_len = tevent_queue_length(current->queue);
442 :
443 22703 : if (current_len == 0) {
444 : /* idle child */
445 22692 : return current;
446 : }
447 :
448 11 : shortest_len = tevent_queue_length(shortest->queue);
449 :
450 11 : if (current_len < shortest_len) {
451 0 : shortest = current;
452 : }
453 : }
454 :
455 11 : return shortest;
456 : }
457 :
458 132667 : struct dcerpc_binding_handle *dom_child_handle(struct winbindd_domain *domain)
459 : {
460 132667 : 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 45384 : static void wb_domain_request_cleanup(struct tevent_req *req,
476 : enum tevent_req_state req_state)
477 : {
478 45384 : 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 45384 : TALLOC_FREE(state->pending_subreq);
489 45384 : TALLOC_FREE(state->queue_entry);
490 45384 : tevent_queue_start(state->domain->queue);
491 45384 : }
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 22692 : 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 22692 : req = tevent_req_create(mem_ctx, &state,
508 : struct wb_domain_request_state);
509 22692 : if (req == NULL) {
510 0 : return NULL;
511 : }
512 :
513 22692 : state->domain = domain;
514 22692 : state->ev = ev;
515 22692 : state->request = request;
516 :
517 22692 : tevent_req_set_cleanup_fn(req, wb_domain_request_cleanup);
518 :
519 22692 : state->queue_entry = tevent_queue_add_entry(
520 : domain->queue, state->ev, req,
521 0 : wb_domain_request_trigger, NULL);
522 22692 : if (tevent_req_nomem(state->queue_entry, req)) {
523 0 : return tevent_req_post(req, ev);
524 : }
525 :
526 22692 : return req;
527 : }
528 :
529 22703 : static void wb_domain_request_trigger(struct tevent_req *req,
530 : void *private_data)
531 : {
532 22703 : struct wb_domain_request_state *state = tevent_req_data(
533 : req, struct wb_domain_request_state);
534 22703 : struct winbindd_domain *domain = state->domain;
535 22703 : struct tevent_req *subreq = NULL;
536 0 : size_t shortest_queue_length;
537 :
538 22703 : state->child = choose_domain_child(domain);
539 22703 : shortest_queue_length = tevent_queue_length(state->child->queue);
540 22703 : 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 11 : state->child = NULL;
549 11 : tevent_queue_stop(state->domain->queue);
550 11 : tevent_queue_entry_untrigger(state->queue_entry);
551 11 : return;
552 : }
553 :
554 22692 : if (domain->initialized) {
555 22589 : subreq = wb_child_request_send(state, state->ev, state->child,
556 : state->request);
557 22589 : if (tevent_req_nomem(subreq, req)) {
558 0 : return;
559 : }
560 22589 : tevent_req_set_callback(subreq, wb_domain_request_done, req);
561 22589 : 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 22589 : TALLOC_FREE(state->queue_entry);
571 22589 : return;
572 : }
573 :
574 103 : state->init_req = talloc_zero(state, struct winbindd_request);
575 103 : if (tevent_req_nomem(state->init_req, req)) {
576 0 : return;
577 : }
578 :
579 103 : if (IS_DC || domain->primary || domain->internal) {
580 : /* The primary domain has to find the DC name itself */
581 95 : state->r.in.dcname = talloc_strdup(state, "");
582 95 : if (tevent_req_nomem(state->r.in.dcname, req)) {
583 0 : return;
584 : }
585 :
586 95 : subreq = dcerpc_wbint_InitConnection_r_send(state,
587 : state->ev,
588 95 : state->child->binding_handle,
589 : &state->r);
590 95 : if (tevent_req_nomem(subreq, req)) {
591 0 : return;
592 : }
593 95 : tevent_req_set_callback(subreq, wb_domain_request_initialized,
594 : req);
595 95 : state->pending_subreq = subreq;
596 95 : 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 8 : subreq = wb_dsgetdcname_send(state, state->ev,
608 8 : state->domain->name,
609 : NULL, /* domain_guid */
610 : NULL, /* site_name */
611 : DS_RETURN_DNS_NAME); /* flags */
612 8 : if (tevent_req_nomem(subreq, req)) {
613 0 : return;
614 : }
615 8 : tevent_req_set_callback(subreq, wb_domain_request_gotdc, req);
616 8 : state->pending_subreq = subreq;
617 8 : return;
618 : }
619 :
620 8 : static void wb_domain_request_gotdc(struct tevent_req *subreq)
621 : {
622 8 : struct tevent_req *req = tevent_req_callback_data(
623 : subreq, struct tevent_req);
624 8 : struct wb_domain_request_state *state = tevent_req_data(
625 : req, struct wb_domain_request_state);
626 8 : struct netr_DsRGetDCNameInfo *dcinfo = NULL;
627 0 : NTSTATUS status;
628 8 : const char *dcname = NULL;
629 :
630 8 : state->pending_subreq = NULL;
631 :
632 8 : status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
633 8 : TALLOC_FREE(subreq);
634 8 : if (tevent_req_nterror(req, status)) {
635 0 : return;
636 : }
637 8 : dcname = dcinfo->dc_unc;
638 24 : while (dcname != NULL && *dcname == '\\') {
639 16 : dcname++;
640 : }
641 :
642 8 : state->r.in.dcname = talloc_strdup(state, dcname);
643 8 : if (tevent_req_nomem(state->r.in.dcname, req)) {
644 0 : return;
645 : }
646 :
647 8 : TALLOC_FREE(dcinfo);
648 :
649 8 : subreq = dcerpc_wbint_InitConnection_r_send(state,
650 : state->ev,
651 8 : state->child->binding_handle,
652 : &state->r);
653 8 : if (tevent_req_nomem(subreq, req)) {
654 0 : return;
655 : }
656 8 : tevent_req_set_callback(subreq, wb_domain_request_initialized, req);
657 8 : state->pending_subreq = subreq;
658 : }
659 :
660 103 : static void wb_domain_request_initialized(struct tevent_req *subreq)
661 : {
662 103 : struct tevent_req *req = tevent_req_callback_data(
663 : subreq, struct tevent_req);
664 103 : struct wb_domain_request_state *state = tevent_req_data(
665 : req, struct wb_domain_request_state);
666 0 : NTSTATUS status;
667 :
668 103 : state->pending_subreq = NULL;
669 :
670 103 : status = dcerpc_wbint_InitConnection_r_recv(subreq, state);
671 103 : TALLOC_FREE(subreq);
672 103 : if (NT_STATUS_IS_ERR(status)) {
673 0 : tevent_req_error(req, map_errno_from_nt_status(status));
674 0 : return;
675 : }
676 :
677 103 : status = state->r.out.result;
678 103 : if (NT_STATUS_IS_ERR(status)) {
679 0 : tevent_req_error(req, map_errno_from_nt_status(status));
680 0 : return;
681 : }
682 :
683 103 : state->domain->sid = *state->r.out.sid;
684 :
685 103 : talloc_free(state->domain->name);
686 103 : state->domain->name = talloc_strdup(state->domain, *state->r.out.name);
687 103 : if (state->domain->name == NULL) {
688 0 : tevent_req_error(req, ENOMEM);
689 0 : return;
690 : }
691 :
692 103 : if (*state->r.out.alt_name != NULL &&
693 39 : strlen(*state->r.out.alt_name) > 0) {
694 36 : talloc_free(state->domain->alt_name);
695 :
696 72 : state->domain->alt_name = talloc_strdup(state->domain,
697 36 : *state->r.out.alt_name);
698 36 : if (state->domain->alt_name == NULL) {
699 0 : tevent_req_error(req, ENOMEM);
700 0 : return;
701 : }
702 : }
703 :
704 103 : state->domain->native_mode =
705 103 : (*state->r.out.flags & WB_DOMINFO_DOMAIN_NATIVE);
706 103 : state->domain->active_directory =
707 103 : (*state->r.out.flags & WB_DOMINFO_DOMAIN_AD);
708 103 : state->domain->initialized = true;
709 :
710 103 : subreq = wb_child_request_send(state, state->ev, state->child,
711 : state->request);
712 103 : if (tevent_req_nomem(subreq, req)) {
713 0 : return;
714 : }
715 103 : tevent_req_set_callback(subreq, wb_domain_request_done, req);
716 103 : 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 103 : TALLOC_FREE(state->queue_entry);
726 : }
727 :
728 22692 : static void wb_domain_request_done(struct tevent_req *subreq)
729 : {
730 22692 : struct tevent_req *req = tevent_req_callback_data(
731 : subreq, struct tevent_req);
732 22692 : struct wb_domain_request_state *state = tevent_req_data(
733 : req, struct wb_domain_request_state);
734 0 : int ret, err;
735 :
736 22692 : state->pending_subreq = NULL;
737 :
738 22692 : ret = wb_child_request_recv(subreq, talloc_tos(), &state->response,
739 : &err);
740 22692 : TALLOC_FREE(subreq);
741 22692 : if (ret == -1) {
742 0 : tevent_req_error(req, err);
743 0 : return;
744 : }
745 22692 : tevent_req_done(req);
746 : }
747 :
748 22692 : int wb_domain_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
749 : struct winbindd_response **presponse, int *err)
750 : {
751 22692 : struct wb_domain_request_state *state = tevent_req_data(
752 : req, struct wb_domain_request_state);
753 :
754 22692 : if (tevent_req_is_unix_error(req, err)) {
755 0 : return -1;
756 : }
757 22692 : *presponse = talloc_move(mem_ctx, &state->response);
758 22692 : 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 225 : 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 225 : loadparm_s3_global_substitution();
785 :
786 450 : if (logprefix && logname) {
787 225 : char *logbase = NULL;
788 :
789 225 : if (*lp_logfile(talloc_tos(), lp_sub)) {
790 225 : char *end = NULL;
791 :
792 225 : if (asprintf(&logbase, "%s", lp_logfile(talloc_tos(), lp_sub)) < 0) {
793 0 : smb_panic("Internal error: asprintf failed");
794 : }
795 :
796 225 : if ((end = strrchr_m(logbase, '/'))) {
797 225 : *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 225 : 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 225 : SAFE_FREE(logbase);
812 : } else {
813 0 : smb_panic("Internal error: logprefix == NULL && "
814 : "logname == NULL");
815 : }
816 :
817 225 : child->pid = 0;
818 225 : child->sock = -1;
819 225 : child->domain = domain;
820 225 : child->queue = tevent_queue_create(NULL, "winbind_child");
821 225 : SMB_ASSERT(child->queue != NULL);
822 :
823 225 : child->binding_handle = wbint_binding_handle(NULL, NULL, child);
824 225 : SMB_ASSERT(child->binding_handle != NULL);
825 225 : }
826 :
827 : struct winbind_child_died_state {
828 : pid_t pid;
829 : struct winbindd_child *child;
830 : };
831 :
832 69 : static bool winbind_child_died_fn(struct winbindd_child *child,
833 : void *private_data)
834 : {
835 69 : struct winbind_child_died_state *state = private_data;
836 :
837 69 : if (child->pid == state->pid) {
838 0 : state->child = child;
839 0 : return false;
840 : }
841 69 : return true;
842 : }
843 :
844 23 : void winbind_child_died(pid_t pid)
845 : {
846 23 : struct winbind_child_died_state state = { .pid = pid };
847 :
848 23 : forall_children(winbind_child_died_fn, &state);
849 :
850 23 : if (state.child == NULL) {
851 23 : DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
852 23 : 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 47 : void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
861 : {
862 47 : flush_negative_conn_cache_for_domain(domain->name);
863 47 : if (domain->alt_name != NULL) {
864 45 : flush_negative_conn_cache_for_domain(domain->alt_name);
865 : }
866 47 : }
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 266 : static bool winbind_msg_relay_fn(struct winbindd_child *child,
881 : void *private_data)
882 : {
883 266 : struct winbind_msg_relay_state *state = private_data;
884 :
885 266 : DBG_DEBUG("sending message to pid %u.\n",
886 : (unsigned int)child->pid);
887 :
888 266 : messaging_send(state->msg_ctx, pid_to_procid(child->pid),
889 266 : state->msg_type, state->data);
890 266 : 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 86 : 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 86 : struct winbind_msg_relay_state state = {
947 : .msg_ctx = msg,
948 : .msg_type = msg_type,
949 : .data = data,
950 : };
951 0 : bool ok;
952 :
953 86 : DBG_DEBUG("Got reload-config message\n");
954 :
955 : /* Flush various caches */
956 86 : winbindd_flush_caches();
957 :
958 86 : winbindd_reload_services_file((const char *)private_data);
959 :
960 : /* Set tevent_thread_call_depth_set_callback according to debug level */
961 86 : if (lp_winbind_debug_traceid() && debuglevel_get() > 1) {
962 0 : tevent_thread_call_depth_set_callback(winbind_call_flow, NULL);
963 : } else {
964 86 : tevent_thread_call_depth_set_callback(NULL, NULL);
965 : }
966 :
967 86 : ok = add_trusted_domains_dc();
968 86 : if (!ok) {
969 0 : DBG_ERR("add_trusted_domains_dc() failed\n");
970 : }
971 :
972 86 : forall_children(winbind_msg_relay_fn, &state);
973 86 : }
974 :
975 : /* Set our domains as offline and forward the offline message to our children. */
976 :
977 : struct winbind_msg_on_offline_state {
978 : struct messaging_context *msg_ctx;
979 : uint32_t msg_type;
980 : };
981 :
982 8 : static bool winbind_msg_on_offline_fn(struct winbindd_child *child,
983 : void *private_data)
984 : {
985 8 : struct winbind_msg_on_offline_state *state = private_data;
986 :
987 8 : if (child->domain->internal) {
988 4 : return true;
989 : }
990 :
991 : /*
992 : * Each winbindd child should only process requests for one
993 : * domain - make sure we only set it online / offline for that
994 : * domain.
995 : */
996 4 : DBG_DEBUG("sending message to pid %u for domain %s.\n",
997 : (unsigned int)child->pid, child->domain->name);
998 :
999 4 : messaging_send_buf(state->msg_ctx,
1000 : pid_to_procid(child->pid),
1001 : state->msg_type,
1002 4 : (const uint8_t *)child->domain->name,
1003 4 : strlen(child->domain->name)+1);
1004 :
1005 4 : return true;
1006 : }
1007 :
1008 4 : void winbind_msg_offline(struct messaging_context *msg_ctx,
1009 : void *private_data,
1010 : uint32_t msg_type,
1011 : struct server_id server_id,
1012 : DATA_BLOB *data)
1013 : {
1014 4 : struct winbind_msg_on_offline_state state = {
1015 : .msg_ctx = msg_ctx,
1016 : .msg_type = MSG_WINBIND_OFFLINE,
1017 : };
1018 0 : struct winbindd_domain *domain;
1019 :
1020 4 : DEBUG(10,("winbind_msg_offline: got offline message.\n"));
1021 :
1022 4 : if (!lp_winbind_offline_logon()) {
1023 0 : DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
1024 0 : return;
1025 : }
1026 :
1027 : /* Set our global state as offline. */
1028 4 : if (!set_global_winbindd_state_offline()) {
1029 0 : DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
1030 0 : return;
1031 : }
1032 :
1033 : /* Set all our domains as offline. */
1034 16 : for (domain = domain_list(); domain; domain = domain->next) {
1035 12 : if (domain->internal) {
1036 8 : continue;
1037 : }
1038 4 : DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
1039 4 : domain->online = false;
1040 : }
1041 :
1042 4 : forall_domain_children(winbind_msg_on_offline_fn, &state);
1043 : }
1044 :
1045 : /* Set our domains as online and forward the online message to our children. */
1046 :
1047 0 : void winbind_msg_online(struct messaging_context *msg_ctx,
1048 : void *private_data,
1049 : uint32_t msg_type,
1050 : struct server_id server_id,
1051 : DATA_BLOB *data)
1052 : {
1053 0 : struct winbind_msg_on_offline_state state = {
1054 : .msg_ctx = msg_ctx,
1055 : .msg_type = MSG_WINBIND_ONLINE,
1056 : };
1057 :
1058 0 : DEBUG(10,("winbind_msg_online: got online message.\n"));
1059 :
1060 0 : if (!lp_winbind_offline_logon()) {
1061 0 : DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
1062 0 : return;
1063 : }
1064 :
1065 : /* Set our global state as online. */
1066 0 : set_global_winbindd_state_online();
1067 :
1068 0 : smb_nscd_flush_user_cache();
1069 0 : smb_nscd_flush_group_cache();
1070 :
1071 : /* Tell all our child domains to go online online. */
1072 0 : forall_domain_children(winbind_msg_on_offline_fn, &state);
1073 : }
1074 :
1075 0 : static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
1076 : {
1077 0 : struct winbindd_domain *domain;
1078 0 : char *buf = NULL;
1079 :
1080 0 : if ((buf = talloc_asprintf(mem_ctx, "global:%s ",
1081 0 : get_global_winbindd_state_offline() ?
1082 : "Offline":"Online")) == NULL) {
1083 0 : return NULL;
1084 : }
1085 :
1086 0 : for (domain = domain_list(); domain; domain = domain->next) {
1087 0 : if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ",
1088 : domain->name,
1089 0 : domain->online ?
1090 : "Online":"Offline")) == NULL) {
1091 0 : return NULL;
1092 : }
1093 : }
1094 :
1095 0 : buf = talloc_asprintf_append_buffer(buf, "\n");
1096 :
1097 0 : DEBUG(5,("collect_onlinestatus: %s", buf));
1098 :
1099 0 : return buf;
1100 : }
1101 :
1102 0 : void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
1103 : void *private_data,
1104 : uint32_t msg_type,
1105 : struct server_id server_id,
1106 : DATA_BLOB *data)
1107 : {
1108 0 : TALLOC_CTX *mem_ctx;
1109 0 : const char *message;
1110 :
1111 0 : DEBUG(5,("winbind_msg_onlinestatus received.\n"));
1112 :
1113 0 : mem_ctx = talloc_init("winbind_msg_onlinestatus");
1114 0 : if (mem_ctx == NULL) {
1115 0 : return;
1116 : }
1117 :
1118 0 : message = collect_onlinestatus(mem_ctx);
1119 0 : if (message == NULL) {
1120 0 : talloc_destroy(mem_ctx);
1121 0 : return;
1122 : }
1123 :
1124 0 : messaging_send_buf(msg_ctx, server_id, MSG_WINBIND_ONLINESTATUS,
1125 0 : (const uint8_t *)message, strlen(message) + 1);
1126 :
1127 0 : talloc_destroy(mem_ctx);
1128 : }
1129 :
1130 0 : void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
1131 : void *private_data,
1132 : uint32_t msg_type,
1133 : struct server_id server_id,
1134 : DATA_BLOB *data)
1135 : {
1136 0 : TALLOC_CTX *mem_ctx;
1137 0 : const char *message = NULL;
1138 0 : const char *domain = NULL;
1139 0 : char *s = NULL;
1140 0 : NTSTATUS status;
1141 0 : struct winbindd_domain *dom = NULL;
1142 :
1143 0 : DEBUG(5,("winbind_msg_dump_domain_list received.\n"));
1144 :
1145 0 : mem_ctx = talloc_init("winbind_msg_dump_domain_list");
1146 0 : if (!mem_ctx) {
1147 0 : return;
1148 : }
1149 :
1150 0 : if (data->length > 0) {
1151 0 : domain = (const char *)data->data;
1152 : }
1153 :
1154 0 : if (domain) {
1155 :
1156 0 : DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n",
1157 : domain));
1158 :
1159 0 : message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain,
1160 : find_domain_from_name_noinit(domain));
1161 0 : if (!message) {
1162 0 : talloc_destroy(mem_ctx);
1163 0 : return;
1164 : }
1165 :
1166 0 : messaging_send_buf(msg_ctx, server_id,
1167 : MSG_WINBIND_DUMP_DOMAIN_LIST,
1168 0 : (const uint8_t *)message, strlen(message) + 1);
1169 :
1170 0 : talloc_destroy(mem_ctx);
1171 :
1172 0 : return;
1173 : }
1174 :
1175 0 : DEBUG(5,("winbind_msg_dump_domain_list all domains\n"));
1176 :
1177 0 : for (dom = domain_list(); dom; dom=dom->next) {
1178 0 : message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, dom);
1179 0 : if (!message) {
1180 0 : talloc_destroy(mem_ctx);
1181 0 : return;
1182 : }
1183 :
1184 0 : s = talloc_asprintf_append(s, "%s\n", message);
1185 0 : if (!s) {
1186 0 : talloc_destroy(mem_ctx);
1187 0 : return;
1188 : }
1189 : }
1190 :
1191 0 : status = messaging_send_buf(msg_ctx, server_id,
1192 : MSG_WINBIND_DUMP_DOMAIN_LIST,
1193 0 : (uint8_t *)s, strlen(s) + 1);
1194 0 : if (!NT_STATUS_IS_OK(status)) {
1195 0 : DEBUG(0,("failed to send message: %s\n",
1196 : nt_errstr(status)));
1197 : }
1198 :
1199 0 : talloc_destroy(mem_ctx);
1200 : }
1201 :
1202 0 : static void account_lockout_policy_handler(struct tevent_context *ctx,
1203 : struct tevent_timer *te,
1204 : struct timeval now,
1205 : void *private_data)
1206 : {
1207 0 : struct winbindd_child *child =
1208 : (struct winbindd_child *)private_data;
1209 0 : TALLOC_CTX *mem_ctx = NULL;
1210 0 : struct samr_DomInfo12 lockout_policy;
1211 0 : NTSTATUS result;
1212 :
1213 0 : DEBUG(10,("account_lockout_policy_handler called\n"));
1214 :
1215 0 : TALLOC_FREE(child->lockout_policy_event);
1216 :
1217 0 : if ( !winbindd_can_contact_domain( child->domain ) ) {
1218 0 : DEBUG(10,("account_lockout_policy_handler: Removing myself since I "
1219 : "do not have an incoming trust to domain %s\n",
1220 : child->domain->name));
1221 :
1222 0 : return;
1223 : }
1224 :
1225 0 : mem_ctx = talloc_init("account_lockout_policy_handler ctx");
1226 0 : if (!mem_ctx) {
1227 0 : result = NT_STATUS_NO_MEMORY;
1228 : } else {
1229 0 : result = wb_cache_lockout_policy(child->domain, mem_ctx,
1230 : &lockout_policy);
1231 : }
1232 0 : TALLOC_FREE(mem_ctx);
1233 :
1234 0 : if (!NT_STATUS_IS_OK(result)) {
1235 0 : DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
1236 : nt_errstr(result)));
1237 : }
1238 :
1239 0 : child->lockout_policy_event = tevent_add_timer(global_event_context(), NULL,
1240 : timeval_current_ofs(3600, 0),
1241 : account_lockout_policy_handler,
1242 : child);
1243 : }
1244 :
1245 0 : static time_t get_machine_password_timeout(void)
1246 : {
1247 : /* until we have gpo support use lp setting */
1248 0 : return lp_machine_password_timeout();
1249 : }
1250 :
1251 0 : static bool calculate_next_machine_pwd_change(const char *domain,
1252 : struct timeval *t)
1253 : {
1254 0 : time_t pass_last_set_time;
1255 0 : time_t timeout;
1256 0 : time_t next_change;
1257 0 : struct timeval tv;
1258 0 : char *pw;
1259 :
1260 0 : pw = secrets_fetch_machine_password(domain,
1261 : &pass_last_set_time,
1262 : NULL);
1263 :
1264 0 : if (pw == NULL) {
1265 0 : DEBUG(0,("cannot fetch own machine password ????\n"));
1266 0 : return false;
1267 : }
1268 :
1269 0 : SAFE_FREE(pw);
1270 :
1271 0 : timeout = get_machine_password_timeout();
1272 0 : if (timeout == 0) {
1273 0 : DEBUG(10,("machine password never expires\n"));
1274 0 : return false;
1275 : }
1276 :
1277 0 : tv.tv_sec = pass_last_set_time;
1278 0 : DEBUG(10, ("password last changed %s\n",
1279 : timeval_string(talloc_tos(), &tv, false)));
1280 0 : tv.tv_sec += timeout;
1281 0 : DEBUGADD(10, ("password valid until %s\n",
1282 : timeval_string(talloc_tos(), &tv, false)));
1283 :
1284 0 : if (time(NULL) < (pass_last_set_time + timeout)) {
1285 0 : next_change = pass_last_set_time + timeout;
1286 0 : DEBUG(10,("machine password still valid until: %s\n",
1287 : http_timestring(talloc_tos(), next_change)));
1288 0 : *t = tevent_timeval_set(next_change, 0);
1289 :
1290 0 : if (lp_clustering()) {
1291 0 : uint8_t randbuf;
1292 : /*
1293 : * When having a cluster, we have several
1294 : * winbinds racing for the password change. In
1295 : * the machine_password_change_handler()
1296 : * function we check if someone else was
1297 : * faster when the event triggers. We add a
1298 : * 255-second random delay here, so that we
1299 : * don't run to change the password at the
1300 : * exact same moment.
1301 : */
1302 0 : generate_random_buffer(&randbuf, sizeof(randbuf));
1303 0 : DEBUG(10, ("adding %d seconds randomness\n",
1304 : (int)randbuf));
1305 0 : t->tv_sec += randbuf;
1306 : }
1307 0 : return true;
1308 : }
1309 :
1310 0 : DEBUG(10,("machine password expired, needs immediate change\n"));
1311 :
1312 0 : *t = timeval_zero();
1313 :
1314 0 : return true;
1315 : }
1316 :
1317 0 : static void machine_password_change_handler(struct tevent_context *ctx,
1318 : struct tevent_timer *te,
1319 : struct timeval now,
1320 : void *private_data)
1321 : {
1322 0 : struct messaging_context *msg_ctx = global_messaging_context();
1323 0 : struct winbindd_child *child =
1324 : (struct winbindd_child *)private_data;
1325 0 : struct rpc_pipe_client *netlogon_pipe = NULL;
1326 0 : struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1327 0 : NTSTATUS result;
1328 0 : struct timeval next_change;
1329 :
1330 0 : DEBUG(10,("machine_password_change_handler called\n"));
1331 :
1332 0 : TALLOC_FREE(child->machine_password_change_event);
1333 :
1334 0 : if (!calculate_next_machine_pwd_change(child->domain->name,
1335 : &next_change)) {
1336 0 : DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
1337 0 : return;
1338 : }
1339 :
1340 0 : DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
1341 : timeval_string(talloc_tos(), &next_change, false)));
1342 :
1343 0 : if (!timeval_expired(&next_change)) {
1344 0 : DEBUG(10, ("Someone else has already changed the pw\n"));
1345 0 : goto done;
1346 : }
1347 :
1348 0 : if (!winbindd_can_contact_domain(child->domain)) {
1349 0 : DEBUG(10,("machine_password_change_handler: Removing myself since I "
1350 : "do not have an incoming trust to domain %s\n",
1351 : child->domain->name));
1352 0 : return;
1353 : }
1354 :
1355 0 : result = cm_connect_netlogon_secure(child->domain,
1356 : &netlogon_pipe,
1357 : &netlogon_creds_ctx);
1358 0 : if (!NT_STATUS_IS_OK(result)) {
1359 0 : DEBUG(10,("machine_password_change_handler: "
1360 : "failed to connect netlogon pipe: %s\n",
1361 : nt_errstr(result)));
1362 0 : return;
1363 : }
1364 :
1365 0 : result = trust_pw_change(netlogon_creds_ctx,
1366 : msg_ctx,
1367 0 : netlogon_pipe->binding_handle,
1368 0 : child->domain->name,
1369 0 : child->domain->dcname,
1370 : false); /* force */
1371 :
1372 0 : DEBUG(10, ("machine_password_change_handler: "
1373 : "trust_pw_change returned %s\n",
1374 : nt_errstr(result)));
1375 :
1376 0 : if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1377 0 : DEBUG(3,("machine_password_change_handler: password set returned "
1378 : "ACCESS_DENIED. Maybe the trust account "
1379 : "password was changed and we didn't know it. "
1380 : "Killing connections to domain %s\n",
1381 : child->domain->name));
1382 0 : invalidate_cm_connection(child->domain);
1383 : }
1384 :
1385 0 : if (!calculate_next_machine_pwd_change(child->domain->name,
1386 : &next_change)) {
1387 0 : DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
1388 0 : return;
1389 : }
1390 :
1391 0 : DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
1392 : timeval_string(talloc_tos(), &next_change, false)));
1393 :
1394 0 : if (!NT_STATUS_IS_OK(result)) {
1395 0 : struct timeval tmp;
1396 : /*
1397 : * In case of failure, give the DC a minute to recover
1398 : */
1399 0 : tmp = timeval_current_ofs(60, 0);
1400 0 : next_change = timeval_max(&next_change, &tmp);
1401 : }
1402 :
1403 0 : done:
1404 0 : child->machine_password_change_event = tevent_add_timer(global_event_context(), NULL,
1405 : next_change,
1406 : machine_password_change_handler,
1407 : child);
1408 : }
1409 :
1410 : /* Deal with a request to go offline. */
1411 :
1412 0 : static void child_msg_offline(struct messaging_context *msg,
1413 : void *private_data,
1414 : uint32_t msg_type,
1415 : struct server_id server_id,
1416 : DATA_BLOB *data)
1417 : {
1418 0 : struct winbindd_domain *domain;
1419 0 : struct winbindd_domain *primary_domain = NULL;
1420 0 : const char *domainname = (const char *)data->data;
1421 :
1422 0 : if (data->data == NULL || data->length == 0) {
1423 0 : return;
1424 : }
1425 :
1426 0 : DEBUG(5,("child_msg_offline received for domain %s.\n", domainname));
1427 :
1428 0 : if (!lp_winbind_offline_logon()) {
1429 0 : DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
1430 0 : return;
1431 : }
1432 :
1433 0 : primary_domain = find_our_domain();
1434 :
1435 : /* Mark the requested domain offline. */
1436 :
1437 0 : for (domain = domain_list(); domain; domain = domain->next) {
1438 0 : if (domain->internal) {
1439 0 : continue;
1440 : }
1441 0 : if (strequal(domain->name, domainname)) {
1442 0 : DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name));
1443 0 : set_domain_offline(domain);
1444 : /* we are in the trusted domain, set the primary domain
1445 : * offline too */
1446 0 : if (domain != primary_domain) {
1447 0 : set_domain_offline(primary_domain);
1448 : }
1449 : }
1450 : }
1451 : }
1452 :
1453 : /* Deal with a request to go online. */
1454 :
1455 0 : static void child_msg_online(struct messaging_context *msg,
1456 : void *private_data,
1457 : uint32_t msg_type,
1458 : struct server_id server_id,
1459 : DATA_BLOB *data)
1460 : {
1461 0 : struct winbindd_domain *domain;
1462 0 : struct winbindd_domain *primary_domain = NULL;
1463 0 : const char *domainname = (const char *)data->data;
1464 :
1465 0 : if (data->data == NULL || data->length == 0) {
1466 0 : return;
1467 : }
1468 :
1469 0 : DEBUG(5,("child_msg_online received for domain %s.\n", domainname));
1470 :
1471 0 : if (!lp_winbind_offline_logon()) {
1472 0 : DEBUG(10,("child_msg_online: rejecting online message.\n"));
1473 0 : return;
1474 : }
1475 :
1476 0 : primary_domain = find_our_domain();
1477 :
1478 : /* Set our global state as online. */
1479 0 : set_global_winbindd_state_online();
1480 :
1481 : /* Try and mark everything online - delete any negative cache entries
1482 : to force a reconnect now. */
1483 :
1484 0 : for (domain = domain_list(); domain; domain = domain->next) {
1485 0 : if (domain->internal) {
1486 0 : continue;
1487 : }
1488 0 : if (strequal(domain->name, domainname)) {
1489 0 : DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name));
1490 0 : winbindd_flush_negative_conn_cache(domain);
1491 0 : set_domain_online_request(domain);
1492 :
1493 : /* we can be in trusted domain, which will contact primary domain
1494 : * we have to bring primary domain online in trusted domain process
1495 : * see, winbindd_dual_pam_auth() --> winbindd_dual_pam_auth_samlogon()
1496 : * --> contact_domain = find_our_domain()
1497 : * */
1498 0 : if (domain != primary_domain) {
1499 0 : winbindd_flush_negative_conn_cache(primary_domain);
1500 0 : set_domain_online_request(primary_domain);
1501 : }
1502 : }
1503 : }
1504 : }
1505 :
1506 : struct winbindd_reinit_after_fork_state {
1507 : const struct winbindd_child *myself;
1508 : };
1509 :
1510 0 : static bool winbindd_reinit_after_fork_fn(struct winbindd_child *child,
1511 : void *private_data)
1512 : {
1513 0 : struct winbindd_reinit_after_fork_state *state = private_data;
1514 :
1515 0 : if (child == state->myself) {
1516 0 : return true;
1517 : }
1518 :
1519 : /* Destroy all possible events in child list. */
1520 0 : TALLOC_FREE(child->lockout_policy_event);
1521 0 : TALLOC_FREE(child->machine_password_change_event);
1522 :
1523 : /*
1524 : * Children should never be able to send each other messages,
1525 : * all messages must go through the parent.
1526 : */
1527 0 : child->pid = (pid_t)0;
1528 :
1529 : /*
1530 : * Close service sockets to all other children
1531 : */
1532 0 : if (child->sock != -1) {
1533 0 : close(child->sock);
1534 0 : child->sock = -1;
1535 : }
1536 :
1537 0 : return true;
1538 : }
1539 :
1540 0 : NTSTATUS winbindd_reinit_after_fork(const struct winbindd_child *myself,
1541 : const char *logfilename)
1542 : {
1543 0 : struct winbindd_reinit_after_fork_state state = { .myself = myself };
1544 0 : struct winbindd_domain *domain;
1545 0 : NTSTATUS status;
1546 :
1547 0 : status = reinit_after_fork(
1548 : global_messaging_context(),
1549 : global_event_context(),
1550 : true);
1551 0 : if (!NT_STATUS_IS_OK(status)) {
1552 0 : DEBUG(0,("reinit_after_fork() failed\n"));
1553 0 : return status;
1554 : }
1555 0 : initialize_password_db(true, global_event_context());
1556 :
1557 0 : close_conns_after_fork();
1558 :
1559 0 : if (logfilename != NULL) {
1560 0 : lp_set_logfile(logfilename);
1561 0 : reopen_logs();
1562 : }
1563 :
1564 0 : if (!winbindd_setup_sig_term_handler(false)) {
1565 0 : return NT_STATUS_NO_MEMORY;
1566 : }
1567 :
1568 0 : if (!winbindd_setup_sig_hup_handler(logfilename)) {
1569 0 : return NT_STATUS_NO_MEMORY;
1570 : }
1571 :
1572 : /* Stop zombies in children */
1573 0 : CatchChild();
1574 :
1575 : /* Don't handle the same messages as our parent. */
1576 0 : messaging_deregister(global_messaging_context(),
1577 : MSG_SMB_CONF_UPDATED, NULL);
1578 0 : messaging_deregister(global_messaging_context(),
1579 : MSG_SHUTDOWN, NULL);
1580 0 : messaging_deregister(global_messaging_context(),
1581 : MSG_WINBIND_OFFLINE, NULL);
1582 0 : messaging_deregister(global_messaging_context(),
1583 : MSG_WINBIND_ONLINE, NULL);
1584 0 : messaging_deregister(global_messaging_context(),
1585 : MSG_WINBIND_ONLINESTATUS, NULL);
1586 0 : messaging_deregister(global_messaging_context(),
1587 : MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1588 0 : messaging_deregister(global_messaging_context(),
1589 : MSG_DEBUG, NULL);
1590 :
1591 0 : messaging_deregister(global_messaging_context(),
1592 : MSG_WINBIND_DOMAIN_OFFLINE, NULL);
1593 0 : messaging_deregister(global_messaging_context(),
1594 : MSG_WINBIND_DOMAIN_ONLINE, NULL);
1595 :
1596 : /* We have destroyed all events in the winbindd_event_context
1597 : * in reinit_after_fork(), so clean out all possible pending
1598 : * event pointers. */
1599 :
1600 : /* Deal with check_online_events. */
1601 :
1602 0 : for (domain = domain_list(); domain; domain = domain->next) {
1603 0 : TALLOC_FREE(domain->check_online_event);
1604 : }
1605 :
1606 : /* Ensure we're not handling a credential cache event inherited
1607 : * from our parent. */
1608 :
1609 0 : ccache_remove_all_after_fork();
1610 :
1611 0 : forall_children(winbindd_reinit_after_fork_fn, &state);
1612 :
1613 0 : return NT_STATUS_OK;
1614 : }
1615 :
1616 : /*
1617 : * In a child there will be only one domain, reference that here.
1618 : */
1619 : static struct winbindd_domain *child_domain;
1620 :
1621 57 : struct winbindd_domain *wb_child_domain(void)
1622 : {
1623 57 : return child_domain;
1624 : }
1625 :
1626 : struct child_handler_state {
1627 : struct winbindd_child *child;
1628 : struct winbindd_cli_state cli;
1629 : };
1630 :
1631 0 : static void child_handler(struct tevent_context *ev, struct tevent_fd *fde,
1632 : uint16_t flags, void *private_data)
1633 : {
1634 0 : struct child_handler_state *state =
1635 : (struct child_handler_state *)private_data;
1636 0 : NTSTATUS status;
1637 0 : uint64_t parent_traceid;
1638 :
1639 : /* fetch a request from the main daemon */
1640 0 : status = child_read_request(state->cli.sock, state->cli.request);
1641 :
1642 0 : if (!NT_STATUS_IS_OK(status)) {
1643 : /* we lost contact with our parent */
1644 0 : _exit(0);
1645 : }
1646 :
1647 : /* read traceid from request */
1648 0 : parent_traceid = state->cli.request->traceid;
1649 0 : debug_traceid_set(parent_traceid);
1650 :
1651 0 : DEBUG(4,("child daemon request %d\n",
1652 : (int)state->cli.request->cmd));
1653 :
1654 0 : ZERO_STRUCTP(state->cli.response);
1655 0 : state->cli.request->null_term = '\0';
1656 0 : state->cli.mem_ctx = talloc_tos();
1657 0 : child_process_request(state->child, &state->cli);
1658 :
1659 0 : DEBUG(4, ("Finished processing child request %d\n",
1660 : (int)state->cli.request->cmd));
1661 :
1662 0 : SAFE_FREE(state->cli.request->extra_data.data);
1663 :
1664 0 : status = child_write_response(state->cli.sock, state->cli.response);
1665 0 : if (!NT_STATUS_IS_OK(status)) {
1666 0 : exit(1);
1667 : }
1668 0 : }
1669 :
1670 148 : static bool fork_domain_child(struct winbindd_child *child)
1671 : {
1672 0 : int fdpair[2];
1673 0 : struct child_handler_state state;
1674 0 : struct winbindd_request request;
1675 0 : struct winbindd_response response;
1676 148 : struct winbindd_domain *primary_domain = NULL;
1677 0 : NTSTATUS status;
1678 0 : ssize_t nwritten;
1679 0 : struct tevent_fd *fde;
1680 148 : struct tevent_req *req = NULL;
1681 :
1682 148 : if (child->domain) {
1683 103 : DEBUG(10, ("fork_domain_child called for domain '%s'\n",
1684 : child->domain->name));
1685 : } else {
1686 45 : DEBUG(10, ("fork_domain_child called without domain.\n"));
1687 : }
1688 :
1689 148 : if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) {
1690 0 : DEBUG(0, ("Could not open child pipe: %s\n",
1691 : strerror(errno)));
1692 0 : return False;
1693 : }
1694 :
1695 148 : ZERO_STRUCT(state);
1696 148 : state.child = child;
1697 148 : state.cli.pid = getpid();
1698 148 : state.cli.request = &request;
1699 148 : state.cli.response = &response;
1700 :
1701 148 : child->pid = fork();
1702 :
1703 148 : if (child->pid == -1) {
1704 0 : DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
1705 0 : close(fdpair[0]);
1706 0 : close(fdpair[1]);
1707 0 : return False;
1708 : }
1709 :
1710 148 : if (child->pid != 0) {
1711 : /* Parent */
1712 0 : ssize_t nread;
1713 0 : int rc;
1714 :
1715 148 : close(fdpair[0]);
1716 :
1717 148 : nread = sys_read(fdpair[1], &status, sizeof(status));
1718 148 : if (nread != sizeof(status)) {
1719 0 : DEBUG(1, ("fork_domain_child: Could not read child status: "
1720 : "nread=%d, error=%s\n", (int)nread,
1721 : strerror(errno)));
1722 0 : close(fdpair[1]);
1723 0 : return false;
1724 : }
1725 148 : if (!NT_STATUS_IS_OK(status)) {
1726 0 : DEBUG(1, ("fork_domain_child: Child status is %s\n",
1727 : nt_errstr(status)));
1728 0 : close(fdpair[1]);
1729 0 : return false;
1730 : }
1731 :
1732 148 : child->monitor_fde = tevent_add_fd(global_event_context(),
1733 : global_event_context(),
1734 : fdpair[1],
1735 : TEVENT_FD_READ,
1736 : child_socket_readable,
1737 : child);
1738 148 : if (child->monitor_fde == NULL) {
1739 0 : DBG_WARNING("tevent_add_fd failed\n");
1740 0 : close(fdpair[1]);
1741 0 : return false;
1742 : }
1743 :
1744 148 : rc = set_blocking(fdpair[1], false);
1745 148 : if (rc < 0) {
1746 0 : close(fdpair[1]);
1747 0 : return false;
1748 : }
1749 :
1750 148 : child->sock = fdpair[1];
1751 :
1752 148 : return true;
1753 : }
1754 :
1755 : /* Child */
1756 0 : child_domain = child->domain;
1757 :
1758 0 : DEBUG(10, ("Child process %d\n", (int)getpid()));
1759 :
1760 0 : state.cli.sock = fdpair[0];
1761 0 : close(fdpair[1]);
1762 :
1763 : /* Reset traceid and deactivate call_depth tracking */
1764 0 : if (lp_winbind_debug_traceid()) {
1765 0 : debug_traceid_set(1);
1766 0 : tevent_thread_call_depth_set_callback(NULL, NULL);
1767 : }
1768 :
1769 0 : status = winbindd_reinit_after_fork(child, child->logfilename);
1770 :
1771 : /* setup callbacks again, one of them is removed in reinit_after_fork */
1772 0 : if (lp_winbind_debug_traceid()) {
1773 0 : winbind_debug_traceid_setup(global_event_context());
1774 : }
1775 :
1776 0 : nwritten = sys_write(state.cli.sock, &status, sizeof(status));
1777 0 : if (nwritten != sizeof(status)) {
1778 0 : DEBUG(1, ("fork_domain_child: Could not write status: "
1779 : "nwritten=%d, error=%s\n", (int)nwritten,
1780 : strerror(errno)));
1781 0 : _exit(0);
1782 : }
1783 0 : if (!NT_STATUS_IS_OK(status)) {
1784 0 : DEBUG(1, ("winbindd_reinit_after_fork failed: %s\n",
1785 : nt_errstr(status)));
1786 0 : _exit(0);
1787 : }
1788 :
1789 0 : if (child_domain != NULL) {
1790 0 : process_set_title("wb[%s]", "domain child [%s]", child_domain->name);
1791 0 : } else if (is_idmap_child(child)) {
1792 0 : process_set_title("wb-idmap", "idmap child");
1793 : }
1794 :
1795 : /* Handle online/offline messages. */
1796 0 : messaging_register(global_messaging_context(), NULL,
1797 : MSG_WINBIND_OFFLINE, child_msg_offline);
1798 0 : messaging_register(global_messaging_context(), NULL,
1799 : MSG_WINBIND_ONLINE, child_msg_online);
1800 0 : messaging_register(global_messaging_context(), NULL,
1801 : MSG_DEBUG, debug_message);
1802 0 : messaging_register(global_messaging_context(), NULL,
1803 : MSG_WINBIND_IP_DROPPED,
1804 : winbind_msg_ip_dropped);
1805 0 : messaging_register(global_messaging_context(), NULL,
1806 : MSG_WINBIND_DISCONNECT_DC,
1807 : winbind_msg_disconnect_dc);
1808 :
1809 0 : req = messaging_filtered_read_send(global_event_context(),
1810 : global_event_context(),
1811 : global_messaging_context(),
1812 : winbindd_child_msg_filter,
1813 : child);
1814 0 : if (req == NULL) {
1815 0 : DBG_ERR("messaging_filtered_read_send failed\n");
1816 0 : _exit(1);
1817 : }
1818 :
1819 0 : primary_domain = find_our_domain();
1820 :
1821 0 : if (primary_domain == NULL) {
1822 0 : smb_panic("no primary domain found");
1823 : }
1824 :
1825 : /* It doesn't matter if we allow cache login,
1826 : * try to bring domain online after fork. */
1827 0 : if ( child->domain ) {
1828 0 : child->domain->startup = True;
1829 0 : child->domain->startup_time = time_mono(NULL);
1830 : /* we can be in primary domain or in trusted domain
1831 : * If we are in trusted domain, set the primary domain
1832 : * in start-up mode */
1833 0 : if (!(child->domain->internal)) {
1834 0 : set_domain_online_request(child->domain);
1835 0 : if (!(child->domain->primary)) {
1836 0 : primary_domain->startup = True;
1837 0 : primary_domain->startup_time = time_mono(NULL);
1838 0 : set_domain_online_request(primary_domain);
1839 : }
1840 : }
1841 : }
1842 :
1843 : /* We might be in the idmap child...*/
1844 0 : if (child->domain && !(child->domain->internal) &&
1845 0 : lp_winbind_offline_logon()) {
1846 :
1847 0 : set_domain_online_request(child->domain);
1848 :
1849 0 : if (primary_domain && (primary_domain != child->domain)) {
1850 : /* We need to talk to the primary
1851 : * domain as well as the trusted
1852 : * domain inside a trusted domain
1853 : * child.
1854 : * See the code in :
1855 : * set_dc_type_and_flags_trustinfo()
1856 : * for details.
1857 : */
1858 0 : set_domain_online_request(primary_domain);
1859 : }
1860 :
1861 0 : child->lockout_policy_event = tevent_add_timer(
1862 : global_event_context(), NULL, timeval_zero(),
1863 : account_lockout_policy_handler,
1864 : child);
1865 : }
1866 :
1867 0 : if (child->domain && child->domain->primary &&
1868 0 : !USE_KERBEROS_KEYTAB &&
1869 0 : lp_server_role() == ROLE_DOMAIN_MEMBER) {
1870 :
1871 0 : struct timeval next_change;
1872 :
1873 0 : if (calculate_next_machine_pwd_change(child->domain->name,
1874 : &next_change)) {
1875 0 : child->machine_password_change_event = tevent_add_timer(
1876 : global_event_context(), NULL, next_change,
1877 : machine_password_change_handler,
1878 : child);
1879 : }
1880 : }
1881 :
1882 0 : fde = tevent_add_fd(global_event_context(), NULL, state.cli.sock,
1883 : TEVENT_FD_READ, child_handler, &state);
1884 0 : if (fde == NULL) {
1885 0 : DEBUG(1, ("tevent_add_fd failed\n"));
1886 0 : _exit(1);
1887 : }
1888 :
1889 0 : while (1) {
1890 :
1891 0 : int ret;
1892 0 : TALLOC_CTX *frame = talloc_stackframe();
1893 :
1894 0 : ret = tevent_loop_once(global_event_context());
1895 0 : if (ret != 0) {
1896 0 : DEBUG(1, ("tevent_loop_once failed: %s\n",
1897 : strerror(errno)));
1898 0 : _exit(1);
1899 : }
1900 :
1901 0 : if (child->domain && child->domain->startup &&
1902 0 : (time_mono(NULL) > child->domain->startup_time + 30)) {
1903 : /* No longer in "startup" mode. */
1904 0 : DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
1905 : child->domain->name ));
1906 0 : child->domain->startup = False;
1907 : }
1908 :
1909 0 : TALLOC_FREE(frame);
1910 : }
1911 : }
1912 :
1913 0 : void winbind_msg_ip_dropped_parent(struct messaging_context *msg_ctx,
1914 : void *private_data,
1915 : uint32_t msg_type,
1916 : struct server_id server_id,
1917 : DATA_BLOB *data)
1918 : {
1919 0 : struct winbind_msg_relay_state state = {
1920 : .msg_ctx = msg_ctx,
1921 : .msg_type = msg_type,
1922 : .data = data,
1923 : };
1924 :
1925 0 : winbind_msg_ip_dropped(msg_ctx, private_data, msg_type,
1926 : server_id, data);
1927 :
1928 0 : forall_children(winbind_msg_relay_fn, &state);
1929 0 : }
1930 :
1931 45 : void winbindd_terminate(bool is_parent)
1932 : {
1933 45 : if (is_parent) {
1934 : /* When parent goes away we should
1935 : * remove the socket file. Not so
1936 : * when children terminate.
1937 : */
1938 45 : char *path = NULL;
1939 :
1940 45 : if (asprintf(&path, "%s/%s",
1941 : lp_winbindd_socket_directory(), WINBINDD_SOCKET_NAME) > 0) {
1942 45 : unlink(path);
1943 45 : SAFE_FREE(path);
1944 : }
1945 : }
1946 :
1947 45 : idmap_close();
1948 :
1949 45 : netlogon_creds_cli_close_global_db();
1950 :
1951 : #if 0
1952 : if (interactive) {
1953 : TALLOC_CTX *mem_ctx = talloc_init("end_description");
1954 : char *description = talloc_describe_all(mem_ctx);
1955 :
1956 : DEBUG(3, ("tallocs left:\n%s\n", description));
1957 : talloc_destroy(mem_ctx);
1958 : }
1959 : #endif
1960 :
1961 45 : if (is_parent) {
1962 45 : pidfile_unlink(lp_pid_directory(), "winbindd");
1963 : }
1964 :
1965 45 : exit(0);
1966 : }
1967 :
1968 0 : static void winbindd_sig_term_handler(struct tevent_context *ev,
1969 : struct tevent_signal *se,
1970 : int signum,
1971 : int count,
1972 : void *siginfo,
1973 : void *private_data)
1974 : {
1975 0 : bool *p = talloc_get_type_abort(private_data, bool);
1976 0 : bool is_parent = *p;
1977 :
1978 0 : TALLOC_FREE(p);
1979 :
1980 0 : DEBUG(0,("Got sig[%d] terminate (is_parent=%d)\n",
1981 : signum, is_parent));
1982 0 : winbindd_terminate(is_parent);
1983 0 : }
1984 :
1985 45 : bool winbindd_setup_sig_term_handler(bool parent)
1986 : {
1987 0 : struct tevent_signal *se;
1988 0 : bool *is_parent;
1989 :
1990 45 : is_parent = talloc(global_event_context(), bool);
1991 45 : if (!is_parent) {
1992 0 : return false;
1993 : }
1994 :
1995 45 : *is_parent = parent;
1996 :
1997 45 : se = tevent_add_signal(global_event_context(),
1998 : is_parent,
1999 : SIGTERM, 0,
2000 : winbindd_sig_term_handler,
2001 : is_parent);
2002 45 : if (!se) {
2003 0 : DEBUG(0,("failed to setup SIGTERM handler\n"));
2004 0 : talloc_free(is_parent);
2005 0 : return false;
2006 : }
2007 :
2008 45 : se = tevent_add_signal(global_event_context(),
2009 : is_parent,
2010 : SIGINT, 0,
2011 : winbindd_sig_term_handler,
2012 : is_parent);
2013 45 : if (!se) {
2014 0 : DEBUG(0,("failed to setup SIGINT handler\n"));
2015 0 : talloc_free(is_parent);
2016 0 : return false;
2017 : }
2018 :
2019 45 : se = tevent_add_signal(global_event_context(),
2020 : is_parent,
2021 : SIGQUIT, 0,
2022 : winbindd_sig_term_handler,
2023 : is_parent);
2024 45 : if (!se) {
2025 0 : DEBUG(0,("failed to setup SIGINT handler\n"));
2026 0 : talloc_free(is_parent);
2027 0 : return false;
2028 : }
2029 :
2030 45 : return true;
2031 : }
2032 :
2033 0 : static void flush_caches_noinit(void)
2034 : {
2035 : /*
2036 : * We need to invalidate cached user list entries on a SIGHUP
2037 : * otherwise cached access denied errors due to restrict anonymous
2038 : * hang around until the sequence number changes.
2039 : * NB
2040 : * Skip uninitialized domains when flush cache.
2041 : * If domain is not initialized, it means it is never
2042 : * used or never become online. look, wcache_invalidate_cache()
2043 : * -> get_cache() -> init_dc_connection(). It causes a lot of traffic
2044 : * for unused domains and large traffic for primary domain's DC if there
2045 : * are many domains..
2046 : */
2047 :
2048 0 : if (!wcache_invalidate_cache_noinit()) {
2049 0 : DEBUG(0, ("invalidating the cache failed; revalidate the cache\n"));
2050 0 : if (!winbindd_cache_validate_and_initialize()) {
2051 0 : exit(1);
2052 : }
2053 : }
2054 0 : }
2055 :
2056 0 : static void winbindd_sig_hup_handler(struct tevent_context *ev,
2057 : struct tevent_signal *se,
2058 : int signum,
2059 : int count,
2060 : void *siginfo,
2061 : void *private_data)
2062 : {
2063 0 : const char *file = (const char *)private_data;
2064 :
2065 0 : DEBUG(1,("Reloading services after SIGHUP\n"));
2066 0 : flush_caches_noinit();
2067 0 : winbindd_reload_services_file(file);
2068 0 : }
2069 :
2070 45 : bool winbindd_setup_sig_hup_handler(const char *lfile)
2071 : {
2072 0 : struct tevent_signal *se;
2073 45 : char *file = NULL;
2074 :
2075 45 : if (lfile) {
2076 0 : file = talloc_strdup(global_event_context(),
2077 : lfile);
2078 0 : if (!file) {
2079 0 : return false;
2080 : }
2081 : }
2082 :
2083 45 : se = tevent_add_signal(global_event_context(),
2084 : global_event_context(),
2085 : SIGHUP, 0,
2086 : winbindd_sig_hup_handler,
2087 : file);
2088 45 : if (!se) {
2089 0 : return false;
2090 : }
2091 :
2092 45 : return true;
2093 : }
|