source: vendor/3.6.23/source3/utils/smbcontrol.c

Last change on this file was 860, checked in by Silvan Scherrer, 11 years ago

Samba 3.6: updated vendor to latest version

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