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