root/source3/winbindd/winbindd_dual.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. child_read_request
  2. async_request
  3. async_main_request_sent
  4. async_request_timeout_handler
  5. async_request_fail
  6. async_request_sent
  7. async_reply_recv
  8. schedule_async_request
  9. async_domain_request
  10. domain_init_recv
  11. recvfrom_child
  12. sendto_child
  13. sendto_domain
  14. child_process_request
  15. setup_child
  16. winbind_child_died
  17. winbindd_flush_negative_conn_cache
  18. winbind_msg_debug
  19. winbind_msg_offline
  20. winbind_msg_online
  21. winbind_msg_onlinestatus
  22. winbind_msg_dump_event_list
  23. winbind_msg_dump_domain_list
  24. account_lockout_policy_handler
  25. get_machine_password_timeout
  26. calculate_next_machine_pwd_change
  27. machine_password_change_handler
  28. child_msg_offline
  29. child_msg_online
  30. collect_onlinestatus
  31. child_msg_onlinestatus
  32. child_msg_dump_event_list
  33. winbindd_reinit_after_fork
  34. fork_domain_child

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

/* [<][>][^][v][top][bottom][index][help] */