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 "../../nsswitch/libwbclient/wbc_async.h" 33 34#undef DBGC_CLASS 35#define DBGC_CLASS DBGC_WINBIND 36 37extern bool override_logfile; 38extern struct winbindd_methods cache_methods; 39 40/* Read some data from a client connection */ 41 42static NTSTATUS child_read_request(struct winbindd_cli_state *state) 43{ 44 NTSTATUS status; 45 46 /* Read data */ 47 48 status = read_data(state->sock, (char *)state->request, 49 sizeof(*state->request)); 50 51 if (!NT_STATUS_IS_OK(status)) { 52 DEBUG(3, ("child_read_request: read_data failed: %s\n", 53 nt_errstr(status))); 54 return status; 55 } 56 57 if (state->request->extra_len == 0) { 58 state->request->extra_data.data = NULL; 59 return NT_STATUS_OK; 60 } 61 62 DEBUG(10, ("Need to read %d extra bytes\n", (int)state->request->extra_len)); 63 64 state->request->extra_data.data = 65 SMB_MALLOC_ARRAY(char, state->request->extra_len + 1); 66 67 if (state->request->extra_data.data == NULL) { 68 DEBUG(0, ("malloc failed\n")); 69 return NT_STATUS_NO_MEMORY; 70 } 71 72 /* Ensure null termination */ 73 state->request->extra_data.data[state->request->extra_len] = '\0'; 74 75 status= read_data(state->sock, state->request->extra_data.data, 76 state->request->extra_len); 77 78 if (!NT_STATUS_IS_OK(status)) { 79 DEBUG(0, ("Could not read extra data: %s\n", 80 nt_errstr(status))); 81 } 82 return status; 83} 84 85/* 86 * Do winbind child async request. This is not simply wb_simple_trans. We have 87 * to do the queueing ourselves because while a request is queued, the child 88 * might have crashed, and we have to re-fork it in the _trigger function. 89 */ 90 91struct wb_child_request_state { 92 struct tevent_context *ev; 93 struct winbindd_child *child; 94 struct winbindd_request *request; 95 struct winbindd_response *response; 96}; 97 98static bool fork_domain_child(struct winbindd_child *child); 99 100static void wb_child_request_trigger(struct tevent_req *req, 101 void *private_data); 102static void wb_child_request_done(struct tevent_req *subreq); 103 104struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx, 105 struct tevent_context *ev, 106 struct winbindd_child *child, 107 struct winbindd_request *request) 108{ 109 struct tevent_req *req; 110 struct wb_child_request_state *state; 111 112 req = tevent_req_create(mem_ctx, &state, 113 struct wb_child_request_state); 114 if (req == NULL) { 115 return NULL; 116 } 117 118 state->ev = ev; 119 state->child = child; 120 state->request = request; 121 122 if (!tevent_queue_add(child->queue, ev, req, 123 wb_child_request_trigger, NULL)) { 124 tevent_req_nomem(NULL, req); 125 return tevent_req_post(req, ev); 126 } 127 return req; 128} 129 130static void wb_child_request_trigger(struct tevent_req *req, 131 void *private_data) 132{ 133 struct wb_child_request_state *state = tevent_req_data( 134 req, struct wb_child_request_state); 135 struct tevent_req *subreq; 136 137 if ((state->child->pid == 0) && (!fork_domain_child(state->child))) { 138 tevent_req_error(req, errno); 139 return; 140 } 141 142 subreq = wb_simple_trans_send(state, winbind_event_context(), NULL, 143 state->child->sock, state->request); 144 if (tevent_req_nomem(subreq, req)) { 145 return; 146 } 147 tevent_req_set_callback(subreq, wb_child_request_done, req); 148 149 if (!tevent_req_set_endtime(req, state->ev, 150 timeval_current_ofs(300, 0))) { 151 tevent_req_nomem(NULL, req); 152 return; 153 } 154} 155 156static void wb_child_request_done(struct tevent_req *subreq) 157{ 158 struct tevent_req *req = tevent_req_callback_data( 159 subreq, struct tevent_req); 160 struct wb_child_request_state *state = tevent_req_data( 161 req, struct wb_child_request_state); 162 int ret, err; 163 164 ret = wb_simple_trans_recv(subreq, state, &state->response, &err); 165 TALLOC_FREE(subreq); 166 if (ret == -1) { 167 tevent_req_error(req, err); 168 return; 169 } 170 tevent_req_done(req); 171} 172 173int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, 174 struct winbindd_response **presponse, int *err) 175{ 176 struct wb_child_request_state *state = tevent_req_data( 177 req, struct wb_child_request_state); 178 179 if (tevent_req_is_unix_error(req, err)) { 180 return -1; 181 } 182 *presponse = talloc_move(mem_ctx, &state->response); 183 return 0; 184} 185 186struct wb_domain_request_state { 187 struct tevent_context *ev; 188 struct winbindd_domain *domain; 189 struct winbindd_request *request; 190 struct winbindd_request *init_req; 191 struct winbindd_response *response; 192}; 193 194static void wb_domain_request_gotdc(struct tevent_req *subreq); 195static void wb_domain_request_initialized(struct tevent_req *subreq); 196static void wb_domain_request_done(struct tevent_req *subreq); 197 198struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx, 199 struct tevent_context *ev, 200 struct winbindd_domain *domain, 201 struct winbindd_request *request) 202{ 203 struct tevent_req *req, *subreq; 204 struct wb_domain_request_state *state; 205 206 req = tevent_req_create(mem_ctx, &state, 207 struct wb_domain_request_state); 208 if (req == NULL) { 209 return NULL; 210 } 211 212 if (domain->initialized) { 213 subreq = wb_child_request_send(state, ev, &domain->child, 214 request); 215 if (tevent_req_nomem(subreq, req)) { 216 return tevent_req_post(req, ev); 217 } 218 tevent_req_set_callback(subreq, wb_domain_request_done, req); 219 return req; 220 } 221 222 state->domain = domain; 223 state->ev = ev; 224 state->request = request; 225 226 state->init_req = talloc_zero(state, struct winbindd_request); 227 if (tevent_req_nomem(state->init_req, req)) { 228 return tevent_req_post(req, ev); 229 } 230 231 if (IS_DC || domain->primary || domain->internal) { 232 /* The primary domain has to find the DC name itself */ 233 state->init_req->cmd = WINBINDD_INIT_CONNECTION; 234 fstrcpy(state->init_req->domain_name, domain->name); 235 state->init_req->data.init_conn.is_primary = 236 domain->primary ? true : false; 237 fstrcpy(state->init_req->data.init_conn.dcname, ""); 238 239 subreq = wb_child_request_send(state, ev, &domain->child, 240 state->init_req); 241 if (tevent_req_nomem(subreq, req)) { 242 return tevent_req_post(req, ev); 243 } 244 tevent_req_set_callback(subreq, wb_domain_request_initialized, 245 req); 246 return req; 247 } 248 249 /* 250 * Ask our DC for a DC name 251 */ 252 domain = find_our_domain(); 253 254 /* This is *not* the primary domain, let's ask our DC about a DC 255 * name */ 256 257 state->init_req->cmd = WINBINDD_GETDCNAME; 258 fstrcpy(state->init_req->domain_name, domain->name); 259 260 subreq = wb_child_request_send(state, ev, &domain->child, request); 261 if (tevent_req_nomem(subreq, req)) { 262 return tevent_req_post(req, ev); 263 } 264 tevent_req_set_callback(subreq, wb_domain_request_gotdc, req); 265 return req; 266} 267 268static void wb_domain_request_gotdc(struct tevent_req *subreq) 269{ 270 struct tevent_req *req = tevent_req_callback_data( 271 subreq, struct tevent_req); 272 struct wb_domain_request_state *state = tevent_req_data( 273 req, struct wb_domain_request_state); 274 struct winbindd_response *response; 275 int ret, err; 276 277 ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err); 278 TALLOC_FREE(subreq); 279 if (ret == -1) { 280 tevent_req_error(req, err); 281 return; 282 } 283 state->init_req->cmd = WINBINDD_INIT_CONNECTION; 284 fstrcpy(state->init_req->domain_name, state->domain->name); 285 state->init_req->data.init_conn.is_primary = False; 286 fstrcpy(state->init_req->data.init_conn.dcname, 287 response->data.dc_name); 288 289 TALLOC_FREE(response); 290 291 subreq = wb_child_request_send(state, state->ev, &state->domain->child, 292 state->init_req); 293 if (tevent_req_nomem(subreq, req)) { 294 return; 295 } 296 tevent_req_set_callback(subreq, wb_domain_request_initialized, req); 297} 298 299static void wb_domain_request_initialized(struct tevent_req *subreq) 300{ 301 struct tevent_req *req = tevent_req_callback_data( 302 subreq, struct tevent_req); 303 struct wb_domain_request_state *state = tevent_req_data( 304 req, struct wb_domain_request_state); 305 struct winbindd_response *response; 306 int ret, err; 307 308 ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err); 309 TALLOC_FREE(subreq); 310 if (ret == -1) { 311 tevent_req_error(req, err); 312 return; 313 } 314 315 if (!string_to_sid(&state->domain->sid, 316 response->data.domain_info.sid)) { 317 DEBUG(1,("init_child_recv: Could not convert sid %s " 318 "from string\n", response->data.domain_info.sid)); 319 tevent_req_error(req, EINVAL); 320 return; 321 } 322 fstrcpy(state->domain->name, response->data.domain_info.name); 323 fstrcpy(state->domain->alt_name, response->data.domain_info.alt_name); 324 state->domain->native_mode = response->data.domain_info.native_mode; 325 state->domain->active_directory = 326 response->data.domain_info.active_directory; 327 state->domain->initialized = true; 328 329 TALLOC_FREE(response); 330 331 subreq = wb_child_request_send(state, state->ev, &state->domain->child, 332 state->request); 333 if (tevent_req_nomem(subreq, req)) { 334 return; 335 } 336 tevent_req_set_callback(subreq, wb_domain_request_done, req); 337} 338 339static void wb_domain_request_done(struct tevent_req *subreq) 340{ 341 struct tevent_req *req = tevent_req_callback_data( 342 subreq, struct tevent_req); 343 struct wb_domain_request_state *state = tevent_req_data( 344 req, struct wb_domain_request_state); 345 int ret, err; 346 347 ret = wb_child_request_recv(subreq, talloc_tos(), &state->response, 348 &err); 349 TALLOC_FREE(subreq); 350 if (ret == -1) { 351 tevent_req_error(req, err); 352 return; 353 } 354 tevent_req_done(req); 355} 356 357int wb_domain_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, 358 struct winbindd_response **presponse, int *err) 359{ 360 struct wb_domain_request_state *state = tevent_req_data( 361 req, struct wb_domain_request_state); 362 363 if (tevent_req_is_unix_error(req, err)) { 364 return -1; 365 } 366 *presponse = talloc_move(mem_ctx, &state->response); 367 return 0; 368} 369 370struct domain_request_state { 371 struct winbindd_domain *domain; 372 struct winbindd_request *request; 373 struct winbindd_response *response; 374 void (*continuation)(void *private_data_data, bool success); 375 void *private_data_data; 376}; 377 378static void async_domain_request_done(struct tevent_req *req); 379 380void async_domain_request(TALLOC_CTX *mem_ctx, 381 struct winbindd_domain *domain, 382 struct winbindd_request *request, 383 struct winbindd_response *response, 384 void (*continuation)(void *private_data_data, bool success), 385 void *private_data_data) 386{ 387 struct tevent_req *subreq; 388 struct domain_request_state *state; 389 390 state = TALLOC_P(mem_ctx, struct domain_request_state); 391 if (state == NULL) { 392 DEBUG(0, ("talloc failed\n")); 393 continuation(private_data_data, False); 394 return; 395 } 396 397 state->domain = domain; 398 state->request = request; 399 state->response = response; 400 state->continuation = continuation; 401 state->private_data_data = private_data_data; 402 403 subreq = wb_domain_request_send(state, winbind_event_context(), 404 domain, request); 405 if (subreq == NULL) { 406 DEBUG(5, ("wb_domain_request_send failed\n")); 407 continuation(private_data_data, false); 408 return; 409 } 410 tevent_req_set_callback(subreq, async_domain_request_done, state); 411} 412 413static void async_domain_request_done(struct tevent_req *req) 414{ 415 struct domain_request_state *state = tevent_req_callback_data( 416 req, struct domain_request_state); 417 struct winbindd_response *response; 418 int ret, err; 419 420 ret = wb_domain_request_recv(req, state, &response, &err); 421 TALLOC_FREE(req); 422 if (ret == -1) { 423 DEBUG(5, ("wb_domain_request returned %s\n", strerror(err))); 424 state->continuation(state->private_data_data, false); 425 return; 426 } 427 *(state->response) = *response; 428 state->continuation(state->private_data_data, true); 429} 430 431static void recvfrom_child(void *private_data_data, bool success) 432{ 433 struct winbindd_cli_state *state = 434 talloc_get_type_abort(private_data_data, struct winbindd_cli_state); 435 enum winbindd_result result = state->response->result; 436 437 /* This is an optimization: The child has written directly to the 438 * response buffer. The request itself is still in pending state, 439 * state that in the result code. */ 440 441 state->response->result = WINBINDD_PENDING; 442 443 if ((!success) || (result != WINBINDD_OK)) { 444 request_error(state); 445 return; 446 } 447 448 request_ok(state); 449} 450 451void sendto_domain(struct winbindd_cli_state *state, 452 struct winbindd_domain *domain) 453{ 454 async_domain_request(state->mem_ctx, domain, 455 state->request, state->response, 456 recvfrom_child, state); 457} 458 459static void child_process_request(struct winbindd_child *child, 460 struct winbindd_cli_state *state) 461{ 462 struct winbindd_domain *domain = child->domain; 463 const struct winbindd_child_dispatch_table *table = child->table; 464 465 /* Free response data - we may be interrupted and receive another 466 command before being able to send this data off. */ 467 468 state->response->result = WINBINDD_ERROR; 469 state->response->length = sizeof(struct winbindd_response); 470 471 /* as all requests in the child are sync, we can use talloc_tos() */ 472 state->mem_ctx = talloc_tos(); 473 474 /* Process command */ 475 476 for (; table->name; table++) { 477 if (state->request->cmd == table->struct_cmd) { 478 DEBUG(10,("child_process_request: request fn %s\n", 479 table->name)); 480 state->response->result = table->struct_fn(domain, state); 481 return; 482 } 483 } 484 485 DEBUG(1 ,("child_process_request: unknown request fn number %d\n", 486 (int)state->request->cmd)); 487 state->response->result = WINBINDD_ERROR; 488} 489 490void setup_child(struct winbindd_domain *domain, struct winbindd_child *child, 491 const struct winbindd_child_dispatch_table *table, 492 const char *logprefix, 493 const char *logname) 494{ 495 if (logprefix && logname) { 496 if (asprintf(&child->logfilename, "%s/%s-%s", 497 get_dyn_LOGFILEBASE(), logprefix, logname) < 0) { 498 smb_panic("Internal error: asprintf failed"); 499 } 500 } else { 501 smb_panic("Internal error: logprefix == NULL && " 502 "logname == NULL"); 503 } 504 505 child->domain = domain; 506 child->table = table; 507 child->queue = tevent_queue_create(NULL, "winbind_child"); 508 SMB_ASSERT(child->queue != NULL); 509 child->rpccli = wbint_rpccli_create(NULL, domain, child); 510 SMB_ASSERT(child->rpccli != NULL); 511} 512 513struct winbindd_child *children = NULL; 514 515void winbind_child_died(pid_t pid) 516{ 517 struct winbindd_child *child; 518 519 for (child = children; child != NULL; child = child->next) { 520 if (child->pid == pid) { 521 break; 522 } 523 } 524 525 if (child == NULL) { 526 DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid)); 527 return; 528 } 529 530 /* This will be re-added in fork_domain_child() */ 531 532 DLIST_REMOVE(children, child); 533 534 close(child->sock); 535 child->sock = -1; 536 child->pid = 0; 537} 538 539/* Ensure any negative cache entries with the netbios or realm names are removed. */ 540 541void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain) 542{ 543 flush_negative_conn_cache_for_domain(domain->name); 544 if (*domain->alt_name) { 545 flush_negative_conn_cache_for_domain(domain->alt_name); 546 } 547} 548 549/* 550 * Parent winbindd process sets its own debug level first and then 551 * sends a message to all the winbindd children to adjust their debug 552 * level to that of parents. 553 */ 554 555void winbind_msg_debug(struct messaging_context *msg_ctx, 556 void *private_data, 557 uint32_t msg_type, 558 struct server_id server_id, 559 DATA_BLOB *data) 560{ 561 struct winbindd_child *child; 562 563 DEBUG(10,("winbind_msg_debug: got debug message.\n")); 564 565 debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data); 566 567 for (child = children; child != NULL; child = child->next) { 568 569 DEBUG(10,("winbind_msg_debug: sending message to pid %u.\n", 570 (unsigned int)child->pid)); 571 572 messaging_send_buf(msg_ctx, pid_to_procid(child->pid), 573 MSG_DEBUG, 574 data->data, 575 strlen((char *) data->data) + 1); 576 } 577} 578 579/* Set our domains as offline and forward the offline message to our children. */ 580 581void winbind_msg_offline(struct messaging_context *msg_ctx, 582 void *private_data, 583 uint32_t msg_type, 584 struct server_id server_id, 585 DATA_BLOB *data) 586{ 587 struct winbindd_child *child; 588 struct winbindd_domain *domain; 589 590 DEBUG(10,("winbind_msg_offline: got offline message.\n")); 591 592 if (!lp_winbind_offline_logon()) { 593 DEBUG(10,("winbind_msg_offline: rejecting offline message.\n")); 594 return; 595 } 596 597 /* Set our global state as offline. */ 598 if (!set_global_winbindd_state_offline()) { 599 DEBUG(10,("winbind_msg_offline: offline request failed.\n")); 600 return; 601 } 602 603 /* Set all our domains as offline. */ 604 for (domain = domain_list(); domain; domain = domain->next) { 605 if (domain->internal) { 606 continue; 607 } 608 DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name)); 609 set_domain_offline(domain); 610 } 611 612 for (child = children; child != NULL; child = child->next) { 613 /* Don't send message to internal childs. We've already 614 done so above. */ 615 if (!child->domain || winbindd_internal_child(child)) { 616 continue; 617 } 618 619 /* Or internal domains (this should not be possible....) */ 620 if (child->domain->internal) { 621 continue; 622 } 623 624 /* Each winbindd child should only process requests for one domain - make sure 625 we only set it online / offline for that domain. */ 626 627 DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n", 628 (unsigned int)child->pid, domain->name )); 629 630 messaging_send_buf(msg_ctx, pid_to_procid(child->pid), 631 MSG_WINBIND_OFFLINE, 632 (uint8 *)child->domain->name, 633 strlen(child->domain->name)+1); 634 } 635} 636 637/* Set our domains as online and forward the online message to our children. */ 638 639void winbind_msg_online(struct messaging_context *msg_ctx, 640 void *private_data, 641 uint32_t msg_type, 642 struct server_id server_id, 643 DATA_BLOB *data) 644{ 645 struct winbindd_child *child; 646 struct winbindd_domain *domain; 647 648 DEBUG(10,("winbind_msg_online: got online message.\n")); 649 650 if (!lp_winbind_offline_logon()) { 651 DEBUG(10,("winbind_msg_online: rejecting online message.\n")); 652 return; 653 } 654 655 /* Set our global state as online. */ 656 set_global_winbindd_state_online(); 657 658 smb_nscd_flush_user_cache(); 659 smb_nscd_flush_group_cache(); 660 661 /* Set all our domains as online. */ 662 for (domain = domain_list(); domain; domain = domain->next) { 663 if (domain->internal) { 664 continue; 665 } 666 DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain->name)); 667 668 winbindd_flush_negative_conn_cache(domain); 669 set_domain_online_request(domain); 670 671 /* Send an online message to the idmap child when our 672 primary domain comes back online */ 673 674 if ( domain->primary ) { 675 struct winbindd_child *idmap = idmap_child(); 676 677 if ( idmap->pid != 0 ) { 678 messaging_send_buf(msg_ctx, 679 pid_to_procid(idmap->pid), 680 MSG_WINBIND_ONLINE, 681 (uint8 *)domain->name, 682 strlen(domain->name)+1); 683 } 684 } 685 } 686 687 for (child = children; child != NULL; child = child->next) { 688 /* Don't send message to internal childs. */ 689 if (!child->domain || winbindd_internal_child(child)) { 690 continue; 691 } 692 693 /* Or internal domains (this should not be possible....) */ 694 if (child->domain->internal) { 695 continue; 696 } 697 698 /* Each winbindd child should only process requests for one domain - make sure 699 we only set it online / offline for that domain. */ 700 701 DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n", 702 (unsigned int)child->pid, child->domain->name )); 703 704 messaging_send_buf(msg_ctx, pid_to_procid(child->pid), 705 MSG_WINBIND_ONLINE, 706 (uint8 *)child->domain->name, 707 strlen(child->domain->name)+1); 708 } 709} 710 711static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx) 712{ 713 struct winbindd_domain *domain; 714 char *buf = NULL; 715 716 if ((buf = talloc_asprintf(mem_ctx, "global:%s ", 717 get_global_winbindd_state_offline() ? 718 "Offline":"Online")) == NULL) { 719 return NULL; 720 } 721 722 for (domain = domain_list(); domain; domain = domain->next) { 723 if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ", 724 domain->name, 725 domain->online ? 726 "Online":"Offline")) == NULL) { 727 return NULL; 728 } 729 } 730 731 buf = talloc_asprintf_append_buffer(buf, "\n"); 732 733 DEBUG(5,("collect_onlinestatus: %s", buf)); 734 735 return buf; 736} 737 738void winbind_msg_onlinestatus(struct messaging_context *msg_ctx, 739 void *private_data, 740 uint32_t msg_type, 741 struct server_id server_id, 742 DATA_BLOB *data) 743{ 744 TALLOC_CTX *mem_ctx; 745 const char *message; 746 struct server_id *sender; 747 748 DEBUG(5,("winbind_msg_onlinestatus received.\n")); 749 750 if (!data->data) { 751 return; 752 } 753 754 sender = (struct server_id *)data->data; 755 756 mem_ctx = talloc_init("winbind_msg_onlinestatus"); 757 if (mem_ctx == NULL) { 758 return; 759 } 760 761 message = collect_onlinestatus(mem_ctx); 762 if (message == NULL) { 763 talloc_destroy(mem_ctx); 764 return; 765 } 766 767 messaging_send_buf(msg_ctx, *sender, MSG_WINBIND_ONLINESTATUS, 768 (uint8 *)message, strlen(message) + 1); 769 770 talloc_destroy(mem_ctx); 771} 772 773void winbind_msg_dump_event_list(struct messaging_context *msg_ctx, 774 void *private_data, 775 uint32_t msg_type, 776 struct server_id server_id, 777 DATA_BLOB *data) 778{ 779 struct winbindd_child *child; 780 781 DEBUG(10,("winbind_msg_dump_event_list received\n")); 782 783 dump_event_list(winbind_event_context()); 784 785 for (child = children; child != NULL; child = child->next) { 786 787 DEBUG(10,("winbind_msg_dump_event_list: sending message to pid %u\n", 788 (unsigned int)child->pid)); 789 790 messaging_send_buf(msg_ctx, pid_to_procid(child->pid), 791 MSG_DUMP_EVENT_LIST, 792 NULL, 0); 793 } 794 795} 796 797void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx, 798 void *private_data, 799 uint32_t msg_type, 800 struct server_id server_id, 801 DATA_BLOB *data) 802{ 803 TALLOC_CTX *mem_ctx; 804 const char *message = NULL; 805 struct server_id *sender = NULL; 806 const char *domain = NULL; 807 char *s = NULL; 808 NTSTATUS status; 809 struct winbindd_domain *dom = NULL; 810 811 DEBUG(5,("winbind_msg_dump_domain_list received.\n")); 812 813 if (!data || !data->data) { 814 return; 815 } 816 817 if (data->length < sizeof(struct server_id)) { 818 return; 819 } 820 821 mem_ctx = talloc_init("winbind_msg_dump_domain_list"); 822 if (!mem_ctx) { 823 return; 824 } 825 826 sender = (struct server_id *)data->data; 827 if (data->length > sizeof(struct server_id)) { 828 domain = (const char *)data->data+sizeof(struct server_id); 829 } 830 831 if (domain) { 832 833 DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n", 834 domain)); 835 836 message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, 837 find_domain_from_name_noinit(domain)); 838 if (!message) { 839 talloc_destroy(mem_ctx); 840 return; 841 } 842 843 messaging_send_buf(msg_ctx, *sender, 844 MSG_WINBIND_DUMP_DOMAIN_LIST, 845 (uint8_t *)message, strlen(message) + 1); 846 847 talloc_destroy(mem_ctx); 848 849 return; 850 } 851 852 DEBUG(5,("winbind_msg_dump_domain_list all domains\n")); 853 854 for (dom = domain_list(); dom; dom=dom->next) { 855 message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, dom); 856 if (!message) { 857 talloc_destroy(mem_ctx); 858 return; 859 } 860 861 s = talloc_asprintf_append(s, "%s\n", message); 862 if (!s) { 863 talloc_destroy(mem_ctx); 864 return; 865 } 866 } 867 868 status = messaging_send_buf(msg_ctx, *sender, 869 MSG_WINBIND_DUMP_DOMAIN_LIST, 870 (uint8_t *)s, strlen(s) + 1); 871 if (!NT_STATUS_IS_OK(status)) { 872 DEBUG(0,("failed to send message: %s\n", 873 nt_errstr(status))); 874 } 875 876 talloc_destroy(mem_ctx); 877} 878 879static void account_lockout_policy_handler(struct event_context *ctx, 880 struct timed_event *te, 881 struct timeval now, 882 void *private_data) 883{ 884 struct winbindd_child *child = 885 (struct winbindd_child *)private_data; 886 TALLOC_CTX *mem_ctx = NULL; 887 struct winbindd_methods *methods; 888 struct samr_DomInfo12 lockout_policy; 889 NTSTATUS result; 890 891 DEBUG(10,("account_lockout_policy_handler called\n")); 892 893 TALLOC_FREE(child->lockout_policy_event); 894 895 if ( !winbindd_can_contact_domain( child->domain ) ) { 896 DEBUG(10,("account_lockout_policy_handler: Removing myself since I " 897 "do not have an incoming trust to domain %s\n", 898 child->domain->name)); 899 900 return; 901 } 902 903 methods = child->domain->methods; 904 905 mem_ctx = talloc_init("account_lockout_policy_handler ctx"); 906 if (!mem_ctx) { 907 result = NT_STATUS_NO_MEMORY; 908 } else { 909 result = methods->lockout_policy(child->domain, mem_ctx, &lockout_policy); 910 } 911 TALLOC_FREE(mem_ctx); 912 913 if (!NT_STATUS_IS_OK(result)) { 914 DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n", 915 nt_errstr(result))); 916 } 917 918 child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL, 919 timeval_current_ofs(3600, 0), 920 account_lockout_policy_handler, 921 child); 922} 923 924static time_t get_machine_password_timeout(void) 925{ 926 /* until we have gpo support use lp setting */ 927 return lp_machine_password_timeout(); 928} 929 930static bool calculate_next_machine_pwd_change(const char *domain, 931 struct timeval *t) 932{ 933 time_t pass_last_set_time; 934 time_t timeout; 935 time_t next_change; 936 struct timeval tv; 937 char *pw; 938 939 pw = secrets_fetch_machine_password(domain, 940 &pass_last_set_time, 941 NULL); 942 943 if (pw == NULL) { 944 DEBUG(0,("cannot fetch own machine password ????")); 945 return false; 946 } 947 948 SAFE_FREE(pw); 949 950 timeout = get_machine_password_timeout(); 951 if (timeout == 0) { 952 DEBUG(10,("machine password never expires\n")); 953 return false; 954 } 955 956 tv.tv_sec = pass_last_set_time; 957 DEBUG(10, ("password last changed %s\n", 958 timeval_string(talloc_tos(), &tv, false))); 959 tv.tv_sec += timeout; 960 DEBUGADD(10, ("password valid until %s\n", 961 timeval_string(talloc_tos(), &tv, false))); 962 963 if (time(NULL) < (pass_last_set_time + timeout)) { 964 next_change = pass_last_set_time + timeout; 965 DEBUG(10,("machine password still valid until: %s\n", 966 http_timestring(talloc_tos(), next_change))); 967 *t = timeval_set(next_change, 0); 968 969 if (lp_clustering()) { 970 uint8_t randbuf; 971 /* 972 * When having a cluster, we have several 973 * winbinds racing for the password change. In 974 * the machine_password_change_handler() 975 * function we check if someone else was 976 * faster when the event triggers. We add a 977 * 255-second random delay here, so that we 978 * don't run to change the password at the 979 * exact same moment. 980 */ 981 generate_random_buffer(&randbuf, sizeof(randbuf)); 982 DEBUG(10, ("adding %d seconds randomness\n", 983 (int)randbuf)); 984 t->tv_sec += randbuf; 985 } 986 return true; 987 } 988 989 DEBUG(10,("machine password expired, needs immediate change\n")); 990 991 *t = timeval_zero(); 992 993 return true; 994} 995 996static void machine_password_change_handler(struct event_context *ctx, 997 struct timed_event *te, 998 struct timeval now, 999 void *private_data) 1000{ 1001 struct winbindd_child *child = 1002 (struct winbindd_child *)private_data; 1003 struct rpc_pipe_client *netlogon_pipe = NULL; 1004 TALLOC_CTX *frame; 1005 NTSTATUS result; 1006 struct timeval next_change; 1007 1008 DEBUG(10,("machine_password_change_handler called\n")); 1009 1010 TALLOC_FREE(child->machine_password_change_event); 1011 1012 if (!calculate_next_machine_pwd_change(child->domain->name, 1013 &next_change)) { 1014 DEBUG(10, ("calculate_next_machine_pwd_change failed\n")); 1015 return; 1016 } 1017 1018 DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n", 1019 timeval_string(talloc_tos(), &next_change, false))); 1020 1021 if (!timeval_expired(&next_change)) { 1022 DEBUG(10, ("Someone else has already changed the pw\n")); 1023 goto done; 1024 } 1025 1026 if (!winbindd_can_contact_domain(child->domain)) { 1027 DEBUG(10,("machine_password_change_handler: Removing myself since I " 1028 "do not have an incoming trust to domain %s\n", 1029 child->domain->name)); 1030 return; 1031 } 1032 1033 result = cm_connect_netlogon(child->domain, &netlogon_pipe); 1034 if (!NT_STATUS_IS_OK(result)) { 1035 DEBUG(10,("machine_password_change_handler: " 1036 "failed to connect netlogon pipe: %s\n", 1037 nt_errstr(result))); 1038 return; 1039 } 1040 1041 frame = talloc_stackframe(); 1042 1043 result = trust_pw_find_change_and_store_it(netlogon_pipe, 1044 frame, 1045 child->domain->name); 1046 TALLOC_FREE(frame); 1047 1048 DEBUG(10, ("machine_password_change_handler: " 1049 "trust_pw_find_change_and_store_it returned %s\n", 1050 nt_errstr(result))); 1051 1052 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) { 1053 DEBUG(3,("machine_password_change_handler: password set returned " 1054 "ACCESS_DENIED. Maybe the trust account " 1055 "password was changed and we didn't know it. " 1056 "Killing connections to domain %s\n", 1057 child->domain->name)); 1058 TALLOC_FREE(child->domain->conn.netlogon_pipe); 1059 } 1060 1061 if (!calculate_next_machine_pwd_change(child->domain->name, 1062 &next_change)) { 1063 DEBUG(10, ("calculate_next_machine_pwd_change failed\n")); 1064 return; 1065 } 1066 1067 DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n", 1068 timeval_string(talloc_tos(), &next_change, false))); 1069 1070 if (!NT_STATUS_IS_OK(result)) { 1071 struct timeval tmp; 1072 /* 1073 * In case of failure, give the DC a minute to recover 1074 */ 1075 tmp = timeval_current_ofs(60, 0); 1076 next_change = timeval_max(&next_change, &tmp); 1077 } 1078 1079done: 1080 child->machine_password_change_event = event_add_timed(winbind_event_context(), NULL, 1081 next_change, 1082 machine_password_change_handler, 1083 child); 1084} 1085 1086/* Deal with a request to go offline. */ 1087 1088static void child_msg_offline(struct messaging_context *msg, 1089 void *private_data, 1090 uint32_t msg_type, 1091 struct server_id server_id, 1092 DATA_BLOB *data) 1093{ 1094 struct winbindd_domain *domain; 1095 struct winbindd_domain *primary_domain = NULL; 1096 const char *domainname = (const char *)data->data; 1097 1098 if (data->data == NULL || data->length == 0) { 1099 return; 1100 } 1101 1102 DEBUG(5,("child_msg_offline received for domain %s.\n", domainname)); 1103 1104 if (!lp_winbind_offline_logon()) { 1105 DEBUG(10,("child_msg_offline: rejecting offline message.\n")); 1106 return; 1107 } 1108 1109 primary_domain = find_our_domain(); 1110 1111 /* Mark the requested domain offline. */ 1112 1113 for (domain = domain_list(); domain; domain = domain->next) { 1114 if (domain->internal) { 1115 continue; 1116 } 1117 if (strequal(domain->name, domainname)) { 1118 DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name)); 1119 set_domain_offline(domain); 1120 /* we are in the trusted domain, set the primary domain 1121 * offline too */ 1122 if (domain != primary_domain) { 1123 set_domain_offline(primary_domain); 1124 } 1125 } 1126 } 1127} 1128 1129/* Deal with a request to go online. */ 1130 1131static void child_msg_online(struct messaging_context *msg, 1132 void *private_data, 1133 uint32_t msg_type, 1134 struct server_id server_id, 1135 DATA_BLOB *data) 1136{ 1137 struct winbindd_domain *domain; 1138 struct winbindd_domain *primary_domain = NULL; 1139 const char *domainname = (const char *)data->data; 1140 1141 if (data->data == NULL || data->length == 0) { 1142 return; 1143 } 1144 1145 DEBUG(5,("child_msg_online received for domain %s.\n", domainname)); 1146 1147 if (!lp_winbind_offline_logon()) { 1148 DEBUG(10,("child_msg_online: rejecting online message.\n")); 1149 return; 1150 } 1151 1152 primary_domain = find_our_domain(); 1153 1154 /* Set our global state as online. */ 1155 set_global_winbindd_state_online(); 1156 1157 /* Try and mark everything online - delete any negative cache entries 1158 to force a reconnect now. */ 1159 1160 for (domain = domain_list(); domain; domain = domain->next) { 1161 if (domain->internal) { 1162 continue; 1163 } 1164 if (strequal(domain->name, domainname)) { 1165 DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name)); 1166 winbindd_flush_negative_conn_cache(domain); 1167 set_domain_online_request(domain); 1168 1169 /* we can be in trusted domain, which will contact primary domain 1170 * we have to bring primary domain online in trusted domain process 1171 * see, winbindd_dual_pam_auth() --> winbindd_dual_pam_auth_samlogon() 1172 * --> contact_domain = find_our_domain() 1173 * */ 1174 if (domain != primary_domain) { 1175 winbindd_flush_negative_conn_cache(primary_domain); 1176 set_domain_online_request(primary_domain); 1177 } 1178 } 1179 } 1180} 1181 1182static void child_msg_dump_event_list(struct messaging_context *msg, 1183 void *private_data, 1184 uint32_t msg_type, 1185 struct server_id server_id, 1186 DATA_BLOB *data) 1187{ 1188 DEBUG(5,("child_msg_dump_event_list received\n")); 1189 1190 dump_event_list(winbind_event_context()); 1191} 1192 1193bool winbindd_reinit_after_fork(const char *logfilename) 1194{ 1195 struct winbindd_domain *domain; 1196 struct winbindd_child *cl; 1197 1198 if (!NT_STATUS_IS_OK(reinit_after_fork(winbind_messaging_context(), 1199 winbind_event_context(), 1200 true))) { 1201 DEBUG(0,("reinit_after_fork() failed\n")); 1202 return false; 1203 } 1204 1205 close_conns_after_fork(); 1206 1207 if (!override_logfile && logfilename) { 1208 lp_set_logfile(logfilename); 1209 reopen_logs(); 1210 } 1211 1212 if (!winbindd_setup_sig_term_handler(false)) 1213 return false; 1214 if (!winbindd_setup_sig_hup_handler(override_logfile ? NULL : 1215 logfilename)) 1216 return false; 1217 1218 /* Stop zombies in children */ 1219 CatchChild(); 1220 1221 /* Don't handle the same messages as our parent. */ 1222 messaging_deregister(winbind_messaging_context(), 1223 MSG_SMB_CONF_UPDATED, NULL); 1224 messaging_deregister(winbind_messaging_context(), 1225 MSG_SHUTDOWN, NULL); 1226 messaging_deregister(winbind_messaging_context(), 1227 MSG_WINBIND_OFFLINE, NULL); 1228 messaging_deregister(winbind_messaging_context(), 1229 MSG_WINBIND_ONLINE, NULL); 1230 messaging_deregister(winbind_messaging_context(), 1231 MSG_WINBIND_ONLINESTATUS, NULL); 1232 messaging_deregister(winbind_messaging_context(), 1233 MSG_DUMP_EVENT_LIST, NULL); 1234 messaging_deregister(winbind_messaging_context(), 1235 MSG_WINBIND_DUMP_DOMAIN_LIST, NULL); 1236 messaging_deregister(winbind_messaging_context(), 1237 MSG_DEBUG, NULL); 1238 1239 /* We have destroyed all events in the winbindd_event_context 1240 * in reinit_after_fork(), so clean out all possible pending 1241 * event pointers. */ 1242 1243 /* Deal with check_online_events. */ 1244 1245 for (domain = domain_list(); domain; domain = domain->next) { 1246 TALLOC_FREE(domain->check_online_event); 1247 } 1248 1249 /* Ensure we're not handling a credential cache event inherited 1250 * from our parent. */ 1251 1252 ccache_remove_all_after_fork(); 1253 1254 /* Destroy all possible events in child list. */ 1255 for (cl = children; cl != NULL; cl = cl->next) { 1256 TALLOC_FREE(cl->lockout_policy_event); 1257 TALLOC_FREE(cl->machine_password_change_event); 1258 1259 /* Children should never be able to send 1260 * each other messages, all messages must 1261 * go through the parent. 1262 */ 1263 cl->pid = (pid_t)0; 1264 } 1265 /* 1266 * This is a little tricky, children must not 1267 * send an MSG_WINBIND_ONLINE message to idmap_child(). 1268 * If we are in a child of our primary domain or 1269 * in the process created by fork_child_dc_connect(), 1270 * and the primary domain cannot go online, 1271 * fork_child_dc_connection() sends MSG_WINBIND_ONLINE 1272 * periodically to idmap_child(). 1273 * 1274 * The sequence is, fork_child_dc_connect() ---> getdcs() ---> 1275 * get_dc_name_via_netlogon() ---> cm_connect_netlogon() 1276 * ---> init_dc_connection() ---> cm_open_connection ---> 1277 * set_domain_online(), sends MSG_WINBIND_ONLINE to 1278 * idmap_child(). Disallow children sending messages 1279 * to each other, all messages must go through the parent. 1280 */ 1281 cl = idmap_child(); 1282 cl->pid = (pid_t)0; 1283 1284 return true; 1285} 1286 1287/* 1288 * In a child there will be only one domain, reference that here. 1289 */ 1290static struct winbindd_domain *child_domain; 1291 1292struct winbindd_domain *wb_child_domain(void) 1293{ 1294 return child_domain; 1295} 1296 1297static bool fork_domain_child(struct winbindd_child *child) 1298{ 1299 int fdpair[2]; 1300 struct winbindd_cli_state state; 1301 struct winbindd_request request; 1302 struct winbindd_response response; 1303 struct winbindd_domain *primary_domain = NULL; 1304 1305 if (child->domain) { 1306 DEBUG(10, ("fork_domain_child called for domain '%s'\n", 1307 child->domain->name)); 1308 } else { 1309 DEBUG(10, ("fork_domain_child called without domain.\n")); 1310 } 1311 child_domain = child->domain; 1312 1313 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) { 1314 DEBUG(0, ("Could not open child pipe: %s\n", 1315 strerror(errno))); 1316 return False; 1317 } 1318 1319 ZERO_STRUCT(state); 1320 state.pid = sys_getpid(); 1321 state.request = &request; 1322 state.response = &response; 1323 1324 child->pid = sys_fork(); 1325 1326 if (child->pid == -1) { 1327 DEBUG(0, ("Could not fork: %s\n", strerror(errno))); 1328 return False; 1329 } 1330 1331 if (child->pid != 0) { 1332 /* Parent */ 1333 close(fdpair[0]); 1334 child->next = child->prev = NULL; 1335 DLIST_ADD(children, child); 1336 child->sock = fdpair[1]; 1337 return True; 1338 } 1339 1340 /* Child */ 1341 1342 DEBUG(10, ("Child process %d\n", (int)sys_getpid())); 1343 1344 state.sock = fdpair[0]; 1345 close(fdpair[1]); 1346 1347 if (!winbindd_reinit_after_fork(child->logfilename)) { 1348 _exit(0); 1349 } 1350 1351 /* Handle online/offline messages. */ 1352 messaging_register(winbind_messaging_context(), NULL, 1353 MSG_WINBIND_OFFLINE, child_msg_offline); 1354 messaging_register(winbind_messaging_context(), NULL, 1355 MSG_WINBIND_ONLINE, child_msg_online); 1356 messaging_register(winbind_messaging_context(), NULL, 1357 MSG_DUMP_EVENT_LIST, child_msg_dump_event_list); 1358 messaging_register(winbind_messaging_context(), NULL, 1359 MSG_DEBUG, debug_message); 1360 1361 primary_domain = find_our_domain(); 1362 1363 if (primary_domain == NULL) { 1364 smb_panic("no primary domain found"); 1365 } 1366 1367 /* It doesn't matter if we allow cache login, 1368 * try to bring domain online after fork. */ 1369 if ( child->domain ) { 1370 child->domain->startup = True; 1371 child->domain->startup_time = time(NULL); 1372 /* we can be in primary domain or in trusted domain 1373 * If we are in trusted domain, set the primary domain 1374 * in start-up mode */ 1375 if (!(child->domain->internal)) { 1376 set_domain_online_request(child->domain); 1377 if (!(child->domain->primary)) { 1378 primary_domain->startup = True; 1379 primary_domain->startup_time = time(NULL); 1380 set_domain_online_request(primary_domain); 1381 } 1382 } 1383 } 1384 1385 /* 1386 * We are in idmap child, make sure that we set the 1387 * check_online_event to bring primary domain online. 1388 */ 1389 if (child == idmap_child()) { 1390 set_domain_online_request(primary_domain); 1391 } 1392 1393 /* We might be in the idmap child...*/ 1394 if (child->domain && !(child->domain->internal) && 1395 lp_winbind_offline_logon()) { 1396 1397 set_domain_online_request(child->domain); 1398 1399 if (primary_domain && (primary_domain != child->domain)) { 1400 /* We need to talk to the primary 1401 * domain as well as the trusted 1402 * domain inside a trusted domain 1403 * child. 1404 * See the code in : 1405 * set_dc_type_and_flags_trustinfo() 1406 * for details. 1407 */ 1408 set_domain_online_request(primary_domain); 1409 } 1410 1411 child->lockout_policy_event = event_add_timed( 1412 winbind_event_context(), NULL, timeval_zero(), 1413 account_lockout_policy_handler, 1414 child); 1415 } 1416 1417 if (child->domain && child->domain->primary && 1418 !USE_KERBEROS_KEYTAB && 1419 lp_server_role() == ROLE_DOMAIN_MEMBER) { 1420 1421 struct timeval next_change; 1422 1423 if (calculate_next_machine_pwd_change(child->domain->name, 1424 &next_change)) { 1425 child->machine_password_change_event = event_add_timed( 1426 winbind_event_context(), NULL, next_change, 1427 machine_password_change_handler, 1428 child); 1429 } 1430 } 1431 1432 while (1) { 1433 1434 int ret; 1435 fd_set r_fds; 1436 fd_set w_fds; 1437 int maxfd; 1438 struct timeval t; 1439 struct timeval *tp; 1440 struct timeval now; 1441 TALLOC_CTX *frame = talloc_stackframe(); 1442 struct iovec iov[2]; 1443 int iov_count; 1444 NTSTATUS status; 1445 1446 if (run_events(winbind_event_context(), 0, NULL, NULL)) { 1447 TALLOC_FREE(frame); 1448 continue; 1449 } 1450 1451 GetTimeOfDay(&now); 1452 1453 if (child->domain && child->domain->startup && 1454 (now.tv_sec > child->domain->startup_time + 30)) { 1455 /* No longer in "startup" mode. */ 1456 DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n", 1457 child->domain->name )); 1458 child->domain->startup = False; 1459 } 1460 1461 FD_ZERO(&r_fds); 1462 FD_ZERO(&w_fds); 1463 1464 if (state.sock < 0 || state.sock >= FD_SETSIZE) { 1465 TALLOC_FREE(frame); 1466 perror("EBADF"); 1467 _exit(1); 1468 } 1469 1470 FD_SET(state.sock, &r_fds); 1471 maxfd = state.sock; 1472 1473 /* 1474 * Initialize this high as event_add_to_select_args() 1475 * uses a timeval_min() on this and next_event. Fix 1476 * from Roel van Meer <rolek@alt001.com>. 1477 */ 1478 t.tv_sec = 999999; 1479 t.tv_usec = 0; 1480 1481 event_add_to_select_args(winbind_event_context(), &now, 1482 &r_fds, &w_fds, &t, &maxfd); 1483 tp = get_timed_events_timeout(winbind_event_context(), &t); 1484 if (tp) { 1485 DEBUG(11,("select will use timeout of %u.%u seconds\n", 1486 (unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec )); 1487 } 1488 1489 ret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, tp); 1490 1491 if (run_events(winbind_event_context(), ret, &r_fds, &w_fds)) { 1492 /* We got a signal - continue. */ 1493 TALLOC_FREE(frame); 1494 continue; 1495 } 1496 1497 if (ret == 0) { 1498 DEBUG(11,("nothing is ready yet, continue\n")); 1499 TALLOC_FREE(frame); 1500 continue; 1501 } 1502 1503 if (ret == -1 && errno == EINTR) { 1504 /* We got a signal - continue. */ 1505 TALLOC_FREE(frame); 1506 continue; 1507 } 1508 1509 if (ret == -1 && errno != EINTR) { 1510 DEBUG(0,("select error occured\n")); 1511 TALLOC_FREE(frame); 1512 perror("select"); 1513 _exit(1); 1514 } 1515 1516 /* fetch a request from the main daemon */ 1517 status = child_read_request(&state); 1518 1519 if (!NT_STATUS_IS_OK(status)) { 1520 /* we lost contact with our parent */ 1521 _exit(0); 1522 } 1523 1524 DEBUG(4,("child daemon request %d\n", (int)state.request->cmd)); 1525 1526 ZERO_STRUCTP(state.response); 1527 state.request->null_term = '\0'; 1528 state.mem_ctx = frame; 1529 child_process_request(child, &state); 1530 1531 DEBUG(4, ("Finished processing child request %d\n", 1532 (int)state.request->cmd)); 1533 1534 SAFE_FREE(state.request->extra_data.data); 1535 1536 iov[0].iov_base = (void *)state.response; 1537 iov[0].iov_len = sizeof(struct winbindd_response); 1538 iov_count = 1; 1539 1540 if (state.response->length > sizeof(struct winbindd_response)) { 1541 iov[1].iov_base = 1542 (void *)state.response->extra_data.data; 1543 iov[1].iov_len = state.response->length-iov[0].iov_len; 1544 iov_count = 2; 1545 } 1546 1547 DEBUG(10, ("Writing %d bytes to parent\n", 1548 (int)state.response->length)); 1549 1550 if (write_data_iov(state.sock, iov, iov_count) != 1551 state.response->length) { 1552 DEBUG(0, ("Could not write result\n")); 1553 exit(1); 1554 } 1555 TALLOC_FREE(frame); 1556 } 1557} 1558