2 Unix SMB/CIFS implementation.
4 Send messages to other Samba daemons
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
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.
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.
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/>.
27 #include "system/filesys.h"
28 #include "lib/util/server_id.h"
29 #include "lib/cmdline/cmdline.h"
30 #include "librpc/gen_ndr/spoolss.h"
31 #include "nt_printing.h"
32 #include "printing/notify.h"
33 #include "libsmb/nmblib.h"
36 #include "../lib/util/pidfile.h"
38 #include "cmdline_contexts.h"
39 #include "lib/util/string_wrappers.h"
40 #include "lib/global_contexts.h"
42 #ifdef HAVE_LIBUNWIND_H
43 #include <libunwind.h>
46 #ifdef HAVE_LIBUNWIND_PTRACE_H
47 #include <libunwind-ptrace.h>
50 #ifdef HAVE_SYS_PTRACE_H
51 #include <sys/ptrace.h>
54 /* Default timeout value when waiting for replies (in seconds) */
56 #define DEFAULT_TIMEOUT 10
58 static int timeout
= DEFAULT_TIMEOUT
;
59 static int num_replies
; /* Used by message callback fns */
61 /* Send a message to a destination pid. Zero means broadcast smbd. */
63 static bool send_message(struct messaging_context
*msg_ctx
,
64 struct server_id pid
, int msg_type
,
65 const void *buf
, int len
)
67 if (procid_to_pid(&pid
) != 0)
68 return NT_STATUS_IS_OK(
69 messaging_send_buf(msg_ctx
, pid
, msg_type
,
70 (const uint8_t *)buf
, len
));
72 messaging_send_all(msg_ctx
, msg_type
, buf
, len
);
77 static void smbcontrol_timeout(struct tevent_context
*event_ctx
,
78 struct tevent_timer
*te
,
82 bool *timed_out
= (bool *)private_data
;
87 /* Wait for one or more reply messages */
89 static void wait_replies(struct tevent_context
*ev_ctx
,
90 struct messaging_context
*msg_ctx
,
91 bool multiple_replies
)
93 struct tevent_timer
*te
;
94 bool timed_out
= False
;
96 te
= tevent_add_timer(ev_ctx
, NULL
,
97 timeval_current_ofs(timeout
, 0),
98 smbcontrol_timeout
, (void *)&timed_out
);
100 DEBUG(0, ("tevent_add_timer failed\n"));
106 if (num_replies
> 0 && !multiple_replies
)
108 ret
= tevent_loop_once(ev_ctx
);
115 /* Message handler callback that displays the PID and a string on stdout */
117 static void print_pid_string_cb(struct messaging_context
*msg
,
120 struct server_id pid
,
123 struct server_id_buf pidstr
;
125 printf("PID %s: %.*s", server_id_str_buf(pid
, &pidstr
),
126 (int)data
->length
, (const char *)data
->data
);
130 /* Send no message. Useful for testing. */
132 static bool do_noop(struct tevent_context
*ev_ctx
,
133 struct messaging_context
*msg_ctx
,
134 const struct server_id pid
,
135 const int argc
, const char **argv
)
138 fprintf(stderr
, "Usage: smbcontrol <dest> noop\n");
142 /* Move along, nothing to see here */
147 /* Send a debug string */
149 static bool do_debug(struct tevent_context
*ev_ctx
,
150 struct messaging_context
*msg_ctx
,
151 const struct server_id pid
,
152 const int argc
, const char **argv
)
155 fprintf(stderr
, "Usage: smbcontrol <dest> debug "
160 return send_message(msg_ctx
, pid
, MSG_DEBUG
, argv
[1],
161 strlen(argv
[1]) + 1);
165 static bool do_idmap(struct tevent_context
*ev
,
166 struct messaging_context
*msg_ctx
,
167 const struct server_id pid
,
168 const int argc
, const char **argv
)
170 static const char* usage
= "Usage: "
171 "smbcontrol <dest> idmap <cmd> [arg]\n"
173 "\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
174 "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
175 const char* arg
= NULL
;
184 arglen
= strlen(arg
) + 1;
187 fprintf(stderr
, "%s", usage
);
191 if (strcmp(argv
[1], "delete") == 0) {
192 msg_type
= ID_CACHE_DELETE
;
194 else if (strcmp(argv
[1], "kill") == 0) {
195 msg_type
= ID_CACHE_KILL
;
197 else if (strcmp(argv
[1], "help") == 0) {
198 fprintf(stdout
, "%s", usage
);
202 fprintf(stderr
, "%s", usage
);
206 return send_message(msg_ctx
, pid
, msg_type
, arg
, arglen
);
210 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
212 /* Return the name of a process given it's PID. This will only work on Linux,
213 * but that's probably moot since this whole stack tracing implementation is
214 * Linux-specific anyway.
216 static const char * procname(pid_t pid
, char * buf
, size_t bufsz
)
221 snprintf(path
, sizeof(path
), "/proc/%llu/cmdline",
222 (unsigned long long)pid
);
223 if ((fp
= fopen(path
, "r")) == NULL
) {
227 fgets(buf
, bufsz
, fp
);
233 static void print_stack_trace(pid_t pid
, int * count
)
236 unw_addr_space_t aspace
= NULL
;
245 if (ptrace(PTRACE_ATTACH
, pid
, NULL
, NULL
) < 0) {
247 "Failed to attach to process %llu: %s\n",
248 (unsigned long long)pid
, strerror(errno
));
252 /* Wait until the attach is complete. */
253 waitpid(pid
, NULL
, 0);
255 if (((pinfo
= _UPT_create(pid
)) == NULL
) ||
256 ((aspace
= unw_create_addr_space(&_UPT_accessors
, 0)) == NULL
)) {
257 /* Probably out of memory. */
259 "Unable to initialize stack unwind for process %llu\n",
260 (unsigned long long)pid
);
264 if ((ret
= unw_init_remote(&cursor
, aspace
, pinfo
))) {
266 "Unable to unwind stack for process %llu: %s\n",
267 (unsigned long long)pid
, unw_strerror(ret
));
275 if (procname(pid
, nbuf
, sizeof(nbuf
))) {
276 printf("Stack trace for process %llu (%s):\n",
277 (unsigned long long)pid
, nbuf
);
279 printf("Stack trace for process %llu:\n",
280 (unsigned long long)pid
);
283 while (unw_step(&cursor
) > 0) {
285 unw_get_reg(&cursor
, UNW_REG_IP
, &ip
);
286 unw_get_reg(&cursor
, UNW_REG_SP
, &sp
);
288 ret
= unw_get_proc_name(&cursor
, nbuf
, sizeof(nbuf
), &off
);
289 if (ret
!= 0 && ret
!= -UNW_ENOMEM
) {
290 snprintf(nbuf
, sizeof(nbuf
), "<unknown symbol>");
292 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
293 nbuf
, (long long)off
, (long long)ip
,
301 unw_destroy_addr_space(aspace
);
308 ptrace(PTRACE_DETACH
, pid
, NULL
, NULL
);
311 static int stack_trace_server(pid_t pid
, void *priv
)
313 print_stack_trace(pid
, (int *)priv
);
317 static bool do_daemon_stack_trace(struct tevent_context
*ev_ctx
,
318 struct messaging_context
*msg_ctx
,
319 const struct server_id pid
,
320 const int argc
, const char **argv
)
326 fprintf(stderr
, "Usage: smbcontrol <dest> stacktrace\n");
330 dest
= procid_to_pid(&pid
);
333 /* It would be nice to be able to make sure that this PID is
334 * the PID of a smbd/winbind/nmbd process, not some random PID
335 * the user liked the look of. It doesn't seem like it's worth
336 * the effort at the moment, however.
338 print_stack_trace(dest
, &count
);
340 messaging_dgm_forall(stack_trace_server
, &count
);
346 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
348 static bool do_daemon_stack_trace(struct tevent_context
*ev_ctx
,
349 struct messaging_context
*msg_ctx
,
350 const struct server_id pid
,
351 const int argc
, const char **argv
)
354 "Daemon stack tracing is not supported on this platform\n");
358 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
360 /* Inject a fault (fatal signal) into a running smbd */
362 static bool do_inject_fault(struct tevent_context
*ev_ctx
,
363 struct messaging_context
*msg_ctx
,
364 const struct server_id pid
,
365 const int argc
, const char **argv
)
368 fprintf(stderr
, "Usage: smbcontrol <dest> inject "
369 "<bus|hup|term|internal|segv>\n");
373 #if !defined(DEVELOPER) && !defined(ENABLE_SELFTEST)
374 fprintf(stderr
, "Fault injection is only available in "
375 "developer and self test builds\n");
377 #else /* DEVELOPER || ENABLE_SELFTEST */
381 if (strcmp(argv
[1], "bus") == 0) {
383 } else if (strcmp(argv
[1], "hup") == 0) {
385 } else if (strcmp(argv
[1], "term") == 0) {
387 } else if (strcmp(argv
[1], "segv") == 0) {
389 } else if (strcmp(argv
[1], "internal") == 0) {
390 /* Force an internal error, ie. an unclean exit. */
393 fprintf(stderr
, "Unknown signal name '%s'\n", argv
[1]);
397 return send_message(msg_ctx
, pid
, MSG_SMB_INJECT_FAULT
,
400 #endif /* DEVELOPER || ENABLE_SELFTEST */
403 static bool do_sleep(struct tevent_context
*ev_ctx
,
404 struct messaging_context
*msg_ctx
,
405 const struct server_id pid
,
406 const int argc
, const char **argv
)
408 #if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
409 unsigned int seconds
;
411 const long MAX_SLEEP
= 60 * 60; /* One hour maximum sleep */
415 fprintf(stderr
, "Usage: smbcontrol <dest> sleep seconds\n");
419 #if !defined(DEVELOPER) && !defined(ENABLE_SELFTEST)
420 fprintf(stderr
, "Sleep is only available in "
421 "developer and self test builds\n");
423 #else /* DEVELOPER || ENABLE_SELFTEST */
425 input
= atol(argv
[1]);
426 if (input
< 1 || input
> MAX_SLEEP
) {
428 "Invalid duration for sleep '%s'\n"
429 "It should be at least 1 second and no more than %ld\n",
435 return send_message(msg_ctx
, pid
,
438 sizeof(unsigned int));
439 #endif /* DEVELOPER || ENABLE_SELFTEST */
442 /* Force a browser election */
444 static bool do_election(struct tevent_context
*ev_ctx
,
445 struct messaging_context
*msg_ctx
,
446 const struct server_id pid
,
447 const int argc
, const char **argv
)
450 fprintf(stderr
, "Usage: smbcontrol <dest> force-election\n");
454 return send_message(msg_ctx
, pid
, MSG_FORCE_ELECTION
, NULL
, 0);
457 /* Ping a samba daemon process */
459 static void pong_cb(struct messaging_context
*msg
,
462 struct server_id pid
,
465 struct server_id_buf src_string
;
466 printf("PONG from pid %s\n", server_id_str_buf(pid
, &src_string
));
470 static bool do_ping(struct tevent_context
*ev_ctx
,
471 struct messaging_context
*msg_ctx
,
472 const struct server_id pid
,
473 const int argc
, const char **argv
)
476 fprintf(stderr
, "Usage: smbcontrol <dest> ping\n");
480 /* Send a message and register our interest in a reply */
482 if (!send_message(msg_ctx
, pid
, MSG_PING
, NULL
, 0))
485 messaging_register(msg_ctx
, NULL
, MSG_PONG
, pong_cb
);
487 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
489 /* No replies were received within the timeout period */
491 if (num_replies
== 0)
492 printf("No replies received\n");
494 messaging_deregister(msg_ctx
, MSG_PONG
, NULL
);
499 /* Set profiling options */
501 static bool do_profile(struct tevent_context
*ev_ctx
,
502 struct messaging_context
*msg_ctx
,
503 const struct server_id pid
,
504 const int argc
, const char **argv
)
509 fprintf(stderr
, "Usage: smbcontrol <dest> profile "
510 "<off|count|on|flush>\n");
514 if (strcmp(argv
[1], "off") == 0) {
516 } else if (strcmp(argv
[1], "count") == 0) {
518 } else if (strcmp(argv
[1], "on") == 0) {
520 } else if (strcmp(argv
[1], "flush") == 0) {
523 fprintf(stderr
, "Unknown profile command '%s'\n", argv
[1]);
527 return send_message(msg_ctx
, pid
, MSG_PROFILE
, &v
, sizeof(int));
530 /* Return the profiling level */
532 static void profilelevel_cb(struct messaging_context
*msg_ctx
,
535 struct server_id pid
,
543 if (data
->length
!= sizeof(int)) {
544 fprintf(stderr
, "invalid message length %ld returned\n",
545 (unsigned long)data
->length
);
549 memcpy(&level
, data
->data
, sizeof(int));
562 s
= "count and time";
569 printf("Profiling %s on pid %u\n",s
,(unsigned int)procid_to_pid(&pid
));
572 static void profilelevel_rqst(struct messaging_context
*msg_ctx
,
575 struct server_id pid
,
580 /* Send back a dummy reply */
582 send_message(msg_ctx
, pid
, MSG_PROFILELEVEL
, &v
, sizeof(int));
585 static bool do_profilelevel(struct tevent_context
*ev_ctx
,
586 struct messaging_context
*msg_ctx
,
587 const struct server_id pid
,
588 const int argc
, const char **argv
)
591 fprintf(stderr
, "Usage: smbcontrol <dest> profilelevel\n");
595 /* Send a message and register our interest in a reply */
597 if (!send_message(msg_ctx
, pid
, MSG_REQ_PROFILELEVEL
, NULL
, 0))
600 messaging_register(msg_ctx
, NULL
, MSG_PROFILELEVEL
, profilelevel_cb
);
601 messaging_register(msg_ctx
, NULL
, MSG_REQ_PROFILELEVEL
,
604 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
606 /* No replies were received within the timeout period */
608 if (num_replies
== 0)
609 printf("No replies received\n");
611 messaging_deregister(msg_ctx
, MSG_PROFILE
, NULL
);
616 /* Display debug level settings */
618 static bool do_debuglevel(struct tevent_context
*ev_ctx
,
619 struct messaging_context
*msg_ctx
,
620 const struct server_id pid
,
621 const int argc
, const char **argv
)
624 fprintf(stderr
, "Usage: smbcontrol <dest> debuglevel\n");
628 /* Send a message and register our interest in a reply */
630 if (!send_message(msg_ctx
, pid
, MSG_REQ_DEBUGLEVEL
, NULL
, 0))
633 messaging_register(msg_ctx
, NULL
, MSG_DEBUGLEVEL
, print_pid_string_cb
);
635 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
637 /* No replies were received within the timeout period */
639 if (num_replies
== 0)
640 printf("No replies received\n");
642 messaging_deregister(msg_ctx
, MSG_DEBUGLEVEL
, NULL
);
647 /* Send a print notify message */
649 static bool do_printnotify(struct tevent_context
*ev_ctx
,
650 struct messaging_context
*msg_ctx
,
651 const struct server_id pid
,
652 const int argc
, const char **argv
)
656 /* Check for subcommand */
659 fprintf(stderr
, "Must specify subcommand:\n");
660 fprintf(stderr
, "\tqueuepause <printername>\n");
661 fprintf(stderr
, "\tqueueresume <printername>\n");
662 fprintf(stderr
, "\tjobpause <printername> <unix jobid>\n");
663 fprintf(stderr
, "\tjobresume <printername> <unix jobid>\n");
664 fprintf(stderr
, "\tjobdelete <printername> <unix jobid>\n");
665 fprintf(stderr
, "\tprinter <printername> <comment|port|"
666 "driver> <value>\n");
673 if (strcmp(cmd
, "queuepause") == 0) {
676 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify"
677 " queuepause <printername>\n");
681 notify_printer_status_byname(ev_ctx
, msg_ctx
, argv
[2],
682 PRINTER_STATUS_PAUSED
);
686 } else if (strcmp(cmd
, "queueresume") == 0) {
689 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify"
690 " queuereume <printername>\n");
694 notify_printer_status_byname(ev_ctx
, msg_ctx
, argv
[2],
699 } else if (strcmp(cmd
, "jobpause") == 0) {
703 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify"
704 " jobpause <printername> <unix-jobid>\n");
708 jobid
= atoi(argv
[3]);
710 notify_job_status_byname(
712 argv
[2], jobid
, JOB_STATUS_PAUSED
,
713 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
717 } else if (strcmp(cmd
, "jobresume") == 0) {
721 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify"
722 " jobpause <printername> <unix-jobid>\n");
726 jobid
= atoi(argv
[3]);
728 notify_job_status_byname(
730 argv
[2], jobid
, JOB_STATUS_QUEUED
,
731 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
735 } else if (strcmp(cmd
, "jobdelete") == 0) {
739 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify"
740 " jobpause <printername> <unix-jobid>\n");
744 jobid
= atoi(argv
[3]);
746 notify_job_status_byname(
748 argv
[2], jobid
, JOB_STATUS_DELETING
,
749 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
751 notify_job_status_byname(
753 argv
[2], jobid
, JOB_STATUS_DELETING
|
755 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
759 } else if (strcmp(cmd
, "printer") == 0) {
763 fprintf(stderr
, "Usage: smbcontrol <dest> printnotify "
764 "printer <printername> <comment|port|driver> "
769 if (strcmp(argv
[3], "comment") == 0) {
770 attribute
= PRINTER_NOTIFY_FIELD_COMMENT
;
771 } else if (strcmp(argv
[3], "port") == 0) {
772 attribute
= PRINTER_NOTIFY_FIELD_PORT_NAME
;
773 } else if (strcmp(argv
[3], "driver") == 0) {
774 attribute
= PRINTER_NOTIFY_FIELD_DRIVER_NAME
;
776 fprintf(stderr
, "Invalid printer command '%s'\n",
781 notify_printer_byname(ev_ctx
, msg_ctx
, argv
[2], attribute
,
782 discard_const_p(char, argv
[4]));
787 fprintf(stderr
, "Invalid subcommand '%s'\n", cmd
);
791 print_notify_send_messages(msg_ctx
, 0);
797 static bool do_closeshare(struct tevent_context
*ev_ctx
,
798 struct messaging_context
*msg_ctx
,
799 const struct server_id pid
,
800 const int argc
, const char **argv
)
803 fprintf(stderr
, "Usage: smbcontrol <dest> close-share "
808 return send_message(msg_ctx
, pid
, MSG_SMB_FORCE_TDIS
, argv
[1],
809 strlen(argv
[1]) + 1);
813 * Close a share if access denied by now
816 static bool do_close_denied_share(
817 struct tevent_context
*ev_ctx
,
818 struct messaging_context
*msg_ctx
,
819 const struct server_id pid
,
820 const int argc
, const char **argv
)
823 fprintf(stderr
, "Usage: smbcontrol <dest> close-denied-share "
831 MSG_SMB_FORCE_TDIS_DENIED
,
833 strlen(argv
[1]) + 1);
836 /* Kill a client by IP address */
837 static bool do_kill_client_by_ip(struct tevent_context
*ev_ctx
,
838 struct messaging_context
*msg_ctx
,
839 const struct server_id pid
,
840 const int argc
, const char **argv
)
843 fprintf(stderr
, "Usage: smbcontrol <dest> kill-client-ip "
848 if (!is_ipaddress_v4(argv
[1]) && !is_ipaddress_v6(argv
[1])) {
849 fprintf(stderr
, "%s is not a valid IP address!\n", argv
[1]);
853 return send_message(msg_ctx
, pid
, MSG_SMB_KILL_CLIENT_IP
,
854 argv
[1], strlen(argv
[1]) + 1);
857 /* Tell winbindd an IP got dropped */
859 static bool do_ip_dropped(struct tevent_context
*ev_ctx
,
860 struct messaging_context
*msg_ctx
,
861 const struct server_id pid
,
862 const int argc
, const char **argv
)
865 fprintf(stderr
, "Usage: smbcontrol <dest> ip-dropped "
870 return send_message(msg_ctx
, pid
, MSG_WINBIND_IP_DROPPED
, argv
[1],
871 strlen(argv
[1]) + 1);
874 /* Display talloc pool usage */
876 static bool do_poolusage(struct tevent_context
*ev_ctx
,
877 struct messaging_context
*msg_ctx
,
878 const struct server_id dst
,
879 const int argc
, const char **argv
)
881 pid_t pid
= procid_to_pid(&dst
);
885 fprintf(stderr
, "Usage: smbcontrol <dest> pool-usage\n");
890 fprintf(stderr
, "Can only send to a specific PID\n");
906 static bool do_rpc_dump_status(
907 struct tevent_context
*ev_ctx
,
908 struct messaging_context
*msg_ctx
,
909 const struct server_id dst
,
913 pid_t pid
= procid_to_pid(&dst
);
918 "Usage: smbcontrol <dest> rpc-dump-status\n");
923 fprintf(stderr
, "Can only send to a specific PID\n");
939 /* Fetch and print the ringbuf log */
941 static void print_ringbuf_log_cb(struct messaging_context
*msg
,
944 struct server_id pid
,
947 printf("%s", (const char *)data
->data
);
951 static bool do_ringbuflog(struct tevent_context
*ev_ctx
,
952 struct messaging_context
*msg_ctx
,
953 const struct server_id pid
,
954 const int argc
, const char **argv
)
957 fprintf(stderr
, "Usage: smbcontrol <dest> ringbuf-log\n");
961 messaging_register(msg_ctx
, NULL
, MSG_RINGBUF_LOG
,
962 print_ringbuf_log_cb
);
964 /* Send a message and register our interest in a reply */
966 if (!send_message(msg_ctx
, pid
, MSG_REQ_RINGBUF_LOG
, NULL
, 0)) {
970 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
972 /* No replies were received within the timeout period */
974 if (num_replies
== 0) {
975 printf("No replies received\n");
978 messaging_deregister(msg_ctx
, MSG_RINGBUF_LOG
, NULL
);
980 return num_replies
!= 0;
983 /* Perform a dmalloc mark */
985 static bool do_dmalloc_mark(struct tevent_context
*ev_ctx
,
986 struct messaging_context
*msg_ctx
,
987 const struct server_id pid
,
988 const int argc
, const char **argv
)
991 fprintf(stderr
, "Usage: smbcontrol <dest> dmalloc-mark\n");
995 return send_message(msg_ctx
, pid
, MSG_REQ_DMALLOC_MARK
, NULL
, 0);
998 /* Perform a dmalloc changed */
1000 static bool do_dmalloc_changed(struct tevent_context
*ev_ctx
,
1001 struct messaging_context
*msg_ctx
,
1002 const struct server_id pid
,
1003 const int argc
, const char **argv
)
1006 fprintf(stderr
, "Usage: smbcontrol <dest> "
1007 "dmalloc-log-changed\n");
1011 return send_message(msg_ctx
, pid
, MSG_REQ_DMALLOC_LOG_CHANGED
,
1015 static void print_uint32_cb(struct messaging_context
*msg
, void *private_data
,
1016 uint32_t msg_type
, struct server_id pid
,
1019 uint32_t num_children
;
1021 if (data
->length
!= sizeof(uint32_t)) {
1022 printf("Invalid response: %d bytes long\n",
1026 num_children
= IVAL(data
->data
, 0);
1027 printf("%u children\n", (unsigned)num_children
);
1032 static bool do_num_children(struct tevent_context
*ev_ctx
,
1033 struct messaging_context
*msg_ctx
,
1034 const struct server_id pid
,
1035 const int argc
, const char **argv
)
1038 fprintf(stderr
, "Usage: smbcontrol <dest> num-children\n");
1042 messaging_register(msg_ctx
, NULL
, MSG_SMB_NUM_CHILDREN
,
1045 /* Send a message and register our interest in a reply */
1047 if (!send_message(msg_ctx
, pid
, MSG_SMB_TELL_NUM_CHILDREN
, NULL
, 0))
1050 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
1052 /* No replies were received within the timeout period */
1054 if (num_replies
== 0)
1055 printf("No replies received\n");
1057 messaging_deregister(msg_ctx
, MSG_SMB_NUM_CHILDREN
, NULL
);
1062 static bool do_msg_cleanup(struct tevent_context
*ev_ctx
,
1063 struct messaging_context
*msg_ctx
,
1064 const struct server_id pid
,
1065 const int argc
, const char **argv
)
1069 ret
= messaging_cleanup(msg_ctx
, pid
.pid
);
1071 printf("cleanup(%u) returned %s\n", (unsigned)pid
.pid
,
1072 ret
? strerror(ret
) : "ok");
1077 /* Shutdown a server process */
1079 static bool do_shutdown(struct tevent_context
*ev_ctx
,
1080 struct messaging_context
*msg_ctx
,
1081 const struct server_id pid
,
1082 const int argc
, const char **argv
)
1085 fprintf(stderr
, "Usage: smbcontrol <dest> shutdown\n");
1089 return send_message(msg_ctx
, pid
, MSG_SHUTDOWN
, NULL
, 0);
1092 /* Notify a driver upgrade */
1094 static bool do_drvupgrade(struct tevent_context
*ev_ctx
,
1095 struct messaging_context
*msg_ctx
,
1096 const struct server_id pid
,
1097 const int argc
, const char **argv
)
1100 fprintf(stderr
, "Usage: smbcontrol <dest> drvupgrade "
1105 return send_message(msg_ctx
, pid
, MSG_PRINTER_DRVUPGRADE
, argv
[1],
1106 strlen(argv
[1]) + 1);
1109 static bool do_winbind_online(struct tevent_context
*ev_ctx
,
1110 struct messaging_context
*msg_ctx
,
1111 const struct server_id pid
,
1112 const int argc
, const char **argv
)
1118 fprintf(stderr
, "Usage: smbcontrol winbindd online\n");
1122 db_path
= state_path(talloc_tos(), "winbindd_cache.tdb");
1123 if (db_path
== NULL
) {
1127 /* Remove the entry in the winbindd_cache tdb to tell a later
1128 starting winbindd that we're online. */
1130 tdb
= tdb_open_log(db_path
, 0, TDB_DEFAULT
, O_RDWR
, 0600);
1132 fprintf(stderr
, "Cannot open the tdb %s for writing.\n",
1134 TALLOC_FREE(db_path
);
1138 TALLOC_FREE(db_path
);
1139 tdb_delete_bystring(tdb
, "WINBINDD_OFFLINE");
1142 return send_message(msg_ctx
, pid
, MSG_WINBIND_ONLINE
, NULL
, 0);
1145 static bool do_winbind_offline(struct tevent_context
*ev_ctx
,
1146 struct messaging_context
*msg_ctx
,
1147 const struct server_id pid
,
1148 const int argc
, const char **argv
)
1156 fprintf(stderr
, "Usage: smbcontrol winbindd offline\n");
1160 db_path
= state_path(talloc_tos(), "winbindd_cache.tdb");
1161 if (db_path
== NULL
) {
1165 /* Create an entry in the winbindd_cache tdb to tell a later
1166 starting winbindd that we're offline. We may actually create
1169 tdb
= tdb_open_log(db_path
,
1170 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
1171 TDB_DEFAULT
|TDB_INCOMPATIBLE_HASH
/* TDB_CLEAR_IF_FIRST */,
1172 O_RDWR
|O_CREAT
, 0600);
1175 fprintf(stderr
, "Cannot open the tdb %s for writing.\n",
1177 TALLOC_FREE(db_path
);
1180 TALLOC_FREE(db_path
);
1182 /* There's a potential race condition that if a child
1183 winbindd detects a domain is online at the same time
1184 we're trying to tell it to go offline that it might
1185 delete the record we add between us adding it and
1186 sending the message. Minimize this by retrying up to
1189 for (retry
= 0; retry
< 5; retry
++) {
1191 TDB_DATA d
= { .dptr
= buf
, .dsize
= sizeof(buf
) };
1193 SIVAL(buf
, 0, time(NULL
));
1195 tdb_store_bystring(tdb
, "WINBINDD_OFFLINE", d
, TDB_INSERT
);
1197 ret
= send_message(msg_ctx
, pid
, MSG_WINBIND_OFFLINE
,
1200 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1201 d
= tdb_fetch_bystring( tdb
, "WINBINDD_OFFLINE" );
1202 if (d
.dptr
!= NULL
&& d
.dsize
== 4) {
1208 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1215 static bool do_winbind_onlinestatus(struct tevent_context
*ev_ctx
,
1216 struct messaging_context
*msg_ctx
,
1217 const struct server_id pid
,
1218 const int argc
, const char **argv
)
1221 fprintf(stderr
, "Usage: smbcontrol winbindd onlinestatus\n");
1225 messaging_register(msg_ctx
, NULL
, MSG_WINBIND_ONLINESTATUS
,
1226 print_pid_string_cb
);
1228 if (!send_message(msg_ctx
, pid
, MSG_WINBIND_ONLINESTATUS
, NULL
, 0)) {
1232 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
1234 /* No replies were received within the timeout period */
1236 if (num_replies
== 0)
1237 printf("No replies received\n");
1239 messaging_deregister(msg_ctx
, MSG_WINBIND_ONLINESTATUS
, NULL
);
1244 static bool do_winbind_dump_domain_list(struct tevent_context
*ev_ctx
,
1245 struct messaging_context
*msg_ctx
,
1246 const struct server_id pid
,
1247 const int argc
, const char **argv
)
1249 const char *domain
= NULL
;
1252 if (argc
< 1 || argc
> 2) {
1253 fprintf(stderr
, "Usage: smbcontrol <dest> dump-domain-list "
1260 domain_len
= strlen(argv
[1]) + 1;
1263 messaging_register(msg_ctx
, NULL
, MSG_WINBIND_DUMP_DOMAIN_LIST
,
1264 print_pid_string_cb
);
1266 if (!send_message(msg_ctx
, pid
, MSG_WINBIND_DUMP_DOMAIN_LIST
,
1267 domain
, domain_len
))
1272 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
1274 /* No replies were received within the timeout period */
1276 if (num_replies
== 0) {
1277 printf("No replies received\n");
1280 messaging_deregister(msg_ctx
, MSG_WINBIND_DUMP_DOMAIN_LIST
, NULL
);
1285 static bool do_msg_disconnect_dc(struct tevent_context
*ev_ctx
,
1286 struct messaging_context
*msg_ctx
,
1287 const struct server_id pid
,
1288 const int argc
, const char **argv
)
1291 fprintf(stderr
, "Usage: smbcontrol <dest> disconnect-dc\n");
1295 return send_message(msg_ctx
, pid
, MSG_WINBIND_DISCONNECT_DC
, NULL
, 0);
1298 static void winbind_validate_cache_cb(struct messaging_context
*msg
,
1301 struct server_id pid
,
1304 struct server_id_buf src_string
;
1305 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1306 (*(data
->data
) == 0 ? "" : "NOT "),
1307 server_id_str_buf(pid
, &src_string
));
1311 static bool do_winbind_validate_cache(struct tevent_context
*ev_ctx
,
1312 struct messaging_context
*msg_ctx
,
1313 const struct server_id pid
,
1314 const int argc
, const char **argv
)
1316 struct server_id myid
;
1318 myid
= messaging_server_id(msg_ctx
);
1321 fprintf(stderr
, "Usage: smbcontrol winbindd validate-cache\n");
1325 messaging_register(msg_ctx
, NULL
, MSG_WINBIND_VALIDATE_CACHE
,
1326 winbind_validate_cache_cb
);
1328 if (!send_message(msg_ctx
, pid
, MSG_WINBIND_VALIDATE_CACHE
, &myid
,
1333 wait_replies(ev_ctx
, msg_ctx
, procid_to_pid(&pid
) == 0);
1335 if (num_replies
== 0) {
1336 printf("No replies received\n");
1339 messaging_deregister(msg_ctx
, MSG_WINBIND_VALIDATE_CACHE
, NULL
);
1344 static bool do_reload_config(struct tevent_context
*ev_ctx
,
1345 struct messaging_context
*msg_ctx
,
1346 const struct server_id pid
,
1347 const int argc
, const char **argv
)
1350 fprintf(stderr
, "Usage: smbcontrol <dest> reload-config\n");
1354 return send_message(msg_ctx
, pid
, MSG_SMB_CONF_UPDATED
, NULL
, 0);
1357 static bool do_reload_printers(struct tevent_context
*ev_ctx
,
1358 struct messaging_context
*msg_ctx
,
1359 const struct server_id pid
,
1360 const int argc
, const char **argv
)
1363 fprintf(stderr
, "Usage: smbcontrol <dest> reload-printers\n");
1367 return send_message(msg_ctx
, pid
, MSG_PRINTER_PCAP
, NULL
, 0);
1370 static void my_make_nmb_name( struct nmb_name
*n
, const char *name
, int type
)
1373 memset( (char *)n
, '\0', sizeof(struct nmb_name
) );
1374 fstrcpy(unix_name
, name
);
1375 (void)strupper_m(unix_name
);
1376 push_ascii(n
->name
, unix_name
, sizeof(n
->name
), STR_TERMINATE
);
1377 n
->name_type
= (unsigned int)type
& 0xFF;
1378 push_ascii(n
->scope
, lp_netbios_scope(), 64, STR_TERMINATE
);
1381 static bool do_nodestatus(struct tevent_context
*ev_ctx
,
1382 struct messaging_context
*msg_ctx
,
1383 const struct server_id pid
,
1384 const int argc
, const char **argv
)
1386 struct packet_struct p
;
1389 fprintf(stderr
, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1395 p
.ip
= interpret_addr2(argv
[1]);
1397 p
.packet_type
= NMB_PACKET
;
1399 p
.packet
.nmb
.header
.name_trn_id
= 10;
1400 p
.packet
.nmb
.header
.opcode
= 0;
1401 p
.packet
.nmb
.header
.response
= False
;
1402 p
.packet
.nmb
.header
.nm_flags
.bcast
= False
;
1403 p
.packet
.nmb
.header
.nm_flags
.recursion_available
= False
;
1404 p
.packet
.nmb
.header
.nm_flags
.recursion_desired
= False
;
1405 p
.packet
.nmb
.header
.nm_flags
.trunc
= False
;
1406 p
.packet
.nmb
.header
.nm_flags
.authoritative
= False
;
1407 p
.packet
.nmb
.header
.rcode
= 0;
1408 p
.packet
.nmb
.header
.qdcount
= 1;
1409 p
.packet
.nmb
.header
.ancount
= 0;
1410 p
.packet
.nmb
.header
.nscount
= 0;
1411 p
.packet
.nmb
.header
.arcount
= 0;
1412 my_make_nmb_name(&p
.packet
.nmb
.question
.question_name
, "*", 0x00);
1413 p
.packet
.nmb
.question
.question_type
= 0x21;
1414 p
.packet
.nmb
.question
.question_class
= 0x1;
1416 return send_message(msg_ctx
, pid
, MSG_SEND_PACKET
, &p
, sizeof(p
));
1419 static bool do_notify_cleanup(struct tevent_context
*ev_ctx
,
1420 struct messaging_context
*msg_ctx
,
1421 const struct server_id pid
,
1422 const int argc
, const char **argv
)
1425 fprintf(stderr
, "Usage: smbcontrol smbd notify-cleanup\n");
1428 return send_message(msg_ctx
, pid
, MSG_SMB_NOTIFY_CLEANUP
, NULL
, 0);
1431 /* A list of message type supported */
1433 static const struct {
1434 const char *name
; /* Option name */
1435 bool (*fn
)(struct tevent_context
*ev_ctx
,
1436 struct messaging_context
*msg_ctx
,
1437 const struct server_id pid
,
1438 const int argc
, const char **argv
);
1439 const char *help
; /* Short help text */
1444 .help
= "Set debuglevel",
1449 .help
= "Manipulate idmap cache",
1452 .name
= "force-election",
1454 .help
= "Force a browse election",
1459 .help
= "Elicit a response",
1468 .fn
= do_inject_fault
,
1469 .help
= "Inject a fatal signal into a running smbd"},
1471 .name
= "stacktrace",
1472 .fn
= do_daemon_stack_trace
,
1473 .help
= "Display a stack trace of a daemon",
1476 .name
= "profilelevel",
1477 .fn
= do_profilelevel
,
1481 .name
= "debuglevel",
1482 .fn
= do_debuglevel
,
1483 .help
= "Display current debuglevels",
1486 .name
= "printnotify",
1487 .fn
= do_printnotify
,
1488 .help
= "Send a print notify message",
1491 .name
= "close-share",
1492 .fn
= do_closeshare
,
1493 .help
= "Forcibly disconnect a share",
1496 .name
= "close-denied-share",
1497 .fn
= do_close_denied_share
,
1498 .help
= "Forcibly disconnect users from shares disallowed now",
1501 .name
= "kill-client-ip",
1502 .fn
= do_kill_client_by_ip
,
1503 .help
= "Forcibly disconnect a client with a specific IP address",
1506 .name
= "ip-dropped",
1507 .fn
= do_ip_dropped
,
1508 .help
= "Tell winbind that an IP got dropped",
1511 .name
= "pool-usage",
1513 .help
= "Display talloc memory usage",
1516 .name
= "rpc-dump-status",
1517 .fn
= do_rpc_dump_status
,
1518 .help
= "Display rpc status",
1521 .name
= "ringbuf-log",
1522 .fn
= do_ringbuflog
,
1523 .help
= "Display ringbuf log",
1526 .name
= "dmalloc-mark",
1527 .fn
= do_dmalloc_mark
,
1531 .name
= "dmalloc-log-changed",
1532 .fn
= do_dmalloc_changed
,
1538 .help
= "Shut down daemon",
1541 .name
= "drvupgrade",
1542 .fn
= do_drvupgrade
,
1543 .help
= "Notify a printer driver has changed",
1546 .name
= "reload-config",
1547 .fn
= do_reload_config
,
1548 .help
= "Force smbd or winbindd to reload config file"},
1550 .name
= "reload-printers",
1551 .fn
= do_reload_printers
,
1552 .help
= "Force smbd to reload printers"},
1554 .name
= "nodestatus",
1555 .fn
= do_nodestatus
,
1556 .help
= "Ask nmbd to do a node status request"},
1559 .fn
= do_winbind_online
,
1560 .help
= "Ask winbind to go into online state"},
1563 .fn
= do_winbind_offline
,
1564 .help
= "Ask winbind to go into offline state"},
1566 .name
= "onlinestatus",
1567 .fn
= do_winbind_onlinestatus
,
1568 .help
= "Request winbind online status"},
1570 .name
= "validate-cache" ,
1571 .fn
= do_winbind_validate_cache
,
1572 .help
= "Validate winbind's credential cache",
1575 .name
= "dump-domain-list",
1576 .fn
= do_winbind_dump_domain_list
,
1577 .help
= "Dump winbind domain list"},
1579 .name
= "disconnect-dc",
1580 .fn
= do_msg_disconnect_dc
,
1583 .name
= "notify-cleanup",
1584 .fn
= do_notify_cleanup
,
1587 .name
= "num-children",
1588 .fn
= do_num_children
,
1589 .help
= "Print number of smbd child processes",
1592 .name
= "msg-cleanup",
1593 .fn
= do_msg_cleanup
,
1598 .help
= "Do nothing",
1603 .help
= "Cause the target process to sleep",
1608 /* Display usage information */
1610 static void usage(poptContext pc
)
1614 poptPrintHelp(pc
, stderr
, 0);
1616 fprintf(stderr
, "\n");
1617 fprintf(stderr
, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1620 fprintf(stderr
, "\n");
1621 fprintf(stderr
, "<message-type> is one of:\n");
1623 for (i
= 0; msg_types
[i
].name
; i
++) {
1624 const char *help
= msg_types
[i
].help
;
1628 fprintf(stderr
, "\t%-30s%s\n", msg_types
[i
].name
, help
);
1631 fprintf(stderr
, "\n");
1636 /* Return the pid number for a string destination */
1638 static struct server_id
parse_dest(struct messaging_context
*msg
,
1641 struct server_id result
= {
1642 .pid
= (uint64_t)-1,
1646 /* Zero is a special return value for broadcast to all processes */
1648 if (strequal(dest
, "all")) {
1649 return interpret_pid(MSG_BROADCAST_PID_STR
);
1652 /* Try self - useful for testing */
1654 if (strequal(dest
, "self")) {
1655 return messaging_server_id(msg
);
1658 /* Fix winbind typo. */
1659 if (strequal(dest
, "winbind")) {
1663 /* Check for numeric pid number */
1664 result
= interpret_pid(dest
);
1666 /* Zero isn't valid if not "all". */
1667 if (result
.pid
&& procid_valid(&result
)) {
1671 /* Look up other destinations in pidfile directory */
1673 if ((pid
= pidfile_pid(lp_pid_directory(), dest
)) != 0) {
1674 return pid_to_procid(pid
);
1677 fprintf(stderr
,"Can't find pid for destination '%s'\n", dest
);
1682 /* Execute smbcontrol command */
1684 static bool do_command(struct tevent_context
*ev_ctx
,
1685 struct messaging_context
*msg_ctx
,
1686 int argc
, const char **argv
)
1688 const char *dest
= argv
[0], *command
= argv
[1];
1689 struct server_id pid
;
1692 /* Check destination */
1694 pid
= parse_dest(msg_ctx
, dest
);
1695 if (!procid_valid(&pid
)) {
1701 for (i
= 0; msg_types
[i
].name
; i
++) {
1702 if (strequal(command
, msg_types
[i
].name
))
1703 return msg_types
[i
].fn(ev_ctx
, msg_ctx
, pid
,
1704 argc
- 1, argv
+ 1);
1707 fprintf(stderr
, "smbcontrol: unknown command '%s'\n", command
);
1712 static void smbcontrol_help(poptContext pc
,
1713 enum poptCallbackReason preason
,
1714 struct poptOption
* poption
,
1718 if (poption
->shortName
!= '?') {
1719 poptPrintUsage(pc
, stdout
, 0);
1727 struct poptOption help_options
[] = {
1728 { NULL
, '\0', POPT_ARG_CALLBACK
, (void *)&smbcontrol_help
, '\0',
1730 { "help", '?', 0, NULL
, '?', "Show this help message", NULL
},
1731 { "usage", '\0', 0, NULL
, 'u', "Display brief usage message", NULL
},
1737 int main(int argc
, const char **argv
)
1741 struct tevent_context
*evt_ctx
;
1742 struct messaging_context
*msg_ctx
;
1744 struct poptOption long_options
[] = {
1746 { NULL
, '\0', POPT_ARG_INCLUDE_TABLE
, help_options
,
1747 0, "Help options:", NULL
},
1748 { "timeout", 't', POPT_ARG_INT
, &timeout
, 't',
1749 "Set timeout value in seconds", "TIMEOUT" },
1755 TALLOC_CTX
*frame
= talloc_stackframe();
1761 ok
= samba_cmdline_init(frame
,
1762 SAMBA_CMDLINE_CONFIG_CLIENT
,
1763 false /* require_smbconf */);
1765 DBG_ERR("Failed to init cmdline parser!\n");
1769 lp_set_cmdline("log level", "0");
1771 /* Parse command line arguments using popt */
1773 pc
= samba_popt_get_context(getprogname(),
1779 DBG_ERR("Failed to setup popt context!\n");
1784 poptSetOtherOptionHelp(pc
, "[OPTION...] <destination> <message-type> "
1790 while ((opt
= poptGetNextOpt(pc
)) != -1) {
1792 case 't': /* --timeout */
1795 fprintf(stderr
, "Invalid option\n");
1796 poptPrintHelp(pc
, stderr
, 0);
1801 /* We should now have the remaining command line arguments in
1802 argv. The argc parameter should have been decremented to the
1803 correct value in the above switch statement. */
1805 argv
= (const char **)poptGetArgs(pc
);
1808 while (argv
[argc
] != NULL
) {
1816 msg_ctx
= cmdline_messaging_context(get_dyn_CONFIGFILE());
1817 if (msg_ctx
== NULL
) {
1819 "Could not init messaging context, not root?\n");
1824 evt_ctx
= global_event_context();
1826 /* Need to invert sense of return code -- samba
1827 * routines mostly return True==1 for success, but
1830 ret
= !do_command(evt_ctx
, msg_ctx
, argc
, argv
);
1832 cmdline_messaging_context_free();
1833 poptFreeContext(pc
);