Line data Source code
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 "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"
34 : #include "messages.h"
35 : #include "util_tdb.h"
36 : #include "../lib/util/pidfile.h"
37 : #include "serverid.h"
38 : #include "cmdline_contexts.h"
39 : #include "lib/util/string_wrappers.h"
40 : #include "lib/global_contexts.h"
41 :
42 : #ifdef HAVE_LIBUNWIND_H
43 : #include <libunwind.h>
44 : #endif
45 :
46 : #ifdef HAVE_LIBUNWIND_PTRACE_H
47 : #include <libunwind-ptrace.h>
48 : #endif
49 :
50 : #ifdef HAVE_SYS_PTRACE_H
51 : #include <sys/ptrace.h>
52 : #endif
53 :
54 : /* Default timeout value when waiting for replies (in seconds) */
55 :
56 : #define DEFAULT_TIMEOUT 10
57 :
58 : static int timeout = DEFAULT_TIMEOUT;
59 : static int num_replies; /* Used by message callback fns */
60 :
61 : /* Send a message to a destination pid. Zero means broadcast smbd. */
62 :
63 102 : static bool send_message(struct messaging_context *msg_ctx,
64 : struct server_id pid, int msg_type,
65 : const void *buf, int len)
66 : {
67 102 : if (procid_to_pid(&pid) != 0)
68 102 : return NT_STATUS_IS_OK(
69 : messaging_send_buf(msg_ctx, pid, msg_type,
70 : (const uint8_t *)buf, len));
71 :
72 0 : messaging_send_all(msg_ctx, msg_type, buf, len);
73 :
74 0 : return true;
75 : }
76 :
77 1 : static void smbcontrol_timeout(struct tevent_context *event_ctx,
78 : struct tevent_timer *te,
79 : struct timeval now,
80 : void *private_data)
81 : {
82 1 : bool *timed_out = (bool *)private_data;
83 1 : TALLOC_FREE(te);
84 1 : *timed_out = True;
85 1 : }
86 :
87 : /* Wait for one or more reply messages */
88 :
89 86 : static void wait_replies(struct tevent_context *ev_ctx,
90 : struct messaging_context *msg_ctx,
91 : bool multiple_replies)
92 : {
93 : struct tevent_timer *te;
94 86 : bool timed_out = False;
95 :
96 86 : te = tevent_add_timer(ev_ctx, NULL,
97 : timeval_current_ofs(timeout, 0),
98 : smbcontrol_timeout, (void *)&timed_out);
99 86 : if (te == NULL) {
100 0 : DEBUG(0, ("tevent_add_timer failed\n"));
101 0 : return;
102 : }
103 :
104 232 : while (!timed_out) {
105 : int ret;
106 173 : if (num_replies > 0 && !multiple_replies)
107 85 : break;
108 88 : ret = tevent_loop_once(ev_ctx);
109 88 : if (ret != 0) {
110 0 : break;
111 : }
112 : }
113 : }
114 :
115 : /* Message handler callback that displays the PID and a string on stdout */
116 :
117 0 : static void print_pid_string_cb(struct messaging_context *msg,
118 : void *private_data,
119 : uint32_t msg_type,
120 : struct server_id pid,
121 : DATA_BLOB *data)
122 : {
123 : struct server_id_buf pidstr;
124 :
125 0 : printf("PID %s: %.*s", server_id_str_buf(pid, &pidstr),
126 0 : (int)data->length, (const char *)data->data);
127 0 : num_replies++;
128 0 : }
129 :
130 : /* Send no message. Useful for testing. */
131 :
132 0 : 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)
136 : {
137 0 : if (argc != 1) {
138 0 : fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
139 0 : return False;
140 : }
141 :
142 : /* Move along, nothing to see here */
143 :
144 0 : return True;
145 : }
146 :
147 : /* Send a debug string */
148 :
149 0 : 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)
153 : {
154 0 : if (argc != 2) {
155 0 : fprintf(stderr, "Usage: smbcontrol <dest> debug "
156 : "<debug-string>\n");
157 0 : return False;
158 : }
159 :
160 0 : return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
161 0 : strlen(argv[1]) + 1);
162 : }
163 :
164 :
165 0 : 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)
169 : {
170 : static const char* usage = "Usage: "
171 : "smbcontrol <dest> idmap <cmd> [arg]\n"
172 : "\tcmd:"
173 : "\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
174 : "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
175 0 : const char* arg = NULL;
176 0 : int arglen = 0;
177 : int msg_type;
178 :
179 0 : switch (argc) {
180 0 : case 2:
181 0 : break;
182 0 : case 3:
183 0 : arg = argv[2];
184 0 : arglen = strlen(arg) + 1;
185 0 : break;
186 0 : default:
187 0 : fprintf(stderr, "%s", usage);
188 0 : return false;
189 : }
190 :
191 0 : if (strcmp(argv[1], "delete") == 0) {
192 0 : msg_type = ID_CACHE_DELETE;
193 : }
194 0 : else if (strcmp(argv[1], "kill") == 0) {
195 0 : msg_type = ID_CACHE_KILL;
196 : }
197 0 : else if (strcmp(argv[1], "help") == 0) {
198 0 : fprintf(stdout, "%s", usage);
199 0 : return true;
200 : }
201 : else {
202 0 : fprintf(stderr, "%s", usage);
203 0 : return false;
204 : }
205 :
206 0 : return send_message(msg_ctx, pid, msg_type, arg, arglen);
207 : }
208 :
209 :
210 : #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
211 :
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.
215 : */
216 : static const char * procname(pid_t pid, char * buf, size_t bufsz)
217 : {
218 : char path[64];
219 : FILE * fp;
220 :
221 : snprintf(path, sizeof(path), "/proc/%llu/cmdline",
222 : (unsigned long long)pid);
223 : if ((fp = fopen(path, "r")) == NULL) {
224 : return NULL;
225 : }
226 :
227 : fgets(buf, bufsz, fp);
228 :
229 : fclose(fp);
230 : return buf;
231 : }
232 :
233 : static void print_stack_trace(pid_t pid, int * count)
234 : {
235 : void * pinfo = NULL;
236 : unw_addr_space_t aspace = NULL;
237 : unw_cursor_t cursor;
238 : unw_word_t ip, sp;
239 :
240 : char nbuf[256];
241 : unw_word_t off;
242 :
243 : int ret;
244 :
245 : if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
246 : fprintf(stderr,
247 : "Failed to attach to process %llu: %s\n",
248 : (unsigned long long)pid, strerror(errno));
249 : return;
250 : }
251 :
252 : /* Wait until the attach is complete. */
253 : waitpid(pid, NULL, 0);
254 :
255 : if (((pinfo = _UPT_create(pid)) == NULL) ||
256 : ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
257 : /* Probably out of memory. */
258 : fprintf(stderr,
259 : "Unable to initialize stack unwind for process %llu\n",
260 : (unsigned long long)pid);
261 : goto cleanup;
262 : }
263 :
264 : if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
265 : fprintf(stderr,
266 : "Unable to unwind stack for process %llu: %s\n",
267 : (unsigned long long)pid, unw_strerror(ret));
268 : goto cleanup;
269 : }
270 :
271 : if (*count > 0) {
272 : printf("\n");
273 : }
274 :
275 : if (procname(pid, nbuf, sizeof(nbuf))) {
276 : printf("Stack trace for process %llu (%s):\n",
277 : (unsigned long long)pid, nbuf);
278 : } else {
279 : printf("Stack trace for process %llu:\n",
280 : (unsigned long long)pid);
281 : }
282 :
283 : while (unw_step(&cursor) > 0) {
284 : ip = sp = off = 0;
285 : unw_get_reg(&cursor, UNW_REG_IP, &ip);
286 : unw_get_reg(&cursor, UNW_REG_SP, &sp);
287 :
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>");
291 : }
292 : printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
293 : nbuf, (long long)off, (long long)ip,
294 : (long long)sp);
295 : }
296 :
297 : (*count)++;
298 :
299 : cleanup:
300 : if (aspace) {
301 : unw_destroy_addr_space(aspace);
302 : }
303 :
304 : if (pinfo) {
305 : _UPT_destroy(pinfo);
306 : }
307 :
308 : ptrace(PTRACE_DETACH, pid, NULL, NULL);
309 : }
310 :
311 : static int stack_trace_server(pid_t pid, void *priv)
312 : {
313 : print_stack_trace(pid, (int *)priv);
314 : return 0;
315 : }
316 :
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)
321 : {
322 : pid_t dest;
323 : int count = 0;
324 :
325 : if (argc != 1) {
326 : fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
327 : return False;
328 : }
329 :
330 : dest = procid_to_pid(&pid);
331 :
332 : if (dest != 0) {
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.
337 : */
338 : print_stack_trace(dest, &count);
339 : } else {
340 : messaging_dgm_forall(stack_trace_server, &count);
341 : }
342 :
343 : return True;
344 : }
345 :
346 : #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
347 :
348 0 : 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)
352 : {
353 0 : fprintf(stderr,
354 : "Daemon stack tracing is not supported on this platform\n");
355 0 : return False;
356 : }
357 :
358 : #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
359 :
360 : /* Inject a fault (fatal signal) into a running smbd */
361 :
362 1 : 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)
366 : {
367 1 : if (argc != 2) {
368 0 : fprintf(stderr, "Usage: smbcontrol <dest> inject "
369 : "<bus|hup|term|internal|segv>\n");
370 0 : return False;
371 : }
372 :
373 : #if !defined(DEVELOPER) && !defined(ENABLE_SELFTEST)
374 : fprintf(stderr, "Fault injection is only available in "
375 : "developer and self test builds\n");
376 : return False;
377 : #else /* DEVELOPER || ENABLE_SELFTEST */
378 : {
379 1 : int sig = 0;
380 :
381 1 : if (strcmp(argv[1], "bus") == 0) {
382 0 : sig = SIGBUS;
383 1 : } else if (strcmp(argv[1], "hup") == 0) {
384 0 : sig = SIGHUP;
385 1 : } else if (strcmp(argv[1], "term") == 0) {
386 0 : sig = SIGTERM;
387 1 : } else if (strcmp(argv[1], "segv") == 0) {
388 1 : sig = SIGSEGV;
389 0 : } else if (strcmp(argv[1], "internal") == 0) {
390 : /* Force an internal error, ie. an unclean exit. */
391 0 : sig = -1;
392 : } else {
393 0 : fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
394 0 : return False;
395 : }
396 :
397 1 : return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
398 : &sig, sizeof(int));
399 : }
400 : #endif /* DEVELOPER || ENABLE_SELFTEST */
401 : }
402 :
403 1 : 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)
407 : {
408 : #if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
409 : unsigned int seconds;
410 : long input;
411 1 : const long MAX_SLEEP = 60 * 60; /* One hour maximum sleep */
412 : #endif
413 :
414 1 : if (argc != 2) {
415 0 : fprintf(stderr, "Usage: smbcontrol <dest> sleep seconds\n");
416 0 : return False;
417 : }
418 :
419 : #if !defined(DEVELOPER) && !defined(ENABLE_SELFTEST)
420 : fprintf(stderr, "Sleep is only available in "
421 : "developer and self test builds\n");
422 : return False;
423 : #else /* DEVELOPER || ENABLE_SELFTEST */
424 :
425 1 : input = atol(argv[1]);
426 1 : if (input < 1 || input > MAX_SLEEP) {
427 0 : fprintf(stderr,
428 : "Invalid duration for sleep '%s'\n"
429 : "It should be at least 1 second and no more than %ld\n",
430 0 : argv[1],
431 : MAX_SLEEP);
432 0 : return False;
433 : }
434 1 : seconds = input;
435 1 : return send_message(msg_ctx, pid,
436 : MSG_SMB_SLEEP,
437 : &seconds,
438 : sizeof(unsigned int));
439 : #endif /* DEVELOPER || ENABLE_SELFTEST */
440 : }
441 :
442 : /* Force a browser election */
443 :
444 0 : 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)
448 : {
449 0 : if (argc != 1) {
450 0 : fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
451 0 : return False;
452 : }
453 :
454 0 : return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
455 : }
456 :
457 : /* Ping a samba daemon process */
458 :
459 81 : static void pong_cb(struct messaging_context *msg,
460 : void *private_data,
461 : uint32_t msg_type,
462 : struct server_id pid,
463 : DATA_BLOB *data)
464 : {
465 : struct server_id_buf src_string;
466 81 : printf("PONG from pid %s\n", server_id_str_buf(pid, &src_string));
467 81 : num_replies++;
468 81 : }
469 :
470 82 : 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)
474 : {
475 82 : if (argc != 1) {
476 0 : fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
477 0 : return False;
478 : }
479 :
480 : /* Send a message and register our interest in a reply */
481 :
482 82 : if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
483 0 : return False;
484 :
485 82 : messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
486 :
487 82 : wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
488 :
489 : /* No replies were received within the timeout period */
490 :
491 82 : if (num_replies == 0)
492 1 : printf("No replies received\n");
493 :
494 82 : messaging_deregister(msg_ctx, MSG_PONG, NULL);
495 :
496 82 : return num_replies;
497 : }
498 :
499 : /* Set profiling options */
500 :
501 0 : 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)
505 : {
506 : int v;
507 :
508 0 : if (argc != 2) {
509 0 : fprintf(stderr, "Usage: smbcontrol <dest> profile "
510 : "<off|count|on|flush>\n");
511 0 : return False;
512 : }
513 :
514 0 : if (strcmp(argv[1], "off") == 0) {
515 0 : v = 0;
516 0 : } else if (strcmp(argv[1], "count") == 0) {
517 0 : v = 1;
518 0 : } else if (strcmp(argv[1], "on") == 0) {
519 0 : v = 2;
520 0 : } else if (strcmp(argv[1], "flush") == 0) {
521 0 : v = 3;
522 : } else {
523 0 : fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
524 0 : return False;
525 : }
526 :
527 0 : return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
528 : }
529 :
530 : /* Return the profiling level */
531 :
532 0 : static void profilelevel_cb(struct messaging_context *msg_ctx,
533 : void *private_data,
534 : uint32_t msg_type,
535 : struct server_id pid,
536 : DATA_BLOB *data)
537 : {
538 : int level;
539 : const char *s;
540 :
541 0 : num_replies++;
542 :
543 0 : if (data->length != sizeof(int)) {
544 0 : fprintf(stderr, "invalid message length %ld returned\n",
545 0 : (unsigned long)data->length);
546 0 : return;
547 : }
548 :
549 0 : memcpy(&level, data->data, sizeof(int));
550 :
551 0 : switch (level) {
552 0 : case 0:
553 0 : s = "not enabled";
554 0 : break;
555 0 : case 1:
556 0 : s = "off";
557 0 : break;
558 0 : case 3:
559 0 : s = "count only";
560 0 : break;
561 0 : case 7:
562 0 : s = "count and time";
563 0 : break;
564 0 : default:
565 0 : s = "BOGUS";
566 0 : break;
567 : }
568 :
569 0 : printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
570 : }
571 :
572 0 : static void profilelevel_rqst(struct messaging_context *msg_ctx,
573 : void *private_data,
574 : uint32_t msg_type,
575 : struct server_id pid,
576 : DATA_BLOB *data)
577 : {
578 0 : int v = 0;
579 :
580 : /* Send back a dummy reply */
581 :
582 0 : send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
583 0 : }
584 :
585 0 : 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)
589 : {
590 0 : if (argc != 1) {
591 0 : fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
592 0 : return False;
593 : }
594 :
595 : /* Send a message and register our interest in a reply */
596 :
597 0 : if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
598 0 : return False;
599 :
600 0 : messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
601 0 : messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
602 : profilelevel_rqst);
603 :
604 0 : wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
605 :
606 : /* No replies were received within the timeout period */
607 :
608 0 : if (num_replies == 0)
609 0 : printf("No replies received\n");
610 :
611 0 : messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
612 :
613 0 : return num_replies;
614 : }
615 :
616 : /* Display debug level settings */
617 :
618 0 : 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)
622 : {
623 0 : if (argc != 1) {
624 0 : fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
625 0 : return False;
626 : }
627 :
628 : /* Send a message and register our interest in a reply */
629 :
630 0 : if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
631 0 : return False;
632 :
633 0 : messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
634 :
635 0 : wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
636 :
637 : /* No replies were received within the timeout period */
638 :
639 0 : if (num_replies == 0)
640 0 : printf("No replies received\n");
641 :
642 0 : messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
643 :
644 0 : return num_replies;
645 : }
646 :
647 : /* Send a print notify message */
648 :
649 0 : 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)
653 : {
654 : const char *cmd;
655 :
656 : /* Check for subcommand */
657 :
658 0 : if (argc == 1) {
659 0 : fprintf(stderr, "Must specify subcommand:\n");
660 0 : fprintf(stderr, "\tqueuepause <printername>\n");
661 0 : fprintf(stderr, "\tqueueresume <printername>\n");
662 0 : fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
663 0 : fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
664 0 : fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
665 0 : fprintf(stderr, "\tprinter <printername> <comment|port|"
666 : "driver> <value>\n");
667 :
668 0 : return False;
669 : }
670 :
671 0 : cmd = argv[1];
672 :
673 0 : if (strcmp(cmd, "queuepause") == 0) {
674 :
675 0 : if (argc != 3) {
676 0 : fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
677 : " queuepause <printername>\n");
678 0 : return False;
679 : }
680 :
681 0 : notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
682 : PRINTER_STATUS_PAUSED);
683 :
684 0 : goto send;
685 :
686 0 : } else if (strcmp(cmd, "queueresume") == 0) {
687 :
688 0 : if (argc != 3) {
689 0 : fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
690 : " queuereume <printername>\n");
691 0 : return False;
692 : }
693 :
694 0 : notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
695 : PRINTER_STATUS_OK);
696 :
697 0 : goto send;
698 :
699 0 : } else if (strcmp(cmd, "jobpause") == 0) {
700 : int jobid;
701 :
702 0 : if (argc != 4) {
703 0 : fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
704 : " jobpause <printername> <unix-jobid>\n");
705 0 : return False;
706 : }
707 :
708 0 : jobid = atoi(argv[3]);
709 :
710 0 : notify_job_status_byname(
711 : ev_ctx, msg_ctx,
712 0 : argv[2], jobid, JOB_STATUS_PAUSED,
713 : SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
714 :
715 0 : goto send;
716 :
717 0 : } else if (strcmp(cmd, "jobresume") == 0) {
718 : int jobid;
719 :
720 0 : if (argc != 4) {
721 0 : fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
722 : " jobpause <printername> <unix-jobid>\n");
723 0 : return False;
724 : }
725 :
726 0 : jobid = atoi(argv[3]);
727 :
728 0 : notify_job_status_byname(
729 : ev_ctx, msg_ctx,
730 0 : argv[2], jobid, JOB_STATUS_QUEUED,
731 : SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
732 :
733 0 : goto send;
734 :
735 0 : } else if (strcmp(cmd, "jobdelete") == 0) {
736 : int jobid;
737 :
738 0 : if (argc != 4) {
739 0 : fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
740 : " jobpause <printername> <unix-jobid>\n");
741 0 : return False;
742 : }
743 :
744 0 : jobid = atoi(argv[3]);
745 :
746 0 : notify_job_status_byname(
747 : ev_ctx, msg_ctx,
748 0 : argv[2], jobid, JOB_STATUS_DELETING,
749 : SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
750 :
751 0 : notify_job_status_byname(
752 : ev_ctx, msg_ctx,
753 0 : argv[2], jobid, JOB_STATUS_DELETING|
754 : JOB_STATUS_DELETED,
755 : SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
756 :
757 0 : goto send;
758 :
759 0 : } else if (strcmp(cmd, "printer") == 0) {
760 : uint32_t attribute;
761 :
762 0 : if (argc != 5) {
763 0 : fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
764 : "printer <printername> <comment|port|driver> "
765 : "<value>\n");
766 0 : return False;
767 : }
768 :
769 0 : if (strcmp(argv[3], "comment") == 0) {
770 0 : attribute = PRINTER_NOTIFY_FIELD_COMMENT;
771 0 : } else if (strcmp(argv[3], "port") == 0) {
772 0 : attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
773 0 : } else if (strcmp(argv[3], "driver") == 0) {
774 0 : attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
775 : } else {
776 0 : fprintf(stderr, "Invalid printer command '%s'\n",
777 0 : argv[3]);
778 0 : return False;
779 : }
780 :
781 0 : notify_printer_byname(ev_ctx, msg_ctx, argv[2], attribute,
782 0 : discard_const_p(char, argv[4]));
783 :
784 0 : goto send;
785 : }
786 :
787 0 : fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
788 0 : return False;
789 :
790 0 : send:
791 0 : print_notify_send_messages(msg_ctx, 0);
792 0 : return True;
793 : }
794 :
795 : /* Close a share */
796 :
797 0 : 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)
801 : {
802 0 : if (argc != 2) {
803 0 : fprintf(stderr, "Usage: smbcontrol <dest> close-share "
804 : "<sharename>\n");
805 0 : return False;
806 : }
807 :
808 0 : return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
809 0 : strlen(argv[1]) + 1);
810 : }
811 :
812 : /*
813 : * Close a share if access denied by now
814 : **/
815 :
816 0 : 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)
821 : {
822 0 : if (argc != 2) {
823 0 : fprintf(stderr, "Usage: smbcontrol <dest> close-denied-share "
824 : "<sharename>\n");
825 0 : return False;
826 : }
827 :
828 0 : return send_message(
829 : msg_ctx,
830 : pid,
831 : MSG_SMB_FORCE_TDIS_DENIED,
832 0 : argv[1],
833 0 : strlen(argv[1]) + 1);
834 : }
835 :
836 : /* Kill a client by IP address */
837 0 : 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)
841 : {
842 0 : if (argc != 2) {
843 0 : fprintf(stderr, "Usage: smbcontrol <dest> kill-client-ip "
844 : "<IP address>\n");
845 0 : return false;
846 : }
847 :
848 0 : if (!is_ipaddress_v4(argv[1]) && !is_ipaddress_v6(argv[1])) {
849 0 : fprintf(stderr, "%s is not a valid IP address!\n", argv[1]);
850 0 : return false;
851 : }
852 :
853 0 : return send_message(msg_ctx, pid, MSG_SMB_KILL_CLIENT_IP,
854 0 : argv[1], strlen(argv[1]) + 1);
855 : }
856 :
857 : /* Tell winbindd an IP got dropped */
858 :
859 0 : 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)
863 : {
864 0 : if (argc != 2) {
865 0 : fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
866 : "<ip-address>\n");
867 0 : return False;
868 : }
869 :
870 0 : return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
871 0 : strlen(argv[1]) + 1);
872 : }
873 :
874 : /* Display talloc pool usage */
875 :
876 0 : 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)
880 : {
881 0 : pid_t pid = procid_to_pid(&dst);
882 0 : int stdout_fd = 1;
883 :
884 0 : if (argc != 1) {
885 0 : fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
886 0 : return False;
887 : }
888 :
889 0 : if (pid == 0) {
890 0 : fprintf(stderr, "Can only send to a specific PID\n");
891 0 : return false;
892 : }
893 :
894 0 : messaging_send_iov(
895 : msg_ctx,
896 : dst,
897 : MSG_REQ_POOL_USAGE,
898 : NULL,
899 : 0,
900 : &stdout_fd,
901 : 1);
902 :
903 0 : return true;
904 : }
905 :
906 0 : static bool do_rpc_dump_status(
907 : struct tevent_context *ev_ctx,
908 : struct messaging_context *msg_ctx,
909 : const struct server_id dst,
910 : const int argc,
911 : const char **argv)
912 : {
913 0 : pid_t pid = procid_to_pid(&dst);
914 0 : int stdout_fd = 1;
915 :
916 0 : if (argc != 1) {
917 0 : fprintf(stderr,
918 : "Usage: smbcontrol <dest> rpc-dump-status\n");
919 0 : return False;
920 : }
921 :
922 0 : if (pid == 0) {
923 0 : fprintf(stderr, "Can only send to a specific PID\n");
924 0 : return false;
925 : }
926 :
927 0 : messaging_send_iov(
928 : msg_ctx,
929 : dst,
930 : MSG_RPC_DUMP_STATUS,
931 : NULL,
932 : 0,
933 : &stdout_fd,
934 : 1);
935 :
936 0 : return true;
937 : }
938 :
939 : /* Fetch and print the ringbuf log */
940 :
941 0 : static void print_ringbuf_log_cb(struct messaging_context *msg,
942 : void *private_data,
943 : uint32_t msg_type,
944 : struct server_id pid,
945 : DATA_BLOB *data)
946 : {
947 0 : printf("%s", (const char *)data->data);
948 0 : num_replies++;
949 0 : }
950 :
951 0 : 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)
955 : {
956 0 : if (argc != 1) {
957 0 : fprintf(stderr, "Usage: smbcontrol <dest> ringbuf-log\n");
958 0 : return false;
959 : }
960 :
961 0 : messaging_register(msg_ctx, NULL, MSG_RINGBUF_LOG,
962 : print_ringbuf_log_cb);
963 :
964 : /* Send a message and register our interest in a reply */
965 :
966 0 : if (!send_message(msg_ctx, pid, MSG_REQ_RINGBUF_LOG, NULL, 0)) {
967 0 : return false;
968 : }
969 :
970 0 : wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
971 :
972 : /* No replies were received within the timeout period */
973 :
974 0 : if (num_replies == 0) {
975 0 : printf("No replies received\n");
976 : }
977 :
978 0 : messaging_deregister(msg_ctx, MSG_RINGBUF_LOG, NULL);
979 :
980 0 : return num_replies != 0;
981 : }
982 :
983 : /* Perform a dmalloc mark */
984 :
985 0 : 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)
989 : {
990 0 : if (argc != 1) {
991 0 : fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
992 0 : return False;
993 : }
994 :
995 0 : return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
996 : }
997 :
998 : /* Perform a dmalloc changed */
999 :
1000 0 : 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)
1004 : {
1005 0 : if (argc != 1) {
1006 0 : fprintf(stderr, "Usage: smbcontrol <dest> "
1007 : "dmalloc-log-changed\n");
1008 0 : return False;
1009 : }
1010 :
1011 0 : return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
1012 : NULL, 0);
1013 : }
1014 :
1015 0 : static void print_uint32_cb(struct messaging_context *msg, void *private_data,
1016 : uint32_t msg_type, struct server_id pid,
1017 : DATA_BLOB *data)
1018 : {
1019 : uint32_t num_children;
1020 :
1021 0 : if (data->length != sizeof(uint32_t)) {
1022 0 : printf("Invalid response: %d bytes long\n",
1023 0 : (int)data->length);
1024 0 : goto done;
1025 : }
1026 0 : num_children = IVAL(data->data, 0);
1027 0 : printf("%u children\n", (unsigned)num_children);
1028 0 : done:
1029 0 : num_replies++;
1030 0 : }
1031 :
1032 0 : 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)
1036 : {
1037 0 : if (argc != 1) {
1038 0 : fprintf(stderr, "Usage: smbcontrol <dest> num-children\n");
1039 0 : return False;
1040 : }
1041 :
1042 0 : messaging_register(msg_ctx, NULL, MSG_SMB_NUM_CHILDREN,
1043 : print_uint32_cb);
1044 :
1045 : /* Send a message and register our interest in a reply */
1046 :
1047 0 : if (!send_message(msg_ctx, pid, MSG_SMB_TELL_NUM_CHILDREN, NULL, 0))
1048 0 : return false;
1049 :
1050 0 : wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1051 :
1052 : /* No replies were received within the timeout period */
1053 :
1054 0 : if (num_replies == 0)
1055 0 : printf("No replies received\n");
1056 :
1057 0 : messaging_deregister(msg_ctx, MSG_SMB_NUM_CHILDREN, NULL);
1058 :
1059 0 : return num_replies;
1060 : }
1061 :
1062 0 : 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)
1066 : {
1067 : int ret;
1068 :
1069 0 : ret = messaging_cleanup(msg_ctx, pid.pid);
1070 :
1071 0 : printf("cleanup(%u) returned %s\n", (unsigned)pid.pid,
1072 0 : ret ? strerror(ret) : "ok");
1073 :
1074 0 : return (ret == 0);
1075 : }
1076 :
1077 : /* Shutdown a server process */
1078 :
1079 0 : 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)
1083 : {
1084 0 : if (argc != 1) {
1085 0 : fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
1086 0 : return False;
1087 : }
1088 :
1089 0 : return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
1090 : }
1091 :
1092 : /* Notify a driver upgrade */
1093 :
1094 0 : 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)
1098 : {
1099 0 : if (argc != 2) {
1100 0 : fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
1101 : "<driver-name>\n");
1102 0 : return False;
1103 : }
1104 :
1105 0 : return send_message(msg_ctx, pid, MSG_PRINTER_DRVUPGRADE, argv[1],
1106 0 : strlen(argv[1]) + 1);
1107 : }
1108 :
1109 0 : 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)
1113 : {
1114 : TDB_CONTEXT *tdb;
1115 : char *db_path;
1116 :
1117 0 : if (argc != 1) {
1118 0 : fprintf(stderr, "Usage: smbcontrol winbindd online\n");
1119 0 : return False;
1120 : }
1121 :
1122 0 : db_path = state_path(talloc_tos(), "winbindd_cache.tdb");
1123 0 : if (db_path == NULL) {
1124 0 : return false;
1125 : }
1126 :
1127 : /* Remove the entry in the winbindd_cache tdb to tell a later
1128 : starting winbindd that we're online. */
1129 :
1130 0 : tdb = tdb_open_log(db_path, 0, TDB_DEFAULT, O_RDWR, 0600);
1131 0 : if (!tdb) {
1132 0 : fprintf(stderr, "Cannot open the tdb %s for writing.\n",
1133 : db_path);
1134 0 : TALLOC_FREE(db_path);
1135 0 : return False;
1136 : }
1137 :
1138 0 : TALLOC_FREE(db_path);
1139 0 : tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
1140 0 : tdb_close(tdb);
1141 :
1142 0 : return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
1143 : }
1144 :
1145 4 : 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)
1149 : {
1150 : TDB_CONTEXT *tdb;
1151 4 : bool ret = False;
1152 4 : int retry = 0;
1153 : char *db_path;
1154 :
1155 4 : if (argc != 1) {
1156 0 : fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
1157 0 : return False;
1158 : }
1159 :
1160 4 : db_path = state_path(talloc_tos(), "winbindd_cache.tdb");
1161 4 : if (db_path == NULL) {
1162 0 : return false;
1163 : }
1164 :
1165 : /* Create an entry in the winbindd_cache tdb to tell a later
1166 : starting winbindd that we're offline. We may actually create
1167 : it here... */
1168 :
1169 4 : 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);
1173 :
1174 4 : if (!tdb) {
1175 0 : fprintf(stderr, "Cannot open the tdb %s for writing.\n",
1176 : db_path);
1177 0 : TALLOC_FREE(db_path);
1178 0 : return False;
1179 : }
1180 4 : TALLOC_FREE(db_path);
1181 :
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
1187 : 5 times. */
1188 :
1189 4 : for (retry = 0; retry < 5; retry++) {
1190 : uint8_t buf[4];
1191 4 : TDB_DATA d = { .dptr = buf, .dsize = sizeof(buf) };
1192 :
1193 4 : SIVAL(buf, 0, time(NULL));
1194 :
1195 4 : tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
1196 :
1197 4 : ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
1198 : NULL, 0);
1199 :
1200 : /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1201 4 : d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
1202 4 : if (d.dptr != NULL && d.dsize == 4) {
1203 4 : SAFE_FREE(d.dptr);
1204 4 : break;
1205 : }
1206 :
1207 0 : SAFE_FREE(d.dptr);
1208 0 : DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1209 : }
1210 :
1211 4 : tdb_close(tdb);
1212 4 : return ret;
1213 : }
1214 :
1215 0 : 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)
1219 : {
1220 0 : if (argc != 1) {
1221 0 : fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
1222 0 : return False;
1223 : }
1224 :
1225 0 : messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
1226 : print_pid_string_cb);
1227 :
1228 0 : if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, NULL, 0)) {
1229 0 : return False;
1230 : }
1231 :
1232 0 : wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1233 :
1234 : /* No replies were received within the timeout period */
1235 :
1236 0 : if (num_replies == 0)
1237 0 : printf("No replies received\n");
1238 :
1239 0 : messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1240 :
1241 0 : return num_replies;
1242 : }
1243 :
1244 0 : 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)
1248 : {
1249 0 : const char *domain = NULL;
1250 0 : int domain_len = 0;
1251 :
1252 0 : if (argc < 1 || argc > 2) {
1253 0 : fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1254 : "<domain>\n");
1255 0 : return false;
1256 : }
1257 :
1258 0 : if (argc == 2) {
1259 0 : domain = argv[1];
1260 0 : domain_len = strlen(argv[1]) + 1;
1261 : }
1262 :
1263 0 : messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1264 : print_pid_string_cb);
1265 :
1266 0 : if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1267 : domain, domain_len))
1268 : {
1269 0 : return false;
1270 : }
1271 :
1272 0 : wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1273 :
1274 : /* No replies were received within the timeout period */
1275 :
1276 0 : if (num_replies == 0) {
1277 0 : printf("No replies received\n");
1278 : }
1279 :
1280 0 : messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1281 :
1282 0 : return num_replies;
1283 : }
1284 :
1285 0 : 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)
1289 : {
1290 0 : if (argc != 1) {
1291 0 : fprintf(stderr, "Usage: smbcontrol <dest> disconnect-dc\n");
1292 0 : return False;
1293 : }
1294 :
1295 0 : return send_message(msg_ctx, pid, MSG_WINBIND_DISCONNECT_DC, NULL, 0);
1296 : }
1297 :
1298 4 : static void winbind_validate_cache_cb(struct messaging_context *msg,
1299 : void *private_data,
1300 : uint32_t msg_type,
1301 : struct server_id pid,
1302 : DATA_BLOB *data)
1303 : {
1304 : struct server_id_buf src_string;
1305 8 : printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1306 4 : (*(data->data) == 0 ? "" : "NOT "),
1307 : server_id_str_buf(pid, &src_string));
1308 4 : num_replies++;
1309 4 : }
1310 :
1311 4 : 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)
1315 : {
1316 : struct server_id myid;
1317 :
1318 4 : myid = messaging_server_id(msg_ctx);
1319 :
1320 4 : if (argc != 1) {
1321 0 : fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1322 0 : return False;
1323 : }
1324 :
1325 4 : messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1326 : winbind_validate_cache_cb);
1327 :
1328 4 : if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1329 : sizeof(myid))) {
1330 0 : return False;
1331 : }
1332 :
1333 4 : wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1334 :
1335 4 : if (num_replies == 0) {
1336 0 : printf("No replies received\n");
1337 : }
1338 :
1339 4 : messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1340 :
1341 4 : return num_replies;
1342 : }
1343 :
1344 10 : 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)
1348 : {
1349 10 : if (argc != 1) {
1350 0 : fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1351 0 : return False;
1352 : }
1353 :
1354 10 : return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1355 : }
1356 :
1357 0 : 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)
1361 : {
1362 0 : if (argc != 1) {
1363 0 : fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1364 0 : return False;
1365 : }
1366 :
1367 0 : return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1368 : }
1369 :
1370 0 : static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1371 : {
1372 : fstring unix_name;
1373 0 : memset( (char *)n, '\0', sizeof(struct nmb_name) );
1374 0 : fstrcpy(unix_name, name);
1375 0 : (void)strupper_m(unix_name);
1376 0 : push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1377 0 : n->name_type = (unsigned int)type & 0xFF;
1378 0 : push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE);
1379 0 : }
1380 :
1381 0 : 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)
1385 : {
1386 : struct packet_struct p;
1387 :
1388 0 : if (argc != 2) {
1389 0 : fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1390 0 : return False;
1391 : }
1392 :
1393 0 : ZERO_STRUCT(p);
1394 :
1395 0 : p.ip = interpret_addr2(argv[1]);
1396 0 : p.port = 137;
1397 0 : p.packet_type = NMB_PACKET;
1398 :
1399 0 : p.packet.nmb.header.name_trn_id = 10;
1400 0 : p.packet.nmb.header.opcode = 0;
1401 0 : p.packet.nmb.header.response = False;
1402 0 : p.packet.nmb.header.nm_flags.bcast = False;
1403 0 : p.packet.nmb.header.nm_flags.recursion_available = False;
1404 0 : p.packet.nmb.header.nm_flags.recursion_desired = False;
1405 0 : p.packet.nmb.header.nm_flags.trunc = False;
1406 0 : p.packet.nmb.header.nm_flags.authoritative = False;
1407 0 : p.packet.nmb.header.rcode = 0;
1408 0 : p.packet.nmb.header.qdcount = 1;
1409 0 : p.packet.nmb.header.ancount = 0;
1410 0 : p.packet.nmb.header.nscount = 0;
1411 0 : p.packet.nmb.header.arcount = 0;
1412 0 : my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1413 0 : p.packet.nmb.question.question_type = 0x21;
1414 0 : p.packet.nmb.question.question_class = 0x1;
1415 :
1416 0 : return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1417 : }
1418 :
1419 0 : 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)
1423 : {
1424 0 : if (argc != 1) {
1425 0 : fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1426 0 : return false;
1427 : }
1428 0 : return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1429 : }
1430 :
1431 : /* A list of message type supported */
1432 :
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 */
1440 : } msg_types[] = {
1441 : {
1442 : .name = "debug",
1443 : .fn = do_debug,
1444 : .help = "Set debuglevel",
1445 : },
1446 : {
1447 : .name = "idmap",
1448 : .fn = do_idmap,
1449 : .help = "Manipulate idmap cache",
1450 : },
1451 : {
1452 : .name = "force-election",
1453 : .fn = do_election,
1454 : .help = "Force a browse election",
1455 : },
1456 : {
1457 : .name = "ping",
1458 : .fn = do_ping,
1459 : .help = "Elicit a response",
1460 : },
1461 : {
1462 : .name = "profile",
1463 : .fn = do_profile,
1464 : .help = "",
1465 : },
1466 : {
1467 : .name = "inject",
1468 : .fn = do_inject_fault,
1469 : .help = "Inject a fatal signal into a running smbd"},
1470 : {
1471 : .name = "stacktrace",
1472 : .fn = do_daemon_stack_trace,
1473 : .help = "Display a stack trace of a daemon",
1474 : },
1475 : {
1476 : .name = "profilelevel",
1477 : .fn = do_profilelevel,
1478 : .help = "",
1479 : },
1480 : {
1481 : .name = "debuglevel",
1482 : .fn = do_debuglevel,
1483 : .help = "Display current debuglevels",
1484 : },
1485 : {
1486 : .name = "printnotify",
1487 : .fn = do_printnotify,
1488 : .help = "Send a print notify message",
1489 : },
1490 : {
1491 : .name = "close-share",
1492 : .fn = do_closeshare,
1493 : .help = "Forcibly disconnect a share",
1494 : },
1495 : {
1496 : .name = "close-denied-share",
1497 : .fn = do_close_denied_share,
1498 : .help = "Forcibly disconnect users from shares disallowed now",
1499 : },
1500 : {
1501 : .name = "kill-client-ip",
1502 : .fn = do_kill_client_by_ip,
1503 : .help = "Forcibly disconnect a client with a specific IP address",
1504 : },
1505 : {
1506 : .name = "ip-dropped",
1507 : .fn = do_ip_dropped,
1508 : .help = "Tell winbind that an IP got dropped",
1509 : },
1510 : {
1511 : .name = "pool-usage",
1512 : .fn = do_poolusage,
1513 : .help = "Display talloc memory usage",
1514 : },
1515 : {
1516 : .name = "rpc-dump-status",
1517 : .fn = do_rpc_dump_status,
1518 : .help = "Display rpc status",
1519 : },
1520 : {
1521 : .name = "ringbuf-log",
1522 : .fn = do_ringbuflog,
1523 : .help = "Display ringbuf log",
1524 : },
1525 : {
1526 : .name = "dmalloc-mark",
1527 : .fn = do_dmalloc_mark,
1528 : .help = "",
1529 : },
1530 : {
1531 : .name = "dmalloc-log-changed",
1532 : .fn = do_dmalloc_changed,
1533 : .help = "",
1534 : },
1535 : {
1536 : .name = "shutdown",
1537 : .fn = do_shutdown,
1538 : .help = "Shut down daemon",
1539 : },
1540 : {
1541 : .name = "drvupgrade",
1542 : .fn = do_drvupgrade,
1543 : .help = "Notify a printer driver has changed",
1544 : },
1545 : {
1546 : .name = "reload-config",
1547 : .fn = do_reload_config,
1548 : .help = "Force smbd or winbindd to reload config file"},
1549 : {
1550 : .name = "reload-printers",
1551 : .fn = do_reload_printers,
1552 : .help = "Force smbd to reload printers"},
1553 : {
1554 : .name = "nodestatus",
1555 : .fn = do_nodestatus,
1556 : .help = "Ask nmbd to do a node status request"},
1557 : {
1558 : .name = "online",
1559 : .fn = do_winbind_online,
1560 : .help = "Ask winbind to go into online state"},
1561 : {
1562 : .name = "offline",
1563 : .fn = do_winbind_offline,
1564 : .help = "Ask winbind to go into offline state"},
1565 : {
1566 : .name = "onlinestatus",
1567 : .fn = do_winbind_onlinestatus,
1568 : .help = "Request winbind online status"},
1569 : {
1570 : .name = "validate-cache" ,
1571 : .fn = do_winbind_validate_cache,
1572 : .help = "Validate winbind's credential cache",
1573 : },
1574 : {
1575 : .name = "dump-domain-list",
1576 : .fn = do_winbind_dump_domain_list,
1577 : .help = "Dump winbind domain list"},
1578 : {
1579 : .name = "disconnect-dc",
1580 : .fn = do_msg_disconnect_dc,
1581 : },
1582 : {
1583 : .name = "notify-cleanup",
1584 : .fn = do_notify_cleanup,
1585 : },
1586 : {
1587 : .name = "num-children",
1588 : .fn = do_num_children,
1589 : .help = "Print number of smbd child processes",
1590 : },
1591 : {
1592 : .name = "msg-cleanup",
1593 : .fn = do_msg_cleanup,
1594 : },
1595 : {
1596 : .name = "noop",
1597 : .fn = do_noop,
1598 : .help = "Do nothing",
1599 : },
1600 : {
1601 : .name = "sleep",
1602 : .fn = do_sleep,
1603 : .help = "Cause the target process to sleep",
1604 : },
1605 : { .name = NULL, },
1606 : };
1607 :
1608 : /* Display usage information */
1609 :
1610 0 : static void usage(poptContext pc)
1611 : {
1612 : int i;
1613 :
1614 0 : poptPrintHelp(pc, stderr, 0);
1615 :
1616 0 : fprintf(stderr, "\n");
1617 0 : fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1618 : "process ID\n");
1619 :
1620 0 : fprintf(stderr, "\n");
1621 0 : fprintf(stderr, "<message-type> is one of:\n");
1622 :
1623 0 : for (i = 0; msg_types[i].name; i++) {
1624 0 : const char *help = msg_types[i].help;
1625 0 : if (help == NULL) {
1626 0 : help = "";
1627 : }
1628 0 : fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, help);
1629 : }
1630 :
1631 0 : fprintf(stderr, "\n");
1632 :
1633 0 : exit(1);
1634 : }
1635 :
1636 : /* Return the pid number for a string destination */
1637 :
1638 102 : static struct server_id parse_dest(struct messaging_context *msg,
1639 : const char *dest)
1640 : {
1641 102 : struct server_id result = {
1642 : .pid = (uint64_t)-1,
1643 : };
1644 : pid_t pid;
1645 :
1646 : /* Zero is a special return value for broadcast to all processes */
1647 :
1648 102 : if (strequal(dest, "all")) {
1649 0 : return interpret_pid(MSG_BROADCAST_PID_STR);
1650 : }
1651 :
1652 : /* Try self - useful for testing */
1653 :
1654 102 : if (strequal(dest, "self")) {
1655 0 : return messaging_server_id(msg);
1656 : }
1657 :
1658 : /* Fix winbind typo. */
1659 102 : if (strequal(dest, "winbind")) {
1660 0 : dest = "winbindd";
1661 : }
1662 :
1663 : /* Check for numeric pid number */
1664 102 : result = interpret_pid(dest);
1665 :
1666 : /* Zero isn't valid if not "all". */
1667 102 : if (result.pid && procid_valid(&result)) {
1668 84 : return result;
1669 : }
1670 :
1671 : /* Look up other destinations in pidfile directory */
1672 :
1673 18 : if ((pid = pidfile_pid(lp_pid_directory(), dest)) != 0) {
1674 18 : return pid_to_procid(pid);
1675 : }
1676 :
1677 0 : fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1678 :
1679 0 : return result;
1680 : }
1681 :
1682 : /* Execute smbcontrol command */
1683 :
1684 102 : static bool do_command(struct tevent_context *ev_ctx,
1685 : struct messaging_context *msg_ctx,
1686 : int argc, const char **argv)
1687 : {
1688 102 : const char *dest = argv[0], *command = argv[1];
1689 : struct server_id pid;
1690 : int i;
1691 :
1692 : /* Check destination */
1693 :
1694 102 : pid = parse_dest(msg_ctx, dest);
1695 102 : if (!procid_valid(&pid)) {
1696 0 : return False;
1697 : }
1698 :
1699 : /* Check command */
1700 :
1701 805 : for (i = 0; msg_types[i].name; i++) {
1702 805 : if (strequal(command, msg_types[i].name))
1703 102 : return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1704 : argc - 1, argv + 1);
1705 : }
1706 :
1707 0 : fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1708 :
1709 0 : return False;
1710 : }
1711 :
1712 0 : static void smbcontrol_help(poptContext pc,
1713 : enum poptCallbackReason preason,
1714 : struct poptOption * poption,
1715 : const char * parg,
1716 : void * pdata)
1717 : {
1718 0 : if (poption->shortName != '?') {
1719 0 : poptPrintUsage(pc, stdout, 0);
1720 : } else {
1721 0 : usage(pc);
1722 : }
1723 :
1724 0 : exit(0);
1725 : }
1726 :
1727 : struct poptOption help_options[] = {
1728 : { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1729 : NULL, NULL },
1730 : { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1731 : { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1732 : {0}
1733 : } ;
1734 :
1735 : /* Main program */
1736 :
1737 102 : int main(int argc, const char **argv)
1738 : {
1739 : poptContext pc;
1740 : int opt;
1741 : struct tevent_context *evt_ctx;
1742 : struct messaging_context *msg_ctx;
1743 :
1744 306 : struct poptOption long_options[] = {
1745 : /* POPT_AUTOHELP */
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" },
1750 :
1751 102 : POPT_COMMON_SAMBA
1752 102 : POPT_COMMON_VERSION
1753 : POPT_TABLEEND
1754 : };
1755 102 : TALLOC_CTX *frame = talloc_stackframe();
1756 102 : int ret = 0;
1757 : bool ok;
1758 :
1759 102 : smb_init_locale();
1760 :
1761 102 : ok = samba_cmdline_init(frame,
1762 : SAMBA_CMDLINE_CONFIG_CLIENT,
1763 : false /* require_smbconf */);
1764 102 : if (!ok) {
1765 0 : DBG_ERR("Failed to init cmdline parser!\n");
1766 0 : TALLOC_FREE(frame);
1767 0 : exit(1);
1768 : }
1769 102 : lp_set_cmdline("log level", "0");
1770 :
1771 : /* Parse command line arguments using popt */
1772 :
1773 102 : pc = samba_popt_get_context(getprogname(),
1774 : argc,
1775 : argv,
1776 : long_options,
1777 : 0);
1778 102 : if (pc == NULL) {
1779 0 : DBG_ERR("Failed to setup popt context!\n");
1780 0 : TALLOC_FREE(frame);
1781 0 : exit(1);
1782 : }
1783 :
1784 102 : poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1785 : "<parameters>");
1786 :
1787 102 : if (argc == 1)
1788 0 : usage(pc);
1789 :
1790 169 : while ((opt = poptGetNextOpt(pc)) != -1) {
1791 0 : switch(opt) {
1792 0 : case 't': /* --timeout */
1793 0 : break;
1794 0 : default:
1795 0 : fprintf(stderr, "Invalid option\n");
1796 0 : poptPrintHelp(pc, stderr, 0);
1797 0 : break;
1798 : }
1799 : }
1800 :
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. */
1804 :
1805 102 : argv = (const char **)poptGetArgs(pc);
1806 102 : argc = 0;
1807 102 : if (argv != NULL) {
1808 375 : while (argv[argc] != NULL) {
1809 206 : argc++;
1810 : }
1811 : }
1812 :
1813 102 : if (argc <= 1)
1814 0 : usage(pc);
1815 :
1816 102 : msg_ctx = cmdline_messaging_context(get_dyn_CONFIGFILE());
1817 102 : if (msg_ctx == NULL) {
1818 0 : fprintf(stderr,
1819 : "Could not init messaging context, not root?\n");
1820 0 : TALLOC_FREE(frame);
1821 0 : exit(1);
1822 : }
1823 :
1824 102 : evt_ctx = global_event_context();
1825 :
1826 : /* Need to invert sense of return code -- samba
1827 : * routines mostly return True==1 for success, but
1828 : * shell needs 0. */
1829 :
1830 102 : ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1831 :
1832 102 : cmdline_messaging_context_free();
1833 102 : poptFreeContext(pc);
1834 102 : TALLOC_FREE(frame);
1835 102 : return ret;
1836 : }
|