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