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