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 2 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, write to the Free Software
24   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25*/
26
27#include "includes.h"
28
29#if HAVE_LIBUNWIND_H
30#include <libunwind.h>
31#endif
32
33#if HAVE_LIBUNWIND_PTRACE_H
34#include <libunwind-ptrace.h>
35#endif
36
37#if HAVE_SYS_PTRACE_H
38#include <sys/ptrace.h>
39#endif
40
41/* Default timeout value when waiting for replies (in seconds) */
42
43#define DEFAULT_TIMEOUT 10
44
45static int timeout = DEFAULT_TIMEOUT;
46static int num_replies;		/* Used by message callback fns */
47
48/* Send a message to a destination pid.  Zero means broadcast smbd. */
49
50static BOOL send_message(struct process_id pid, int msg_type,
51			 const void *buf, int len,
52			 BOOL duplicates)
53{
54	TDB_CONTEXT *tdb;
55	BOOL ret;
56	int n_sent = 0;
57
58	if (!message_init())
59		return False;
60
61	if (procid_to_pid(&pid) != 0)
62		return NT_STATUS_IS_OK(message_send_pid(pid, msg_type, buf, len,
63							duplicates));
64
65	tdb = tdb_open_log(lock_path("connections.tdb"), 0,
66			   TDB_DEFAULT, O_RDWR, 0);
67	if (!tdb) {
68		fprintf(stderr,"Failed to open connections database"
69			": %s\n", strerror(errno));
70		return False;
71	}
72
73	ret = message_send_all(tdb,msg_type, buf, len, duplicates,
74			       &n_sent);
75	DEBUG(10,("smbcontrol/send_message: broadcast message to "
76		  "%d processes\n", n_sent));
77
78	tdb_close(tdb);
79
80	return ret;
81}
82
83/* Wait for one or more reply messages */
84
85static void wait_replies(BOOL multiple_replies)
86{
87	time_t start_time = time(NULL);
88
89	/* Wait around a bit.  This is pretty disgusting - we have to
90           busy-wait here as there is no nicer way to do it. */
91
92	do {
93		message_dispatch();
94		if (num_replies > 0 && !multiple_replies)
95			break;
96		sleep(1);
97	} while (timeout - (time(NULL) - start_time) > 0);
98}
99
100/* Message handler callback that displays the PID and a string on stdout */
101
102static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf,
103				size_t len, void *private_data)
104{
105	printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
106	       (int)len, (const char *)buf);
107	num_replies++;
108}
109
110/* Message handler callback that displays a string on stdout */
111
112static void print_string_cb(int msg_type, struct process_id pid,
113			    void *buf, size_t len, void *private_data)
114{
115	printf("%.*s", (int)len, (const char *)buf);
116	num_replies++;
117}
118
119/* Send no message.  Useful for testing. */
120
121static BOOL do_noop(const struct process_id pid,
122		    const int argc, const char **argv)
123{
124	if (argc != 1) {
125		fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
126		return False;
127	}
128
129	/* Move along, nothing to see here */
130
131	return True;
132}
133
134/* Send a debug string */
135
136static BOOL do_debug(const struct process_id pid,
137		     const int argc, const char **argv)
138{
139	if (argc != 2) {
140		fprintf(stderr, "Usage: smbcontrol <dest> debug "
141			"<debug-string>\n");
142		return False;
143	}
144
145	return send_message(
146		pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
147}
148
149#if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
150
151/* Return the name of a process given it's PID. This will only work on Linux,
152 * but that's probably moot since this whole stack tracing implementatino is
153 * Linux-specific anyway.
154 */
155static const char * procname(pid_t pid, char * buf, size_t bufsz)
156{
157	char path[64];
158	FILE * fp;
159
160	snprintf(path, sizeof(path), "/proc/%llu/cmdline",
161		(unsigned long long)pid);
162	if ((fp = fopen(path, "r")) == NULL) {
163		return NULL;
164	}
165
166	fgets(buf, bufsz, fp);
167
168	fclose(fp);
169	return buf;
170}
171
172static void print_stack_trace(pid_t pid, int * count)
173{
174	void *		    pinfo = NULL;
175	unw_addr_space_t    aspace = NULL;
176	unw_cursor_t	    cursor;
177	unw_word_t	    ip, sp;
178
179	char		    nbuf[256];
180	unw_word_t	    off;
181
182	int ret;
183
184	if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
185		fprintf(stderr,
186			"Failed to attach to process %llu: %s\n",
187			(unsigned long long)pid, strerror(errno));
188		return;
189	}
190
191	/* Wait until the attach is complete. */
192	waitpid(pid, NULL, 0);
193
194	if (((pinfo = _UPT_create(pid)) == NULL) ||
195	    ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
196		/* Probably out of memory. */
197		fprintf(stderr,
198			"Unable to initialize stack unwind for process %llu\n",
199			(unsigned long long)pid);
200		goto cleanup;
201	}
202
203	if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
204		fprintf(stderr,
205			"Unable to unwind stack for process %llu: %s\n",
206			(unsigned long long)pid, unw_strerror(ret));
207		goto cleanup;
208	}
209
210	if (*count > 0) {
211		printf("\n");
212	}
213
214	if (procname(pid, nbuf, sizeof(nbuf))) {
215		printf("Stack trace for process %llu (%s):\n",
216			(unsigned long long)pid, nbuf);
217	} else {
218		printf("Stack trace for process %llu:\n",
219			(unsigned long long)pid);
220	}
221
222	while (unw_step(&cursor) > 0) {
223		ip = sp = off = 0;
224		unw_get_reg(&cursor, UNW_REG_IP, &ip);
225		unw_get_reg(&cursor, UNW_REG_SP, &sp);
226
227		ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
228		if (ret != 0 && ret != -UNW_ENOMEM) {
229			snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
230		}
231		printf("    %s + %#llx [ip=%#llx] [sp=%#llx]\n",
232			nbuf, (long long)off, (long long)ip,
233			(long long)sp);
234	}
235
236	(*count)++;
237
238cleanup:
239	if (aspace) {
240		unw_destroy_addr_space(aspace);
241	}
242
243	if (pinfo) {
244		_UPT_destroy(pinfo);
245	}
246
247	ptrace(PTRACE_DETACH, pid, NULL, NULL);
248}
249
250static int stack_trace_connection(TDB_CONTEXT * tdb, TDB_DATA key,
251	TDB_DATA data, void * priv)
252{
253	struct connections_data conn;
254
255	if (data.dsize != sizeof(conn))
256		return 0;
257
258	memcpy(&conn, data.dptr, sizeof(conn));
259	print_stack_trace(procid_to_pid(&conn.pid), (int *)priv);
260
261	return 0;
262}
263
264static BOOL do_daemon_stack_trace(const struct process_id pid,
265		       const int argc, const char **argv)
266{
267	fprintf(stderr,
268		"Daemon stack tracing is not supported on this platform\n");
269	return False;
270
271	pid_t	dest;
272	int	count = 0;
273
274	if (argc != 1) {
275		fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
276		return False;
277	}
278
279	dest = procid_to_pid(&pid);
280
281	if (dest != 0) {
282		/* It would be nice to be able to make sure that this PID is
283		 * the PID of a smbd/winbind/nmbd process, not some random PID
284		 * the user liked the look of. It doesn't seem like it's worth
285		 * the effort at the moment, however.
286		 */
287		print_stack_trace(dest, &count);
288	} else {
289		TDB_CONTEXT * tdb;
290
291		tdb = tdb_open_log(lock_path("connections.tdb"), 0,
292				   TDB_DEFAULT, O_RDONLY, 0);
293		if (!tdb) {
294			fprintf(stderr,
295				"Failed to open connections database: %s\n",
296				strerror(errno));
297			return False;
298		}
299
300		tdb_traverse(tdb, stack_trace_connection, &count);
301		tdb_close(tdb);
302	}
303
304	return True;
305}
306
307#else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
308
309static BOOL do_daemon_stack_trace(const struct process_id pid,
310		       const int argc, const char **argv)
311{
312	fprintf(stderr,
313		"Daemon stack tracing is not supported on this platform\n");
314	return False;
315}
316
317#endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
318
319/* Inject a fault (fatal signal) into a running smbd */
320
321static BOOL do_inject_fault(const struct process_id pid,
322		       const int argc, const char **argv)
323{
324	if (argc != 2) {
325		fprintf(stderr, "Usage: smbcontrol <dest> inject "
326			"<bus|hup|term|internal|segv>\n");
327		return False;
328	}
329
330#ifndef DEVELOPER
331	fprintf(stderr, "Fault injection is only available in "
332		"developer builds\n");
333	return False;
334#else /* DEVELOPER */
335	{
336		int sig = 0;
337
338		if (strcmp(argv[1], "bus") == 0) {
339			sig = SIGBUS;
340		} else if (strcmp(argv[1], "hup") == 0) {
341			sig = SIGHUP;
342		} else if (strcmp(argv[1], "term") == 0) {
343			sig = SIGTERM;
344		} else if (strcmp(argv[1], "segv") == 0) {
345			sig = SIGSEGV;
346		} else if (strcmp(argv[1], "internal") == 0) {
347			/* Force an internal error, ie. an unclean exit. */
348			sig = -1;
349		} else {
350			fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
351			return False;
352		}
353
354		return send_message(pid, MSG_SMB_INJECT_FAULT,
355				    &sig, sizeof(int), False);
356	}
357#endif /* DEVELOPER */
358}
359
360/* Force a browser election */
361
362static BOOL do_election(const struct process_id pid,
363			const int argc, const char **argv)
364{
365	if (argc != 1) {
366		fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
367		return False;
368	}
369
370	return send_message(
371		pid, MSG_FORCE_ELECTION, NULL, 0, False);
372}
373
374/* Ping a samba daemon process */
375
376static void pong_cb(int msg_type, struct process_id pid, void *buf,
377		    size_t len, void *private_data)
378{
379	char *src_string = procid_str(NULL, &pid);
380	printf("PONG from pid %s\n", src_string);
381	TALLOC_FREE(src_string);
382	num_replies++;
383}
384
385static BOOL do_ping(const struct process_id pid, 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(pid, MSG_PING, NULL, 0, False))
395		return False;
396
397	message_register(MSG_PONG, pong_cb, NULL);
398
399	wait_replies(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	message_deregister(MSG_PONG);
407
408	return num_replies;
409}
410
411/* Set profiling options */
412
413static BOOL do_profile(const struct process_id pid,
414		       const int argc, const char **argv)
415{
416	int v;
417
418	if (argc != 2) {
419		fprintf(stderr, "Usage: smbcontrol <dest> profile "
420			"<off|count|on|flush>\n");
421		return False;
422	}
423
424	if (strcmp(argv[1], "off") == 0) {
425		v = 0;
426	} else if (strcmp(argv[1], "count") == 0) {
427		v = 1;
428	} else if (strcmp(argv[1], "on") == 0) {
429		v = 2;
430	} else if (strcmp(argv[1], "flush") == 0) {
431		v = 3;
432	} else {
433		fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
434		return False;
435	}
436
437	return send_message(pid, MSG_PROFILE, &v, sizeof(int), False);
438}
439
440/* Return the profiling level */
441
442static void profilelevel_cb(int msg_type, struct process_id pid, void *buf,
443			    size_t len, void *private_data)
444{
445	int level;
446	const char *s;
447
448	num_replies++;
449
450	if (len != sizeof(int)) {
451		fprintf(stderr, "invalid message length %ld returned\n",
452			(unsigned long)len);
453		return;
454	}
455
456	memcpy(&level, buf, sizeof(int));
457
458	switch (level) {
459	case 0:
460		s = "not enabled";
461		break;
462	case 1:
463		s = "off";
464		break;
465	case 3:
466		s = "count only";
467		break;
468	case 7:
469		s = "count and time";
470		break;
471	default:
472		s = "BOGUS";
473		break;
474	}
475
476	printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
477}
478
479static void profilelevel_rqst(int msg_type, struct process_id pid,
480			      void *buf, size_t len, void *private_data)
481{
482	int v = 0;
483
484	/* Send back a dummy reply */
485
486	send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
487}
488
489static BOOL do_profilelevel(const struct process_id pid,
490			    const int argc, const char **argv)
491{
492	if (argc != 1) {
493		fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
494		return False;
495	}
496
497	/* Send a message and register our interest in a reply */
498
499	if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
500		return False;
501
502	message_register(MSG_PROFILELEVEL, profilelevel_cb, NULL);
503	message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst, NULL);
504
505	wait_replies(procid_to_pid(&pid) == 0);
506
507	/* No replies were received within the timeout period */
508
509	if (num_replies == 0)
510		printf("No replies received\n");
511
512	message_deregister(MSG_PROFILE);
513
514	return num_replies;
515}
516
517/* Display debug level settings */
518
519static BOOL do_debuglevel(const struct process_id pid,
520			  const int argc, const char **argv)
521{
522	if (argc != 1) {
523		fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
524		return False;
525	}
526
527	/* Send a message and register our interest in a reply */
528
529	if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
530		return False;
531
532	message_register(MSG_DEBUGLEVEL, print_pid_string_cb, NULL);
533
534	wait_replies(procid_to_pid(&pid) == 0);
535
536	/* No replies were received within the timeout period */
537
538	if (num_replies == 0)
539		printf("No replies received\n");
540
541	message_deregister(MSG_DEBUGLEVEL);
542
543	return num_replies;
544}
545
546/* Send a print notify message */
547
548static BOOL do_printnotify(const struct process_id pid,
549			   const int argc, const char **argv)
550{
551	const char *cmd;
552
553	/* Check for subcommand */
554
555	if (argc == 1) {
556		fprintf(stderr, "Must specify subcommand:\n");
557		fprintf(stderr, "\tqueuepause <printername>\n");
558		fprintf(stderr, "\tqueueresume <printername>\n");
559		fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
560		fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
561		fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
562		fprintf(stderr, "\tprinter <printername> <comment|port|"
563			"driver> <value>\n");
564
565		return False;
566	}
567
568	cmd = argv[1];
569
570	if (strcmp(cmd, "queuepause") == 0) {
571
572		if (argc != 3) {
573			fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
574				" queuepause <printername>\n");
575			return False;
576		}
577
578		notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
579
580		goto send;
581
582	} else if (strcmp(cmd, "queueresume") == 0) {
583
584		if (argc != 3) {
585			fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
586				" queuereume <printername>\n");
587			return False;
588		}
589
590		notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
591
592		goto send;
593
594	} else if (strcmp(cmd, "jobpause") == 0) {
595		int jobid;
596
597		if (argc != 4) {
598			fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
599				" jobpause <printername> <unix-jobid>\n");
600			return False;
601		}
602
603		jobid = atoi(argv[3]);
604
605		notify_job_status_byname(
606			argv[2], jobid, JOB_STATUS_PAUSED,
607			SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
608
609		goto send;
610
611	} else if (strcmp(cmd, "jobresume") == 0) {
612		int jobid;
613
614		if (argc != 4) {
615			fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
616				" jobpause <printername> <unix-jobid>\n");
617			return False;
618		}
619
620		jobid = atoi(argv[3]);
621
622		notify_job_status_byname(
623			argv[2], jobid, JOB_STATUS_QUEUED,
624			SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
625
626		goto send;
627
628	} else if (strcmp(cmd, "jobdelete") == 0) {
629		int jobid;
630
631		if (argc != 4) {
632			fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
633				" jobpause <printername> <unix-jobid>\n");
634			return False;
635		}
636
637		jobid = atoi(argv[3]);
638
639		notify_job_status_byname(
640			argv[2], jobid, JOB_STATUS_DELETING,
641			SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
642
643		notify_job_status_byname(
644			argv[2], jobid, JOB_STATUS_DELETING|
645			JOB_STATUS_DELETED,
646			SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
647
648		goto send;
649
650	} else if (strcmp(cmd, "printer") == 0) {
651		uint32 attribute;
652
653		if (argc != 5) {
654			fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
655				"printer <printername> <comment|port|driver> "
656				"<value>\n");
657			return False;
658		}
659
660		if (strcmp(argv[3], "comment") == 0) {
661			attribute = PRINTER_NOTIFY_COMMENT;
662		} else if (strcmp(argv[3], "port") == 0) {
663			attribute = PRINTER_NOTIFY_PORT_NAME;
664		} else if (strcmp(argv[3], "driver") == 0) {
665			attribute = PRINTER_NOTIFY_DRIVER_NAME;
666		} else {
667			fprintf(stderr, "Invalid printer command '%s'\n",
668				argv[3]);
669			return False;
670		}
671
672		notify_printer_byname(argv[2], attribute,
673				      CONST_DISCARD(char *, argv[4]));
674
675		goto send;
676	}
677
678	fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
679	return False;
680
681send:
682	print_notify_send_messages(0);
683	return True;
684}
685
686/* Close a share */
687
688static BOOL do_closeshare(const struct process_id pid,
689			  const int argc, const char **argv)
690{
691	if (argc != 2) {
692		fprintf(stderr, "Usage: smbcontrol <dest> close-share "
693			"<sharename>\n");
694		return False;
695	}
696
697	return send_message(
698		pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
699}
700
701/* Force a SAM synchronisation */
702
703static BOOL do_samsync(const struct process_id pid,
704		       const int argc, const char **argv)
705{
706	if (argc != 1) {
707		fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
708		return False;
709	}
710
711	return send_message(
712		pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
713}
714
715/* Force a SAM replication */
716
717static BOOL do_samrepl(const struct process_id pid,
718		       const int argc, const char **argv)
719{
720	if (argc != 1) {
721		fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
722		return False;
723	}
724
725	return send_message(
726		pid, MSG_SMB_SAM_REPL, NULL, 0, False);
727}
728
729/* Display talloc pool usage */
730
731static BOOL do_poolusage(const struct process_id pid,
732			 const int argc, const char **argv)
733{
734	if (argc != 1) {
735		fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
736		return False;
737	}
738
739	message_register(MSG_POOL_USAGE, print_string_cb, NULL);
740
741	/* Send a message and register our interest in a reply */
742
743	if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
744		return False;
745
746	wait_replies(procid_to_pid(&pid) == 0);
747
748	/* No replies were received within the timeout period */
749
750	if (num_replies == 0)
751		printf("No replies received\n");
752
753	message_deregister(MSG_POOL_USAGE);
754
755	return num_replies;
756}
757
758/* Perform a dmalloc mark */
759
760static BOOL do_dmalloc_mark(const struct process_id pid,
761			    const int argc, const char **argv)
762{
763	if (argc != 1) {
764		fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
765		return False;
766	}
767
768	return send_message(
769		pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
770}
771
772/* Perform a dmalloc changed */
773
774static BOOL do_dmalloc_changed(const struct process_id pid,
775			       const int argc, const char **argv)
776{
777	if (argc != 1) {
778		fprintf(stderr, "Usage: smbcontrol <dest> "
779			"dmalloc-log-changed\n");
780		return False;
781	}
782
783	return send_message(
784		pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
785}
786
787/* Shutdown a server process */
788
789static BOOL do_shutdown(const struct process_id pid,
790			const int argc, const char **argv)
791{
792	if (argc != 1) {
793		fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
794		return False;
795	}
796
797	return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
798}
799
800/* Notify a driver upgrade */
801
802static BOOL do_drvupgrade(const struct process_id pid,
803			  const int argc, const char **argv)
804{
805	if (argc != 2) {
806		fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
807			"<driver-name>\n");
808		return False;
809	}
810
811	return send_message(
812		pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
813}
814
815static BOOL do_winbind_online(const struct process_id pid,
816			     const int argc, const char **argv)
817{
818	TDB_CONTEXT *tdb;
819
820	if (argc != 1) {
821		fprintf(stderr, "Usage: smbcontrol winbindd online\n");
822		return False;
823	}
824
825	if (!lp_winbind_offline_logon()) {
826		fprintf(stderr, "The parameter \"winbind offline logon\" must "
827			"be set in the [global] section of smb.conf for this "
828			"command to be allowed.\n");
829		return False;
830	}
831
832	/* Remove the entry in the winbindd_cache tdb to tell a later
833	   starting winbindd that we're online. */
834
835	tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
836	if (!tdb) {
837		fprintf(stderr, "Cannot open the tdb %s for writing.\n",
838			lock_path("winbindd_cache.tdb"));
839		return False;
840	}
841
842	tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
843	tdb_close(tdb);
844
845	return send_message(pid, MSG_WINBIND_ONLINE, NULL, 0, False);
846}
847
848static BOOL do_winbind_offline(const struct process_id pid,
849			     const int argc, const char **argv)
850{
851	TDB_CONTEXT *tdb;
852	BOOL ret = False;
853	int retry = 0;
854
855	if (argc != 1) {
856		fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
857		return False;
858	}
859
860	if (!lp_winbind_offline_logon()) {
861		fprintf(stderr, "The parameter \"winbind offline logon\" must "
862			"be set in the [global] section of smb.conf for this "
863			"command to be allowed.\n");
864		return False;
865	}
866
867	/* Create an entry in the winbindd_cache tdb to tell a later
868	   starting winbindd that we're offline. We may actually create
869	   it here... */
870
871	tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
872				WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
873				TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
874
875	if (!tdb) {
876		fprintf(stderr, "Cannot open the tdb %s for writing.\n",
877			lock_path("winbindd_cache.tdb"));
878		return False;
879	}
880
881	/* There's a potential race condition that if a child
882	   winbindd detects a domain is online at the same time
883	   we're trying to tell it to go offline that it might
884	   delete the record we add between us adding it and
885	   sending the message. Minimize this by retrying up to
886	   5 times. */
887
888	for (retry = 0; retry < 5; retry++) {
889		TDB_DATA d;
890		char buf[4];
891
892		ZERO_STRUCT(d);
893
894		SIVAL(buf, 0, time(NULL));
895		d.dptr = buf;
896		d.dsize = 4;
897
898		tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
899
900		ret = send_message(pid, MSG_WINBIND_OFFLINE, NULL, 0, False);
901
902		/* Check that the entry "WINBINDD_OFFLINE" still exists. */
903		d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
904
905		if (!d.dptr || d.dsize != 4) {
906			SAFE_FREE(d.dptr);
907			DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
908		} else {
909			SAFE_FREE(d.dptr);
910			break;
911		}
912	}
913
914	tdb_close(tdb);
915	return ret;
916}
917
918static BOOL do_winbind_onlinestatus(const struct process_id pid,
919				    const int argc, const char **argv)
920{
921	struct process_id myid;
922
923	myid = pid_to_procid(sys_getpid());
924
925	if (argc != 1) {
926		fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
927		return False;
928	}
929
930	message_register(MSG_WINBIND_ONLINESTATUS, print_pid_string_cb, NULL);
931
932	if (!send_message(pid, MSG_WINBIND_ONLINESTATUS, &myid, sizeof(myid), False))
933		return False;
934
935	wait_replies(procid_to_pid(&pid) == 0);
936
937	/* No replies were received within the timeout period */
938
939	if (num_replies == 0)
940		printf("No replies received\n");
941
942	message_deregister(MSG_WINBIND_ONLINESTATUS);
943
944	return num_replies;
945}
946
947
948static BOOL do_reload_config(const struct process_id pid,
949			     const int argc, const char **argv)
950{
951	if (argc != 1) {
952		fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
953		return False;
954	}
955
956	return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
957}
958
959static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
960{
961	fstring unix_name;
962	memset( (char *)n, '\0', sizeof(struct nmb_name) );
963	fstrcpy(unix_name, name);
964	strupper_m(unix_name);
965	push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
966	n->name_type = (unsigned int)type & 0xFF;
967	push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
968}
969
970static BOOL do_nodestatus(const struct process_id pid,
971			  const int argc, const char **argv)
972{
973	struct packet_struct p;
974
975	if (argc != 2) {
976		fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
977		return False;
978	}
979
980	ZERO_STRUCT(p);
981
982	p.ip = *interpret_addr2(argv[1]);
983	p.port = 137;
984	p.packet_type = NMB_PACKET;
985
986	p.packet.nmb.header.name_trn_id = 10;
987	p.packet.nmb.header.opcode = 0;
988	p.packet.nmb.header.response = False;
989	p.packet.nmb.header.nm_flags.bcast = False;
990	p.packet.nmb.header.nm_flags.recursion_available = False;
991	p.packet.nmb.header.nm_flags.recursion_desired = False;
992	p.packet.nmb.header.nm_flags.trunc = False;
993	p.packet.nmb.header.nm_flags.authoritative = False;
994	p.packet.nmb.header.rcode = 0;
995	p.packet.nmb.header.qdcount = 1;
996	p.packet.nmb.header.ancount = 0;
997	p.packet.nmb.header.nscount = 0;
998	p.packet.nmb.header.arcount = 0;
999	my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1000	p.packet.nmb.question.question_type = 0x21;
1001	p.packet.nmb.question.question_class = 0x1;
1002
1003	return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
1004}
1005
1006/* A list of message type supported */
1007
1008static const struct {
1009	const char *name;	/* Option name */
1010	BOOL (*fn)(const struct process_id pid,
1011		   const int argc, const char **argv);
1012	const char *help;	/* Short help text */
1013} msg_types[] = {
1014	{ "debug", do_debug, "Set debuglevel"  },
1015	{ "force-election", do_election,
1016	  "Force a browse election" },
1017	{ "ping", do_ping, "Elicit a response" },
1018	{ "profile", do_profile, "" },
1019	{ "inject", do_inject_fault,
1020	    "Inject a fatal signal into a running smbd"},
1021	{ "stacktrace", do_daemon_stack_trace,
1022	    "Display a stack trace of a daemon" },
1023	{ "profilelevel", do_profilelevel, "" },
1024	{ "debuglevel", do_debuglevel, "Display current debuglevels" },
1025	{ "printnotify", do_printnotify, "Send a print notify message" },
1026	{ "close-share", do_closeshare, "Forcibly disconnect a share" },
1027        { "samsync", do_samsync, "Initiate SAM synchronisation" },
1028        { "samrepl", do_samrepl, "Initiate SAM replication" },
1029	{ "pool-usage", do_poolusage, "Display talloc memory usage" },
1030	{ "dmalloc-mark", do_dmalloc_mark, "" },
1031	{ "dmalloc-log-changed", do_dmalloc_changed, "" },
1032	{ "shutdown", do_shutdown, "Shut down daemon" },
1033	{ "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1034	{ "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1035	{ "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1036	{ "online", do_winbind_online, "Ask winbind to go into online state"},
1037	{ "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1038	{ "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1039	{ "noop", do_noop, "Do nothing" },
1040	{ NULL }
1041};
1042
1043/* Display usage information */
1044
1045static void usage(poptContext *pc)
1046{
1047	int i;
1048
1049	poptPrintHelp(*pc, stderr, 0);
1050
1051	fprintf(stderr, "\n");
1052	fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1053		"process ID\n");
1054
1055	fprintf(stderr, "\n");
1056	fprintf(stderr, "<message-type> is one of:\n");
1057
1058	for (i = 0; msg_types[i].name; i++)
1059	    fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1060		    msg_types[i].help);
1061
1062	fprintf(stderr, "\n");
1063
1064	exit(1);
1065}
1066
1067/* Return the pid number for a string destination */
1068
1069static struct process_id parse_dest(const char *dest)
1070{
1071	struct process_id result = {-1};
1072	pid_t pid;
1073
1074	/* Zero is a special return value for broadcast smbd */
1075
1076	if (strequal(dest, "smbd")) {
1077		return interpret_pid("0");
1078	}
1079
1080	/* Try self - useful for testing */
1081
1082	if (strequal(dest, "self")) {
1083		return pid_to_procid(sys_getpid());
1084	}
1085
1086	/* Fix winbind typo. */
1087	if (strequal(dest, "winbind")) {
1088		dest = "winbindd";
1089	}
1090
1091
1092	if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
1093		/* Check for numeric pid number */
1094
1095		result = interpret_pid(dest);
1096
1097		/* Zero isn't valid if not smbd. */
1098		if (result.pid && procid_valid(&result)) {
1099			return result;
1100		}
1101	}
1102
1103	/* Look up other destinations in pidfile directory */
1104
1105	if ((pid = pidfile_pid(dest)) != 0) {
1106		return pid_to_procid(pid);
1107	}
1108
1109	fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1110
1111	return result;
1112}
1113
1114/* Execute smbcontrol command */
1115
1116static BOOL do_command(int argc, const char **argv)
1117{
1118	const char *dest = argv[0], *command = argv[1];
1119	struct process_id pid;
1120	int i;
1121
1122	/* Check destination */
1123
1124	pid = parse_dest(dest);
1125	if (!procid_valid(&pid)) {
1126		return False;
1127	}
1128
1129	/* Check command */
1130
1131	for (i = 0; msg_types[i].name; i++) {
1132		if (strequal(command, msg_types[i].name))
1133			return msg_types[i].fn(pid, argc - 1, argv + 1);
1134	}
1135
1136	fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1137
1138	return False;
1139}
1140
1141/* Main program */
1142
1143int main(int argc, const char **argv)
1144{
1145	poptContext pc;
1146	int opt;
1147
1148	static struct poptOption long_options[] = {
1149		POPT_AUTOHELP
1150		{ "timeout", 't', POPT_ARG_INT, &timeout, 't',
1151		  "Set timeout value in seconds", "TIMEOUT" },
1152
1153		POPT_COMMON_SAMBA
1154		POPT_TABLEEND
1155	};
1156
1157	load_case_tables();
1158
1159	setup_logging(argv[0],True);
1160
1161	/* Parse command line arguments using popt */
1162
1163	pc = poptGetContext(
1164		"smbcontrol", argc, (const char **)argv, long_options, 0);
1165
1166	poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1167			       "<parameters>");
1168
1169	if (argc == 1)
1170		usage(&pc);
1171
1172	while ((opt = poptGetNextOpt(pc)) != -1) {
1173		switch(opt) {
1174		case 't':	/* --timeout */
1175			break;
1176		default:
1177			fprintf(stderr, "Invalid option\n");
1178			poptPrintHelp(pc, stderr, 0);
1179			break;
1180		}
1181	}
1182
1183	/* We should now have the remaining command line arguments in
1184           argv.  The argc parameter should have been decremented to the
1185           correct value in the above switch statement. */
1186
1187	argv = (const char **)poptGetArgs(pc);
1188	argc = 0;
1189	while (argv[argc] != NULL) {
1190		argc++;
1191	}
1192
1193	if (argc == 1)
1194		usage(&pc);
1195
1196	lp_load(dyn_CONFIGFILE,False,False,False,True);
1197
1198	/* Need to invert sense of return code -- samba
1199         * routines mostly return True==1 for success, but
1200         * shell needs 0. */
1201
1202	return !do_command(argc, argv);
1203}
1204