s3: Add "smbcontrol winbindd ip-dropped <local-ip>"
[obnox/samba-ctdb.git] / source3 / utils / smbcontrol.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Send messages to other Samba daemons
5
6    Copyright (C) Tim Potter 2003
7    Copyright (C) Andrew Tridgell 1994-1998
8    Copyright (C) Martin Pool 2001-2002
9    Copyright (C) Simo Sorce 2002
10    Copyright (C) James Peach 2006
11    
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16    
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21    
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27
28 #if HAVE_LIBUNWIND_H
29 #include <libunwind.h>
30 #endif
31
32 #if HAVE_LIBUNWIND_PTRACE_H
33 #include <libunwind-ptrace.h>
34 #endif
35
36 #if HAVE_SYS_PTRACE_H
37 #include <sys/ptrace.h>
38 #endif
39
40 /* Default timeout value when waiting for replies (in seconds) */
41
42 #define DEFAULT_TIMEOUT 10
43
44 static int timeout = DEFAULT_TIMEOUT;
45 static int num_replies;         /* Used by message callback fns */
46
47 /* Send a message to a destination pid.  Zero means broadcast smbd. */
48
49 static bool send_message(struct messaging_context *msg_ctx,
50                          struct server_id pid, int msg_type,
51                          const void *buf, int len)
52 {
53         bool ret;
54         int n_sent = 0;
55
56         if (procid_to_pid(&pid) != 0)
57                 return NT_STATUS_IS_OK(
58                         messaging_send_buf(msg_ctx, pid, msg_type,
59                                            (uint8 *)buf, len));
60
61         ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
62         DEBUG(10,("smbcontrol/send_message: broadcast message to "
63                   "%d processes\n", n_sent));
64         
65         return ret;
66 }
67
68 static void smbcontrol_timeout(struct tevent_context *event_ctx,
69                                struct tevent_timer *te,
70                                struct timeval now,
71                                void *private_data)
72 {
73         bool *timed_out = (bool *)private_data;
74         TALLOC_FREE(te);
75         *timed_out = True;
76 }
77
78 /* Wait for one or more reply messages */
79
80 static void wait_replies(struct messaging_context *msg_ctx,
81                          bool multiple_replies)
82 {
83         struct tevent_timer *te;
84         bool timed_out = False;
85
86         if (!(te = tevent_add_timer(messaging_event_context(msg_ctx), NULL,
87                                     timeval_current_ofs(timeout, 0),
88                                     smbcontrol_timeout, (void *)&timed_out))) {
89                 DEBUG(0, ("tevent_add_timer failed\n"));
90                 return;
91         }
92
93         while (!timed_out) {
94                 int ret;
95                 if (num_replies > 0 && !multiple_replies)
96                         break;
97                 ret = tevent_loop_once(messaging_event_context(msg_ctx));
98                 if (ret != 0) {
99                         break;
100                 }
101         }
102 }
103
104 /* Message handler callback that displays the PID and a string on stdout */
105
106 static void print_pid_string_cb(struct messaging_context *msg,
107                                 void *private_data, 
108                                 uint32_t msg_type, 
109                                 struct server_id pid,
110                                 DATA_BLOB *data)
111 {
112         char *pidstr;
113
114         pidstr = procid_str(talloc_tos(), &pid);
115         printf("PID %s: %.*s", pidstr, (int)data->length,
116                (const char *)data->data);
117         TALLOC_FREE(pidstr);
118         num_replies++;
119 }
120
121 /* Message handler callback that displays a string on stdout */
122
123 static void print_string_cb(struct messaging_context *msg,
124                             void *private_data, 
125                             uint32_t msg_type, 
126                             struct server_id pid,
127                             DATA_BLOB *data)
128 {
129         printf("%.*s", (int)data->length, (const char *)data->data);
130         num_replies++;
131 }
132
133 /* Send no message.  Useful for testing. */
134
135 static bool do_noop(struct messaging_context *msg_ctx,
136                     const struct server_id pid,
137                     const int argc, const char **argv)
138 {
139         if (argc != 1) {
140                 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
141                 return False;
142         }
143
144         /* Move along, nothing to see here */
145
146         return True;
147 }
148
149 /* Send a debug string */
150
151 static bool do_debug(struct messaging_context *msg_ctx,
152                      const struct server_id pid,
153                      const int argc, const char **argv)
154 {
155         if (argc != 2) {
156                 fprintf(stderr, "Usage: smbcontrol <dest> debug "
157                         "<debug-string>\n");
158                 return False;
159         }
160
161         return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
162                             strlen(argv[1]) + 1);
163 }
164
165 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
166
167 /* Return the name of a process given it's PID. This will only work on Linux,
168  * but that's probably moot since this whole stack tracing implementatino is
169  * Linux-specific anyway.
170  */
171 static const char * procname(pid_t pid, char * buf, size_t bufsz)
172 {
173         char path[64];
174         FILE * fp;
175
176         snprintf(path, sizeof(path), "/proc/%llu/cmdline",
177                 (unsigned long long)pid);
178         if ((fp = fopen(path, "r")) == NULL) {
179                 return NULL;
180         }
181
182         fgets(buf, bufsz, fp);
183
184         fclose(fp);
185         return buf;
186 }
187
188 static void print_stack_trace(pid_t pid, int * count)
189 {
190         void *              pinfo = NULL;
191         unw_addr_space_t    aspace = NULL;
192         unw_cursor_t        cursor;
193         unw_word_t          ip, sp;
194
195         char                nbuf[256];
196         unw_word_t          off;
197
198         int ret;
199
200         if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
201                 fprintf(stderr,
202                         "Failed to attach to process %llu: %s\n",
203                         (unsigned long long)pid, strerror(errno));
204                 return;
205         }
206
207         /* Wait until the attach is complete. */
208         waitpid(pid, NULL, 0);
209
210         if (((pinfo = _UPT_create(pid)) == NULL) ||
211             ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
212                 /* Probably out of memory. */
213                 fprintf(stderr,
214                         "Unable to initialize stack unwind for process %llu\n",
215                         (unsigned long long)pid);
216                 goto cleanup;
217         }
218
219         if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
220                 fprintf(stderr,
221                         "Unable to unwind stack for process %llu: %s\n",
222                         (unsigned long long)pid, unw_strerror(ret));
223                 goto cleanup;
224         }
225
226         if (*count > 0) {
227                 printf("\n");
228         }
229
230         if (procname(pid, nbuf, sizeof(nbuf))) {
231                 printf("Stack trace for process %llu (%s):\n",
232                         (unsigned long long)pid, nbuf);
233         } else {
234                 printf("Stack trace for process %llu:\n",
235                         (unsigned long long)pid);
236         }
237
238         while (unw_step(&cursor) > 0) {
239                 ip = sp = off = 0;
240                 unw_get_reg(&cursor, UNW_REG_IP, &ip);
241                 unw_get_reg(&cursor, UNW_REG_SP, &sp);
242
243                 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
244                 if (ret != 0 && ret != -UNW_ENOMEM) {
245                         snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
246                 }
247                 printf("    %s + %#llx [ip=%#llx] [sp=%#llx]\n",
248                         nbuf, (long long)off, (long long)ip,
249                         (long long)sp);
250         }
251
252         (*count)++;
253
254 cleanup:
255         if (aspace) {
256                 unw_destroy_addr_space(aspace);
257         }
258
259         if (pinfo) {
260                 _UPT_destroy(pinfo);
261         }
262
263         ptrace(PTRACE_DETACH, pid, NULL, NULL);
264 }
265
266 static int stack_trace_connection(struct db_record *rec,
267                                   const struct connections_key *key,
268                                   const struct connections_data *crec,
269                                   void *priv)
270 {
271         print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
272
273         return 0;
274 }
275
276 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
277                                   const struct server_id pid,
278                        const int argc, const char **argv)
279 {
280         pid_t   dest;
281         int     count = 0;
282
283         if (argc != 1) {
284                 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
285                 return False;
286         }
287
288         dest = procid_to_pid(&pid);
289
290         if (dest != 0) {
291                 /* It would be nice to be able to make sure that this PID is
292                  * the PID of a smbd/winbind/nmbd process, not some random PID
293                  * the user liked the look of. It doesn't seem like it's worth
294                  * the effort at the moment, however.
295                  */
296                 print_stack_trace(dest, &count);
297         } else {
298                 connections_forall(stack_trace_connection, &count);
299         }
300
301         return True;
302 }
303
304 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
305
306 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
307                                   const struct server_id pid,
308                        const int argc, const char **argv)
309 {
310         fprintf(stderr,
311                 "Daemon stack tracing is not supported on this platform\n");
312         return False;
313 }
314
315 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
316
317 /* Inject a fault (fatal signal) into a running smbd */
318
319 static bool do_inject_fault(struct messaging_context *msg_ctx,
320                             const struct server_id pid,
321                        const int argc, const char **argv)
322 {
323         if (argc != 2) {
324                 fprintf(stderr, "Usage: smbcontrol <dest> inject "
325                         "<bus|hup|term|internal|segv>\n");
326                 return False;
327         }
328
329 #ifndef DEVELOPER
330         fprintf(stderr, "Fault injection is only available in "
331                 "developer builds\n");
332         return False;
333 #else /* DEVELOPER */
334         {
335                 int sig = 0;
336
337                 if (strcmp(argv[1], "bus") == 0) {
338                         sig = SIGBUS;
339                 } else if (strcmp(argv[1], "hup") == 0) {
340                         sig = SIGHUP;
341                 } else if (strcmp(argv[1], "term") == 0) {
342                         sig = SIGTERM;
343                 } else if (strcmp(argv[1], "segv") == 0) {
344                         sig = SIGSEGV;
345                 } else if (strcmp(argv[1], "internal") == 0) {
346                         /* Force an internal error, ie. an unclean exit. */
347                         sig = -1;
348                 } else {
349                         fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
350                         return False;
351                 }
352
353                 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
354                                     &sig, sizeof(int));
355         }
356 #endif /* DEVELOPER */
357 }
358
359 /* Force a browser election */
360
361 static bool do_election(struct messaging_context *msg_ctx,
362                         const struct server_id pid,
363                         const int argc, const char **argv)
364 {
365         if (argc != 1) {
366                 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
367                 return False;
368         }
369
370         return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
371 }
372
373 /* Ping a samba daemon process */
374
375 static void pong_cb(struct messaging_context *msg,
376                     void *private_data, 
377                     uint32_t msg_type, 
378                     struct server_id pid,
379                     DATA_BLOB *data)
380 {
381         char *src_string = procid_str(NULL, &pid);
382         printf("PONG from pid %s\n", src_string);
383         TALLOC_FREE(src_string);
384         num_replies++;
385 }
386
387 static bool do_ping(struct messaging_context *msg_ctx,
388                     const struct server_id pid,
389                     const int argc, const char **argv)
390 {
391         if (argc != 1) {
392                 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
393                 return False;
394         }
395
396         /* Send a message and register our interest in a reply */
397
398         if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
399                 return False;
400
401         messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
402
403         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
404
405         /* No replies were received within the timeout period */
406
407         if (num_replies == 0)
408                 printf("No replies received\n");
409
410         messaging_deregister(msg_ctx, MSG_PONG, NULL);
411
412         return num_replies;
413 }
414
415 /* Set profiling options */
416
417 static bool do_profile(struct messaging_context *msg_ctx,
418                        const struct server_id pid,
419                        const int argc, const char **argv)
420 {
421         int v;
422
423         if (argc != 2) {
424                 fprintf(stderr, "Usage: smbcontrol <dest> profile "
425                         "<off|count|on|flush>\n");
426                 return False;
427         }
428
429         if (strcmp(argv[1], "off") == 0) {
430                 v = 0;
431         } else if (strcmp(argv[1], "count") == 0) {
432                 v = 1;
433         } else if (strcmp(argv[1], "on") == 0) {
434                 v = 2;
435         } else if (strcmp(argv[1], "flush") == 0) {
436                 v = 3;
437         } else {
438                 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
439                 return False;
440         }
441
442         return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
443 }
444
445 /* Return the profiling level */
446
447 static void profilelevel_cb(struct messaging_context *msg_ctx,
448                             void *private_data, 
449                             uint32_t msg_type, 
450                             struct server_id pid,
451                             DATA_BLOB *data)
452 {
453         int level;
454         const char *s;
455
456         num_replies++;
457
458         if (data->length != sizeof(int)) {
459                 fprintf(stderr, "invalid message length %ld returned\n", 
460                         (unsigned long)data->length);
461                 return;
462         }
463
464         memcpy(&level, data->data, sizeof(int));
465
466         switch (level) {
467         case 0:
468                 s = "not enabled";
469                 break;
470         case 1:
471                 s = "off";
472                 break;
473         case 3:
474                 s = "count only";
475                 break;
476         case 7:
477                 s = "count and time";
478                 break;
479         default:
480                 s = "BOGUS";
481                 break;
482         }
483         
484         printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
485 }
486
487 static void profilelevel_rqst(struct messaging_context *msg_ctx,
488                               void *private_data, 
489                               uint32_t msg_type, 
490                               struct server_id pid,
491                               DATA_BLOB *data)
492 {
493         int v = 0;
494
495         /* Send back a dummy reply */
496
497         send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
498 }
499
500 static bool do_profilelevel(struct messaging_context *msg_ctx,
501                             const struct server_id pid,
502                             const int argc, const char **argv)
503 {
504         if (argc != 1) {
505                 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
506                 return False;
507         }
508
509         /* Send a message and register our interest in a reply */
510
511         if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
512                 return False;
513
514         messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
515         messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
516                            profilelevel_rqst);
517
518         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
519
520         /* No replies were received within the timeout period */
521
522         if (num_replies == 0)
523                 printf("No replies received\n");
524
525         messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
526
527         return num_replies;
528 }
529
530 /* Display debug level settings */
531
532 static bool do_debuglevel(struct messaging_context *msg_ctx,
533                           const struct server_id pid,
534                           const int argc, const char **argv)
535 {
536         if (argc != 1) {
537                 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
538                 return False;
539         }
540
541         /* Send a message and register our interest in a reply */
542
543         if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
544                 return False;
545
546         messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
547
548         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
549
550         /* No replies were received within the timeout period */
551
552         if (num_replies == 0)
553                 printf("No replies received\n");
554
555         messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
556
557         return num_replies;
558 }
559
560 /* Send a print notify message */
561
562 static bool do_printnotify(struct messaging_context *msg_ctx,
563                            const struct server_id pid,
564                            const int argc, const char **argv)
565 {
566         const char *cmd;
567
568         /* Check for subcommand */
569
570         if (argc == 1) {
571                 fprintf(stderr, "Must specify subcommand:\n");
572                 fprintf(stderr, "\tqueuepause <printername>\n");
573                 fprintf(stderr, "\tqueueresume <printername>\n");
574                 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
575                 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
576                 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
577                 fprintf(stderr, "\tprinter <printername> <comment|port|"
578                         "driver> <value>\n");
579                 
580                 return False;
581         }
582
583         cmd = argv[1];
584
585         if (strcmp(cmd, "queuepause") == 0) {
586
587                 if (argc != 3) {
588                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
589                                 " queuepause <printername>\n");
590                         return False;
591                 }
592                 
593                 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
594
595                 goto send;
596
597         } else if (strcmp(cmd, "queueresume") == 0) {
598
599                 if (argc != 3) {
600                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
601                                 " queuereume <printername>\n");
602                         return False;
603                 }
604                 
605                 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
606
607                 goto send;
608
609         } else if (strcmp(cmd, "jobpause") == 0) {
610                 int jobid;
611
612                 if (argc != 4) {
613                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
614                                 " jobpause <printername> <unix-jobid>\n");
615                         return False;
616                 }
617
618                 jobid = atoi(argv[3]);
619
620                 notify_job_status_byname(
621                         argv[2], jobid, JOB_STATUS_PAUSED, 
622                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
623
624                 goto send;
625
626         } else if (strcmp(cmd, "jobresume") == 0) {
627                 int jobid;
628
629                 if (argc != 4) {
630                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
631                                 " jobpause <printername> <unix-jobid>\n");
632                         return False;
633                 }
634
635                 jobid = atoi(argv[3]);
636
637                 notify_job_status_byname(
638                         argv[2], jobid, JOB_STATUS_QUEUED, 
639                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
640
641                 goto send;
642
643         } else if (strcmp(cmd, "jobdelete") == 0) {
644                 int jobid;
645
646                 if (argc != 4) {
647                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
648                                 " jobpause <printername> <unix-jobid>\n");
649                         return False;
650                 }
651
652                 jobid = atoi(argv[3]);
653
654                 notify_job_status_byname(
655                         argv[2], jobid, JOB_STATUS_DELETING,
656                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
657                 
658                 notify_job_status_byname(
659                         argv[2], jobid, JOB_STATUS_DELETING|
660                         JOB_STATUS_DELETED,
661                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
662
663                 goto send;
664
665         } else if (strcmp(cmd, "printer") == 0) {
666                 uint32 attribute;
667                 
668                 if (argc != 5) {
669                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
670                                 "printer <printername> <comment|port|driver> "
671                                 "<value>\n");
672                         return False;
673                 }
674
675                 if (strcmp(argv[3], "comment") == 0) {
676                         attribute = PRINTER_NOTIFY_FIELD_COMMENT;
677                 } else if (strcmp(argv[3], "port") == 0) {
678                         attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
679                 } else if (strcmp(argv[3], "driver") == 0) {
680                         attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
681                 } else {
682                         fprintf(stderr, "Invalid printer command '%s'\n",
683                                 argv[3]);
684                         return False;
685                 }
686
687                 notify_printer_byname(argv[2], attribute,
688                                       CONST_DISCARD(char *, argv[4]));
689
690                 goto send;
691         }
692
693         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
694         return False;
695
696 send:
697         print_notify_send_messages(msg_ctx, 0);
698         return True;
699 }
700
701 /* Close a share */
702
703 static bool do_closeshare(struct messaging_context *msg_ctx,
704                           const struct server_id pid,
705                           const int argc, const char **argv)
706 {
707         if (argc != 2) {
708                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
709                         "<sharename>\n");
710                 return False;
711         }
712
713         return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
714                             strlen(argv[1]) + 1);
715 }
716
717 /* Tell winbindd an IP got dropped */
718
719 static bool do_ip_dropped(struct messaging_context *msg_ctx,
720                           const struct server_id pid,
721                           const int argc, const char **argv)
722 {
723         if (argc != 2) {
724                 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
725                         "<ip-address>\n");
726                 return False;
727         }
728
729         return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
730                             strlen(argv[1]) + 1);
731 }
732
733 /* force a blocking lock retry */
734
735 static bool do_lockretry(struct messaging_context *msg_ctx,
736                          const struct server_id pid,
737                          const int argc, const char **argv)
738 {
739         if (argc != 1) {
740                 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
741                 return False;
742         }
743
744         return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
745 }
746
747 /* force a validation of all brl entries, including re-sends. */
748
749 static bool do_brl_revalidate(struct messaging_context *msg_ctx,
750                               const struct server_id pid,
751                               const int argc, const char **argv)
752 {
753         if (argc != 1) {
754                 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
755                 return False;
756         }
757
758         return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
759 }
760
761 /* Force a SAM synchronisation */
762
763 static bool do_samsync(struct messaging_context *msg_ctx,
764                        const struct server_id pid,
765                        const int argc, const char **argv)
766 {
767         if (argc != 1) {
768                 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
769                 return False;
770         }
771
772         return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
773 }
774
775 /* Force a SAM replication */
776
777 static bool do_samrepl(struct messaging_context *msg_ctx,
778                        const struct server_id pid,
779                        const int argc, const char **argv)
780 {
781         if (argc != 1) {
782                 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
783                 return False;
784         }
785
786         return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
787 }
788
789 /* Display talloc pool usage */
790
791 static bool do_poolusage(struct messaging_context *msg_ctx,
792                          const struct server_id pid,
793                          const int argc, const char **argv)
794 {
795         if (argc != 1) {
796                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
797                 return False;
798         }
799
800         messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
801
802         /* Send a message and register our interest in a reply */
803
804         if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
805                 return False;
806
807         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
808
809         /* No replies were received within the timeout period */
810
811         if (num_replies == 0)
812                 printf("No replies received\n");
813
814         messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
815
816         return num_replies;
817 }
818
819 /* Perform a dmalloc mark */
820
821 static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
822                             const struct server_id pid,
823                             const int argc, const char **argv)
824 {
825         if (argc != 1) {
826                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
827                 return False;
828         }
829
830         return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
831 }
832
833 /* Perform a dmalloc changed */
834
835 static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
836                                const struct server_id pid,
837                                const int argc, const char **argv)
838 {
839         if (argc != 1) {
840                 fprintf(stderr, "Usage: smbcontrol <dest> "
841                         "dmalloc-log-changed\n");
842                 return False;
843         }
844
845         return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
846                             NULL, 0);
847 }
848
849 /* Shutdown a server process */
850
851 static bool do_shutdown(struct messaging_context *msg_ctx,
852                         const struct server_id pid,
853                         const int argc, const char **argv)
854 {
855         if (argc != 1) {
856                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
857                 return False;
858         }
859
860         return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
861 }
862
863 /* Notify a driver upgrade */
864
865 static bool do_drvupgrade(struct messaging_context *msg_ctx,
866                           const struct server_id pid,
867                           const int argc, const char **argv)
868 {
869         if (argc != 2) {
870                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
871                         "<driver-name>\n");
872                 return False;
873         }
874
875         return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
876                             strlen(argv[1]) + 1);
877 }
878
879 static bool do_winbind_online(struct messaging_context *msg_ctx,
880                               const struct server_id pid,
881                              const int argc, const char **argv)
882 {
883         TDB_CONTEXT *tdb;
884
885         if (argc != 1) {
886                 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
887                 return False;
888         }
889
890         /* Remove the entry in the winbindd_cache tdb to tell a later
891            starting winbindd that we're online. */
892
893         tdb = tdb_open_log(cache_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
894         if (!tdb) {
895                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
896                         cache_path("winbindd_cache.tdb"));
897                 return False;
898         }
899
900         tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
901         tdb_close(tdb);
902
903         return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
904 }
905
906 static bool do_winbind_offline(struct messaging_context *msg_ctx,
907                                const struct server_id pid,
908                              const int argc, const char **argv)
909 {
910         TDB_CONTEXT *tdb;
911         bool ret = False;
912         int retry = 0;
913
914         if (argc != 1) {
915                 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
916                 return False;
917         }
918
919         /* Create an entry in the winbindd_cache tdb to tell a later
920            starting winbindd that we're offline. We may actually create
921            it here... */
922
923         tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
924                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
925                                 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
926
927         if (!tdb) {
928                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
929                         cache_path("winbindd_cache.tdb"));
930                 return False;
931         }
932
933         /* There's a potential race condition that if a child
934            winbindd detects a domain is online at the same time
935            we're trying to tell it to go offline that it might 
936            delete the record we add between us adding it and
937            sending the message. Minimize this by retrying up to
938            5 times. */
939
940         for (retry = 0; retry < 5; retry++) {
941                 TDB_DATA d;
942                 uint8 buf[4];
943
944                 ZERO_STRUCT(d);
945
946                 SIVAL(buf, 0, time(NULL));
947                 d.dptr = buf;
948                 d.dsize = 4;
949
950                 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
951
952                 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
953                                    NULL, 0);
954
955                 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
956                 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
957         
958                 if (!d.dptr || d.dsize != 4) {
959                         SAFE_FREE(d.dptr);
960                         DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
961                 } else {
962                         SAFE_FREE(d.dptr);
963                         break;
964                 }
965         }
966
967         tdb_close(tdb);
968         return ret;
969 }
970
971 static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
972                                     const struct server_id pid,
973                                     const int argc, const char **argv)
974 {
975         struct server_id myid;
976
977         myid = pid_to_procid(sys_getpid());
978
979         if (argc != 1) {
980                 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
981                 return False;
982         }
983
984         messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
985                            print_pid_string_cb);
986
987         if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
988                           sizeof(myid)))
989                 return False;
990
991         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
992
993         /* No replies were received within the timeout period */
994
995         if (num_replies == 0)
996                 printf("No replies received\n");
997
998         messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
999
1000         return num_replies;
1001 }
1002
1003 static bool do_dump_event_list(struct messaging_context *msg_ctx,
1004                                const struct server_id pid,
1005                                const int argc, const char **argv)
1006 {
1007         struct server_id myid;
1008
1009         myid = pid_to_procid(sys_getpid());
1010
1011         if (argc != 1) {
1012                 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1013                 return False;
1014         }
1015
1016         return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1017 }
1018
1019 static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
1020                                         const struct server_id pid,
1021                                         const int argc, const char **argv)
1022 {
1023         const char *domain = NULL;
1024         int domain_len = 0;
1025         struct server_id myid;
1026         uint8_t *buf = NULL;
1027         int buf_len = 0;
1028
1029         myid = pid_to_procid(sys_getpid());
1030
1031         if (argc < 1 || argc > 2) {
1032                 fprintf(stderr, "Usage: smbcontrol <dest> dump_domain_list "
1033                         "<domain>\n");
1034                 return false;
1035         }
1036
1037         if (argc == 2) {
1038                 domain = argv[1];
1039                 domain_len = strlen(argv[1]) + 1;
1040         }
1041
1042         messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1043                            print_pid_string_cb);
1044
1045         buf_len = sizeof(myid)+domain_len;
1046         buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1047         if (!buf) {
1048                 return false;
1049         }
1050
1051         memcpy(buf, &myid, sizeof(myid));
1052         memcpy(&buf[sizeof(myid)], domain, domain_len);
1053
1054         if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1055                           buf, buf_len))
1056         {
1057                 SAFE_FREE(buf);
1058                 return false;
1059         }
1060
1061         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1062
1063         /* No replies were received within the timeout period */
1064
1065         SAFE_FREE(buf);
1066         if (num_replies == 0) {
1067                 printf("No replies received\n");
1068         }
1069
1070         messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1071
1072         return num_replies;
1073 }
1074
1075 static void winbind_validate_cache_cb(struct messaging_context *msg,
1076                                       void *private_data,
1077                                       uint32_t msg_type,
1078                                       struct server_id pid,
1079                                       DATA_BLOB *data)
1080 {
1081         char *src_string = procid_str(NULL, &pid);
1082         printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1083                (*(data->data) == 0 ? "" : "NOT "), src_string);
1084         TALLOC_FREE(src_string);
1085         num_replies++;
1086 }
1087
1088 static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
1089                                       const struct server_id pid,
1090                                       const int argc, const char **argv)
1091 {
1092         struct server_id myid = pid_to_procid(sys_getpid());
1093
1094         if (argc != 1) {
1095                 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1096                 return False;
1097         }
1098
1099         messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1100                            winbind_validate_cache_cb);
1101
1102         if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1103                           sizeof(myid))) {
1104                 return False;
1105         }
1106
1107         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1108
1109         if (num_replies == 0) {
1110                 printf("No replies received\n");
1111         }
1112
1113         messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1114
1115         return num_replies;
1116 }
1117
1118 static bool do_reload_config(struct messaging_context *msg_ctx,
1119                              const struct server_id pid,
1120                              const int argc, const char **argv)
1121 {
1122         if (argc != 1) {
1123                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1124                 return False;
1125         }
1126
1127         return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1128 }
1129
1130 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1131 {
1132         fstring unix_name;
1133         memset( (char *)n, '\0', sizeof(struct nmb_name) );
1134         fstrcpy(unix_name, name);
1135         strupper_m(unix_name);
1136         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1137         n->name_type = (unsigned int)type & 0xFF;
1138         push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
1139 }
1140
1141 static bool do_nodestatus(struct messaging_context *msg_ctx,
1142                           const struct server_id pid,
1143                           const int argc, const char **argv)
1144 {
1145         struct packet_struct p;
1146
1147         if (argc != 2) {
1148                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1149                 return False;
1150         }
1151
1152         ZERO_STRUCT(p);
1153
1154         p.ip = interpret_addr2(argv[1]);
1155         p.port = 137;
1156         p.packet_type = NMB_PACKET;
1157
1158         p.packet.nmb.header.name_trn_id = 10;
1159         p.packet.nmb.header.opcode = 0;
1160         p.packet.nmb.header.response = False;
1161         p.packet.nmb.header.nm_flags.bcast = False;
1162         p.packet.nmb.header.nm_flags.recursion_available = False;
1163         p.packet.nmb.header.nm_flags.recursion_desired = False;
1164         p.packet.nmb.header.nm_flags.trunc = False;
1165         p.packet.nmb.header.nm_flags.authoritative = False;
1166         p.packet.nmb.header.rcode = 0;
1167         p.packet.nmb.header.qdcount = 1;
1168         p.packet.nmb.header.ancount = 0;
1169         p.packet.nmb.header.nscount = 0;
1170         p.packet.nmb.header.arcount = 0;
1171         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1172         p.packet.nmb.question.question_type = 0x21;
1173         p.packet.nmb.question.question_class = 0x1;
1174
1175         return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1176 }
1177
1178 /* A list of message type supported */
1179
1180 static const struct {
1181         const char *name;       /* Option name */
1182         bool (*fn)(struct messaging_context *msg_ctx,
1183                    const struct server_id pid,
1184                    const int argc, const char **argv);
1185         const char *help;       /* Short help text */
1186 } msg_types[] = {
1187         { "debug", do_debug, "Set debuglevel"  },
1188         { "force-election", do_election,
1189           "Force a browse election" },
1190         { "ping", do_ping, "Elicit a response" },
1191         { "profile", do_profile, "" },
1192         { "inject", do_inject_fault,
1193             "Inject a fatal signal into a running smbd"},
1194         { "stacktrace", do_daemon_stack_trace,
1195             "Display a stack trace of a daemon" },
1196         { "profilelevel", do_profilelevel, "" },
1197         { "debuglevel", do_debuglevel, "Display current debuglevels" },
1198         { "printnotify", do_printnotify, "Send a print notify message" },
1199         { "close-share", do_closeshare, "Forcibly disconnect a share" },
1200         { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1201         { "lockretry", do_lockretry, "Force a blocking lock retry" },
1202         { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1203         { "samsync", do_samsync, "Initiate SAM synchronisation" },
1204         { "samrepl", do_samrepl, "Initiate SAM replication" },
1205         { "pool-usage", do_poolusage, "Display talloc memory usage" },
1206         { "dmalloc-mark", do_dmalloc_mark, "" },
1207         { "dmalloc-log-changed", do_dmalloc_changed, "" },
1208         { "shutdown", do_shutdown, "Shut down daemon" },
1209         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1210         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1211         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1212         { "online", do_winbind_online, "Ask winbind to go into online state"},
1213         { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1214         { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1215         { "dump-event-list", do_dump_event_list, "Dump event list"},
1216         { "validate-cache" , do_winbind_validate_cache,
1217           "Validate winbind's credential cache" },
1218         { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1219         { "noop", do_noop, "Do nothing" },
1220         { NULL }
1221 };
1222
1223 /* Display usage information */
1224
1225 static void usage(poptContext pc)
1226 {
1227         int i;
1228
1229         poptPrintHelp(pc, stderr, 0);
1230
1231         fprintf(stderr, "\n");
1232         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1233                 "process ID\n");
1234
1235         fprintf(stderr, "\n");
1236         fprintf(stderr, "<message-type> is one of:\n");
1237
1238         for (i = 0; msg_types[i].name; i++) 
1239             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
1240                     msg_types[i].help);
1241
1242         fprintf(stderr, "\n");
1243
1244         exit(1);
1245 }
1246
1247 /* Return the pid number for a string destination */
1248
1249 static struct server_id parse_dest(const char *dest)
1250 {
1251         struct server_id result = {-1};
1252         pid_t pid;
1253
1254         /* Zero is a special return value for broadcast to all processes */
1255
1256         if (strequal(dest, "all")) {
1257                 return interpret_pid(MSG_BROADCAST_PID_STR);
1258         }
1259
1260         /* Try self - useful for testing */
1261
1262         if (strequal(dest, "self")) {
1263                 return pid_to_procid(sys_getpid());
1264         }
1265
1266         /* Fix winbind typo. */
1267         if (strequal(dest, "winbind")) {
1268                 dest = "winbindd";
1269         }
1270
1271         /* Check for numeric pid number */
1272         result = interpret_pid(dest);
1273
1274         /* Zero isn't valid if not "all". */
1275         if (result.pid && procid_valid(&result)) {
1276                 return result;
1277         }
1278
1279         /* Look up other destinations in pidfile directory */
1280
1281         if ((pid = pidfile_pid(dest)) != 0) {
1282                 return pid_to_procid(pid);
1283         }
1284
1285         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1286
1287         return result;
1288 }
1289
1290 /* Execute smbcontrol command */
1291
1292 static bool do_command(struct messaging_context *msg_ctx,
1293                        int argc, const char **argv)
1294 {
1295         const char *dest = argv[0], *command = argv[1];
1296         struct server_id pid;
1297         int i;
1298
1299         /* Check destination */
1300
1301         pid = parse_dest(dest);
1302         if (!procid_valid(&pid)) {
1303                 return False;
1304         }
1305
1306         /* Check command */
1307
1308         for (i = 0; msg_types[i].name; i++) {
1309                 if (strequal(command, msg_types[i].name))
1310                         return msg_types[i].fn(msg_ctx, pid,
1311                                                argc - 1, argv + 1);
1312         }
1313
1314         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1315
1316         return False;
1317 }
1318
1319 static void smbcontrol_help(poptContext pc,
1320                     enum poptCallbackReason preason,
1321                     struct poptOption * poption,
1322                     const char * parg,
1323                     void * pdata)
1324 {
1325         if (poption->shortName != '?') {
1326                 poptPrintUsage(pc, stdout, 0);
1327         } else {
1328                 usage(pc);
1329         }
1330
1331         exit(0);
1332 }
1333
1334 struct poptOption help_options[] = {
1335         { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1336           NULL, NULL },
1337         { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1338         { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1339         { NULL }
1340 } ;
1341
1342 /* Main program */
1343
1344 int main(int argc, const char **argv)
1345 {
1346         poptContext pc;
1347         int opt;
1348         struct tevent_context *evt_ctx;
1349         struct messaging_context *msg_ctx;
1350
1351         static struct poptOption long_options[] = {
1352                 /* POPT_AUTOHELP */
1353                 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1354                                         0, "Help options:", NULL },
1355                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
1356                   "Set timeout value in seconds", "TIMEOUT" },
1357
1358                 POPT_COMMON_SAMBA
1359                 POPT_TABLEEND
1360         };
1361         TALLOC_CTX *frame = talloc_stackframe();
1362         int ret = 0;
1363
1364         load_case_tables();
1365
1366         setup_logging(argv[0],True);
1367         
1368         /* Parse command line arguments using popt */
1369
1370         pc = poptGetContext(
1371                 "smbcontrol", argc, (const char **)argv, long_options, 0);
1372
1373         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1374                                "<parameters>");
1375
1376         if (argc == 1)
1377                 usage(pc);
1378
1379         while ((opt = poptGetNextOpt(pc)) != -1) {
1380                 switch(opt) {
1381                 case 't':       /* --timeout */
1382                         break;
1383                 default:
1384                         fprintf(stderr, "Invalid option\n");
1385                         poptPrintHelp(pc, stderr, 0);
1386                         break;
1387                 }
1388         }
1389
1390         /* We should now have the remaining command line arguments in
1391            argv.  The argc parameter should have been decremented to the
1392            correct value in the above switch statement. */
1393
1394         argv = (const char **)poptGetArgs(pc);
1395         argc = 0;
1396         if (argv != NULL) {
1397                 while (argv[argc] != NULL) {
1398                         argc++;
1399                 }
1400         }
1401
1402         if (argc <= 1)
1403                 usage(pc);
1404
1405         lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
1406
1407         /* Need to invert sense of return code -- samba
1408          * routines mostly return True==1 for success, but
1409          * shell needs 0. */ 
1410         
1411         if (!(evt_ctx = tevent_context_init(NULL)) ||
1412             !(msg_ctx = messaging_init(NULL, server_id_self(), evt_ctx))) {
1413                 fprintf(stderr, "could not init messaging context\n");
1414                 TALLOC_FREE(frame);
1415                 exit(1);
1416         }
1417         
1418         ret = !do_command(msg_ctx, argc, argv);
1419         TALLOC_FREE(frame);
1420         return ret;
1421 }