s3compat-only s3:winbindd Split event handlers from winbindd.c
[abartlet/samba.git/.git] / source3 / winbindd / winbindd_event_handlers.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon for ntdom nss module
5
6    Copyright (C) by Tim Potter 2000-2002
7    Copyright (C) Andrew Tridgell 2002
8    Copyright (C) Jelmer Vernooij 2003
9    Copyright (C) Volker Lendecke 2004
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "winbindd.h"
27 #include "../../nsswitch/libwbclient/wbc_async.h"
28 #include "librpc/gen_ndr/messaging.h"
29 #include "idmap.h"
30
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_WINBIND
33
34 /* Main function */
35
36 /* Reload configuration */
37
38 bool winbindd_reload_services_file(const char *lfile)
39 {
40         bool ret;
41
42         if (lp_loaded()) {
43                 const char *fname = lp_configfile();
44
45                 if (file_exist(fname) && !strcsequal(fname,get_dyn_CONFIGFILE())) {
46                         set_dyn_CONFIGFILE(fname);
47                 }
48         }
49
50         /* if this is a child, restore the logfile to the special
51            name - <domain>, idmap, etc. */
52         if (lfile && *lfile) {
53                 lp_set_logfile(lfile);
54         }
55
56         reopen_logs();
57         ret = lp_load(get_dyn_CONFIGFILE(),False,False,True,True);
58
59         reopen_logs();
60         load_interfaces();
61
62         return(ret);
63 }
64
65 static void winbindd_status(void)
66 {
67         struct winbindd_cli_state *tmp;
68
69         DEBUG(0, ("winbindd status:\n"));
70
71         /* Print client state information */
72
73         DEBUG(0, ("\t%d clients currently active\n", winbindd_num_clients()));
74
75         if (DEBUGLEVEL >= 2 && winbindd_num_clients()) {
76                 DEBUG(2, ("\tclient list:\n"));
77                 for(tmp = winbindd_client_list(); tmp; tmp = tmp->next) {
78                         DEBUGADD(2, ("\t\tpid %lu, sock %d (%s)\n",
79                                      (unsigned long)tmp->pid, tmp->sock,
80                                      client_is_idle(tmp) ? "idle" : "active"));
81                 }
82         }
83 }
84
85 /* Flush client cache */
86
87 static void flush_caches(void)
88 {
89         /* We need to invalidate cached user list entries on a SIGHUP 
90            otherwise cached access denied errors due to restrict anonymous
91            hang around until the sequence number changes. */
92
93         if (!wcache_invalidate_cache()) {
94                 DEBUG(0, ("invalidating the cache failed; revalidate the cache\n"));
95                 if (!winbindd_cache_validate_and_initialize()) {
96                         exit(1);
97                 }
98         }
99 }
100
101 static void flush_caches_noinit(void)
102 {
103         /*
104          * We need to invalidate cached user list entries on a SIGHUP
105          * otherwise cached access denied errors due to restrict anonymous
106          * hang around until the sequence number changes.
107          * NB
108          * Skip uninitialized domains when flush cache.
109          * If domain is not initialized, it means it is never
110          * used or never become online. look, wcache_invalidate_cache()
111          * -> get_cache() -> init_dc_connection(). It causes a lot of traffic
112          * for unused domains and large traffic for primay domain's DC if there
113          * are many domains..
114          */
115
116         if (!wcache_invalidate_cache_noinit()) {
117                 DEBUG(0, ("invalidating the cache failed; revalidate the cache\n"));
118                 if (!winbindd_cache_validate_and_initialize()) {
119                         exit(1);
120                 }
121         }
122 }
123
124 /* Handle the signal by unlinking socket and exiting */
125
126 static void terminate(bool is_parent)
127 {
128         if (is_parent) {
129                 /* When parent goes away we should
130                  * remove the socket file. Not so
131                  * when children terminate.
132                  */ 
133                 char *path = NULL;
134
135                 if (asprintf(&path, "%s/%s",
136                         get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME) > 0) {
137                         unlink(path);
138                         SAFE_FREE(path);
139                 }
140         }
141
142         idmap_close();
143
144         trustdom_cache_shutdown();
145
146         gencache_stabilize();
147
148 #if 0
149         if (interactive) {
150                 TALLOC_CTX *mem_ctx = talloc_init("end_description");
151                 char *description = talloc_describe_all(mem_ctx);
152
153                 DEBUG(3, ("tallocs left:\n%s\n", description));
154                 talloc_destroy(mem_ctx);
155         }
156 #endif
157
158         if (is_parent) {
159                 serverid_deregister(procid_self());
160                 pidfile_unlink();
161         }
162
163         exit(0);
164 }
165
166 static void winbindd_sig_term_handler(struct tevent_context *ev,
167                                       struct tevent_signal *se,
168                                       int signum,
169                                       int count,
170                                       void *siginfo,
171                                       void *private_data)
172 {
173         bool *is_parent = talloc_get_type_abort(private_data, bool);
174
175         DEBUG(0,("Got sig[%d] terminate (is_parent=%d)\n",
176                  signum, (int)*is_parent));
177         terminate(*is_parent);
178 }
179
180 bool winbindd_setup_sig_term_handler(bool parent)
181 {
182         struct tevent_signal *se;
183         bool *is_parent;
184
185         is_parent = talloc(winbind_event_context(), bool);
186         if (!is_parent) {
187                 return false;
188         }
189
190         *is_parent = parent;
191
192         se = tevent_add_signal(winbind_event_context(),
193                                is_parent,
194                                SIGTERM, 0,
195                                winbindd_sig_term_handler,
196                                is_parent);
197         if (!se) {
198                 DEBUG(0,("failed to setup SIGTERM handler"));
199                 talloc_free(is_parent);
200                 return false;
201         }
202
203         se = tevent_add_signal(winbind_event_context(),
204                                is_parent,
205                                SIGINT, 0,
206                                winbindd_sig_term_handler,
207                                is_parent);
208         if (!se) {
209                 DEBUG(0,("failed to setup SIGINT handler"));
210                 talloc_free(is_parent);
211                 return false;
212         }
213
214         se = tevent_add_signal(winbind_event_context(),
215                                is_parent,
216                                SIGQUIT, 0,
217                                winbindd_sig_term_handler,
218                                is_parent);
219         if (!se) {
220                 DEBUG(0,("failed to setup SIGINT handler"));
221                 talloc_free(is_parent);
222                 return false;
223         }
224
225         return true;
226 }
227
228 static void winbindd_sig_hup_handler(struct tevent_context *ev,
229                                      struct tevent_signal *se,
230                                      int signum,
231                                      int count,
232                                      void *siginfo,
233                                      void *private_data)
234 {
235         const char *file = (const char *)private_data;
236
237         DEBUG(1,("Reloading services after SIGHUP\n"));
238         flush_caches_noinit();
239         winbindd_reload_services_file(file);
240 }
241
242 bool winbindd_setup_sig_hup_handler(const char *lfile)
243 {
244         struct tevent_signal *se;
245         char *file = NULL;
246
247         if (lfile) {
248                 file = talloc_strdup(winbind_event_context(),
249                                      lfile);
250                 if (!file) {
251                         return false;
252                 }
253         }
254
255         se = tevent_add_signal(winbind_event_context(),
256                                winbind_event_context(),
257                                SIGHUP, 0,
258                                winbindd_sig_hup_handler,
259                                file);
260         if (!se) {
261                 return false;
262         }
263
264         return true;
265 }
266
267 static void winbindd_sig_chld_handler(struct tevent_context *ev,
268                                       struct tevent_signal *se,
269                                       int signum,
270                                       int count,
271                                       void *siginfo,
272                                       void *private_data)
273 {
274         pid_t pid;
275
276         while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
277                 winbind_child_died(pid);
278         }
279 }
280
281 static bool winbindd_setup_sig_chld_handler(void)
282 {
283         struct tevent_signal *se;
284
285         se = tevent_add_signal(winbind_event_context(),
286                                winbind_event_context(),
287                                SIGCHLD, 0,
288                                winbindd_sig_chld_handler,
289                                NULL);
290         if (!se) {
291                 return false;
292         }
293
294         return true;
295 }
296
297 static void winbindd_sig_usr2_handler(struct tevent_context *ev,
298                                       struct tevent_signal *se,
299                                       int signum,
300                                       int count,
301                                       void *siginfo,
302                                       void *private_data)
303 {
304         winbindd_status();
305 }
306
307 static bool winbindd_setup_sig_usr2_handler(void)
308 {
309         struct tevent_signal *se;
310
311         se = tevent_add_signal(winbind_event_context(),
312                                winbind_event_context(),
313                                SIGUSR2, 0,
314                                winbindd_sig_usr2_handler,
315                                NULL);
316         if (!se) {
317                 return false;
318         }
319
320         return true;
321 }
322
323 /* React on 'smbcontrol winbindd reload-config' in the same way as on SIGHUP*/
324 static void msg_reload_services(struct messaging_context *msg,
325                                 void *private_data,
326                                 uint32_t msg_type,
327                                 struct server_id server_id,
328                                 DATA_BLOB *data)
329 {
330         /* Flush various caches */
331         flush_caches();
332         winbindd_reload_services_file((const char *) private_data);
333 }
334
335 /* React on 'smbcontrol winbindd shutdown' in the same way as on SIGTERM*/
336 static void msg_shutdown(struct messaging_context *msg,
337                          void *private_data,
338                          uint32_t msg_type,
339                          struct server_id server_id,
340                          DATA_BLOB *data)
341 {
342         /* only the parent waits for this message */
343         DEBUG(0,("Got shutdown message\n"));
344         terminate(true);
345 }
346
347
348 static void winbind_msg_validate_cache(struct messaging_context *msg_ctx,
349                                        void *private_data,
350                                        uint32_t msg_type,
351                                        struct server_id server_id,
352                                        DATA_BLOB *data)
353 {
354         uint8 ret;
355         pid_t child_pid;
356
357         DEBUG(10, ("winbindd_msg_validate_cache: got validate-cache "
358                    "message.\n"));
359
360         /*
361          * call the validation code from a child:
362          * so we don't block the main winbindd and the validation
363          * code can safely use fork/waitpid...
364          */
365         child_pid = sys_fork();
366
367         if (child_pid == -1) {
368                 DEBUG(1, ("winbind_msg_validate_cache: Could not fork: %s\n",
369                           strerror(errno)));
370                 return;
371         }
372
373         if (child_pid != 0) {
374                 /* parent */
375                 DEBUG(5, ("winbind_msg_validate_cache: child created with "
376                           "pid %d.\n", (int)child_pid));
377                 return;
378         }
379
380         /* child */
381
382         if (!winbindd_reinit_after_fork(NULL)) {
383                 _exit(0);
384         }
385
386         /* install default SIGCHLD handler: validation code uses fork/waitpid */
387         CatchSignal(SIGCHLD, SIG_DFL);
388
389         ret = (uint8)winbindd_validate_cache_nobackup();
390         DEBUG(10, ("winbindd_msg_validata_cache: got return value %d\n", ret));
391         messaging_send_buf(msg_ctx, server_id, MSG_WINBIND_VALIDATE_CACHE, &ret,
392                            (size_t)1);
393         _exit(0);
394 }
395
396 void winbindd_register_handlers(void)
397 {
398         struct tevent_timer *te;
399         /* Setup signal handlers */
400
401         if (!winbindd_setup_sig_term_handler(true))
402                 exit(1);
403         if (!winbindd_setup_sig_hup_handler(NULL))
404                 exit(1);
405         if (!winbindd_setup_sig_chld_handler())
406                 exit(1);
407         if (!winbindd_setup_sig_usr2_handler())
408                 exit(1);
409
410         CatchSignal(SIGPIPE, SIG_IGN);                 /* Ignore sigpipe */
411
412         /*
413          * Ensure all cache and idmap caches are consistent
414          * and initialized before we startup.
415          */
416         if (!winbindd_cache_validate_and_initialize()) {
417                 exit(1);
418         }
419
420         /* get broadcast messages */
421
422         if (!serverid_register(procid_self(),
423                                FLAG_MSG_GENERAL|FLAG_MSG_DBWRAP)) {
424                 DEBUG(1, ("Could not register myself in serverid.tdb\n"));
425                 exit(1);
426         }
427
428         /* React on 'smbcontrol winbindd reload-config' in the same way
429            as to SIGHUP signal */
430         messaging_register(winbind_messaging_context(), NULL,
431                            MSG_SMB_CONF_UPDATED, msg_reload_services);
432         messaging_register(winbind_messaging_context(), NULL,
433                            MSG_SHUTDOWN, msg_shutdown);
434
435         /* Handle online/offline messages. */
436         messaging_register(winbind_messaging_context(), NULL,
437                            MSG_WINBIND_OFFLINE, winbind_msg_offline);
438         messaging_register(winbind_messaging_context(), NULL,
439                            MSG_WINBIND_ONLINE, winbind_msg_online);
440         messaging_register(winbind_messaging_context(), NULL,
441                            MSG_WINBIND_ONLINESTATUS, winbind_msg_onlinestatus);
442
443         messaging_register(winbind_messaging_context(), NULL,
444                            MSG_DUMP_EVENT_LIST, winbind_msg_dump_event_list);
445
446         messaging_register(winbind_messaging_context(), NULL,
447                            MSG_WINBIND_VALIDATE_CACHE,
448                            winbind_msg_validate_cache);
449
450         messaging_register(winbind_messaging_context(), NULL,
451                            MSG_WINBIND_DUMP_DOMAIN_LIST,
452                            winbind_msg_dump_domain_list);
453
454         /* Register handler for MSG_DEBUG. */
455         messaging_register(winbind_messaging_context(), NULL,
456                            MSG_DEBUG,
457                            winbind_msg_debug);
458
459         netsamlogon_cache_init(); /* Non-critical */
460
461         /* clear the cached list of trusted domains */
462
463         wcache_tdc_clear();
464
465         if (!init_domain_list()) {
466                 DEBUG(0,("unable to initialize domain list\n"));
467                 exit(1);
468         }
469
470         init_idmap_child();
471         init_locator_child();
472
473         smb_nscd_flush_user_cache();
474         smb_nscd_flush_group_cache();
475
476         te = tevent_add_timer(winbind_event_context(), NULL, timeval_zero(),
477                               rescan_trusted_domains, NULL);
478         if (te == NULL) {
479                 DEBUG(0, ("Could not trigger rescan_trusted_domains()\n"));
480                 exit(1);
481         }
482
483 }