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