smbstatus: add a sessions dictionary
[Samba.git] / source3 / utils / status.c
blobcf5f0a71a0bd48016d1b8bd410897505c4c74e76
1 /*
2 Unix SMB/CIFS implementation.
3 status reporting
4 Copyright (C) Andrew Tridgell 1994-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 Revision History:
21 12 aug 96: Erik.Devriendt@te6.siemens.be
22 added support for shared memory implementation of share mode locking
24 21-Jul-1998: rsharpe@ns.aus.com (Richard Sharpe)
25 Added -L (locks only) -S (shares only) flags and code
30 * This program reports current SMB connections
33 #include "includes.h"
34 #include "lib/util/server_id.h"
35 #include "smbd/globals.h"
36 #include "system/filesys.h"
37 #include "lib/cmdline/cmdline.h"
38 #include "dbwrap/dbwrap.h"
39 #include "dbwrap/dbwrap_open.h"
40 #include "../libcli/security/security.h"
41 #include "session.h"
42 #include "locking/share_mode_lock.h"
43 #include "locking/proto.h"
44 #include "messages.h"
45 #include "librpc/gen_ndr/open_files.h"
46 #include "smbd/smbd.h"
47 #include "librpc/gen_ndr/notify.h"
48 #include "conn_tdb.h"
49 #include "serverid.h"
50 #include "status_profile.h"
51 #include "status.h"
52 #include "status_json.h"
53 #include "smbd/notifyd/notifyd_db.h"
54 #include "cmdline_contexts.h"
55 #include "locking/leases_db.h"
56 #include "lib/util/string_wrappers.h"
58 #ifdef HAVE_JANSSON
59 #include <jansson.h>
60 #include "audit_logging.h" /* various JSON helpers */
61 #include "auth/common_auth.h"
62 #endif /* HAVE_JANSSON */
64 #define SMB_MAXPIDS 2048
65 static uid_t Ucrit_uid = 0; /* added by OH */
66 static struct server_id Ucrit_pid[SMB_MAXPIDS]; /* Ugly !!! */ /* added by OH */
67 static int Ucrit_MaxPid=0; /* added by OH */
68 static unsigned int Ucrit_IsActive = 0; /* added by OH */
70 static bool verbose, brief;
71 static bool shares_only; /* Added by RJS */
72 static bool locks_only; /* Added by RJS */
73 static bool processes_only;
74 static bool show_brl;
75 static bool numeric_only;
76 static bool do_checks = true;
78 const char *username = NULL;
80 /* added by OH */
81 static void Ucrit_addUid(uid_t uid)
83 Ucrit_uid = uid;
84 Ucrit_IsActive = 1;
87 static unsigned int Ucrit_checkUid(uid_t uid)
89 if ( !Ucrit_IsActive )
90 return 1;
92 if ( uid == Ucrit_uid )
93 return 1;
95 return 0;
98 static unsigned int Ucrit_checkPid(struct server_id pid)
100 int i;
102 if ( !Ucrit_IsActive )
103 return 1;
105 for (i=0;i<Ucrit_MaxPid;i++) {
106 if (server_id_equal(&pid, &Ucrit_pid[i])) {
107 return 1;
111 return 0;
114 static bool Ucrit_addPid( struct server_id pid )
116 if ( !Ucrit_IsActive )
117 return True;
119 if ( Ucrit_MaxPid >= SMB_MAXPIDS ) {
120 fprintf(stderr, "ERROR: More than %d pids for user %s!\n",
121 SMB_MAXPIDS, uidtoname(Ucrit_uid));
123 return False;
126 Ucrit_pid[Ucrit_MaxPid++] = pid;
128 return True;
131 static int print_share_mode_stdout(struct traverse_state *state,
132 const char *pid,
133 const char *user_name,
134 const char *denymode,
135 int access_mask,
136 const char *rw,
137 const char *oplock,
138 const char *servicepath,
139 const char *filename,
140 const char *timestr)
142 if (state->first) {
143 d_printf("\nLocked files:\n");
144 d_printf("Pid User(ID) DenyMode Access R/W Oplock SharePath Name Time\n");
145 d_printf("--------------------------------------------------------------------------------------------------\n");
147 state->first = false;
150 d_printf("%-11s %-9s %-10s 0x%-8x %-10s %-14s %s %s %s",
151 pid, user_name, denymode, access_mask, rw, oplock,
152 servicepath, filename, timestr);
153 return 0;
156 static int prepare_share_mode(struct traverse_state *state)
158 /* only print header line if there are open files */
159 state->first = true;
161 return 0;
164 static int print_share_mode(struct file_id fid,
165 const struct share_mode_data *d,
166 const struct share_mode_entry *e,
167 void *private_data)
169 const char *denymode = NULL;
170 uint denymode_int;
171 const char *oplock = NULL;
172 const char *pid = NULL;
173 const char *rw = NULL;
174 const char *filename = NULL;
175 const char *timestr = NULL;
176 const char *user_str = NULL;
177 struct traverse_state *state = (struct traverse_state *)private_data;
179 TALLOC_CTX *tmp_ctx = talloc_stackframe();
180 if (tmp_ctx == NULL) {
181 return -1;
184 if (do_checks && !is_valid_share_mode_entry(e)) {
185 TALLOC_FREE(tmp_ctx);
186 return 0;
189 if (do_checks && !serverid_exists(&e->pid)) {
190 /* the process for this entry does not exist any more */
191 TALLOC_FREE(tmp_ctx);
192 return 0;
195 if (Ucrit_checkPid(e->pid)) {
196 struct server_id_buf tmp;
197 pid = server_id_str_buf(e->pid, &tmp);
198 if (state->resolve_uids) {
199 user_str = talloc_asprintf(tmp_ctx, "%s", uidtoname(e->uid));
200 } else {
201 user_str = talloc_asprintf(tmp_ctx, "%u", (unsigned int)e->uid);
203 if (user_str == NULL) {
204 TALLOC_FREE(tmp_ctx);
205 return -1;
208 denymode_int = map_share_mode_to_deny_mode(e->share_access,
209 e->private_options);
210 switch (denymode_int) {
211 case DENY_NONE:
212 denymode = "DENY_NONE";
213 break;
214 case DENY_ALL:
215 denymode = "DENY_ALL";
216 break;
217 case DENY_DOS:
218 denymode = "DENY_DOS";
219 break;
220 case DENY_READ:
221 denymode = "DENY_READ";
222 break;
223 case DENY_WRITE:
224 denymode = "DENY_WRITE";
225 break;
226 case DENY_FCB:
227 denymode = "DENY_FCB";
228 break;
229 default: {
230 denymode = talloc_asprintf(tmp_ctx,
231 "UNKNOWN(0x%08x)",
232 denymode_int);
233 if (denymode == NULL) {
234 TALLOC_FREE(tmp_ctx);
235 return -1;
237 fprintf(stderr,
238 "unknown-please report ! "
239 "e->share_access = 0x%x, "
240 "e->private_options = 0x%x\n",
241 (unsigned int)e->share_access,
242 (unsigned int)e->private_options);
243 break;
246 filename = talloc_asprintf(tmp_ctx,
247 "%s%s",
248 d->base_name,
249 (d->stream_name != NULL) ? d->stream_name : "");
250 if (filename == NULL) {
251 TALLOC_FREE(tmp_ctx);
252 return -1;
254 if ((e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))==
255 (FILE_READ_DATA|FILE_WRITE_DATA)) {
256 rw = "RDWR";
257 } else if (e->access_mask & FILE_WRITE_DATA) {
258 rw = "WRONLY";
259 } else {
260 rw = "RDONLY";
263 if (e->op_type & BATCH_OPLOCK) {
264 oplock = "BATCH";
265 } else if (e->op_type & EXCLUSIVE_OPLOCK) {
266 oplock = "EXCLUSIVE";
267 } else if (e->op_type & LEVEL_II_OPLOCK) {
268 oplock = "LEVEL_II";
269 } else if (e->op_type == LEASE_OPLOCK) {
270 NTSTATUS status;
271 uint32_t lstate;
273 status = leases_db_get(
274 &e->client_guid,
275 &e->lease_key,
276 &d->id,
277 &lstate, /* current_state */
278 NULL, /* breaking */
279 NULL, /* breaking_to_requested */
280 NULL, /* breaking_to_required */
281 NULL, /* lease_version */
282 NULL); /* epoch */
284 if (NT_STATUS_IS_OK(status)) {
285 oplock = talloc_asprintf(tmp_ctx, "LEASE(%s%s%s)%s%s%s",
286 (lstate & SMB2_LEASE_READ)?"R":"",
287 (lstate & SMB2_LEASE_WRITE)?"W":"",
288 (lstate & SMB2_LEASE_HANDLE)?"H":"",
289 (lstate & SMB2_LEASE_READ)?"":" ",
290 (lstate & SMB2_LEASE_WRITE)?"":" ",
291 (lstate & SMB2_LEASE_HANDLE)?"":" ");
292 } else {
293 oplock = "LEASE STATE UNKNOWN";
295 } else {
296 oplock = "NONE";
299 timestr = time_to_asc((time_t)e->time.tv_sec);
300 print_share_mode_stdout(state,
301 pid,
302 user_str,
303 denymode,
304 (unsigned int)e->access_mask,
306 oplock,
307 d->servicepath,
308 filename,
309 timestr);
311 TALLOC_FREE(tmp_ctx);
312 return 0;
315 static void print_brl_stdout(struct traverse_state *state,
316 char *pid,
317 char *id,
318 const char *desc,
319 intmax_t start,
320 intmax_t size,
321 const char *sharepath,
322 char *fname)
324 if (state->first) {
325 d_printf("Byte range locks:\n");
326 d_printf("Pid dev:inode R/W start size SharePath Name\n");
327 d_printf("--------------------------------------------------------------------------------\n");
329 state->first = false;
331 d_printf("%-10s %-15s %-4s %-9jd %-9jd %-24s %-24s\n",
332 pid, id, desc, start, size, sharepath, fname);
335 static int prepare_brl(struct traverse_state *state)
337 /* only print header line if there are locked files */
338 state->first = true;
340 return 0;
343 static void print_brl(struct file_id id,
344 struct server_id pid,
345 enum brl_type lock_type,
346 enum brl_flavour lock_flav,
347 br_off start,
348 br_off size,
349 void *private_data)
351 unsigned int i;
352 static const struct {
353 enum brl_type lock_type;
354 const char *desc;
355 } lock_types[] = {
356 { READ_LOCK, "R" },
357 { WRITE_LOCK, "W" },
358 { UNLOCK_LOCK, "U" }
360 const char *desc="X";
361 const char *sharepath = "";
362 char *fname = NULL;
363 struct share_mode_lock *share_mode;
364 struct server_id_buf tmp;
365 struct file_id_buf ftmp;
366 struct traverse_state *state = (struct traverse_state *)private_data;
368 share_mode = fetch_share_mode_unlocked(NULL, id);
369 if (share_mode) {
370 fname = share_mode_filename(NULL, share_mode);
371 } else {
372 fname = talloc_strdup(NULL, "");
373 if (fname == NULL) {
374 return;
378 for (i=0;i<ARRAY_SIZE(lock_types);i++) {
379 if (lock_type == lock_types[i].lock_type) {
380 desc = lock_types[i].desc;
384 print_brl_stdout(state,
385 server_id_str_buf(pid, &tmp),
386 file_id_str_buf(id, &ftmp),
387 desc,
388 (intmax_t)start,
389 (intmax_t)size,
390 sharepath,
391 fname);
393 TALLOC_FREE(fname);
394 TALLOC_FREE(share_mode);
397 static const char *session_dialect_str(uint16_t dialect)
399 static fstring unknown_dialect;
401 switch(dialect){
402 case SMB2_DIALECT_REVISION_000:
403 return "NT1";
404 case SMB2_DIALECT_REVISION_202:
405 return "SMB2_02";
406 case SMB2_DIALECT_REVISION_210:
407 return "SMB2_10";
408 case SMB2_DIALECT_REVISION_222:
409 return "SMB2_22";
410 case SMB2_DIALECT_REVISION_224:
411 return "SMB2_24";
412 case SMB3_DIALECT_REVISION_300:
413 return "SMB3_00";
414 case SMB3_DIALECT_REVISION_302:
415 return "SMB3_02";
416 case SMB3_DIALECT_REVISION_310:
417 return "SMB3_10";
418 case SMB3_DIALECT_REVISION_311:
419 return "SMB3_11";
422 fstr_sprintf(unknown_dialect, "Unknown (0x%04x)", dialect);
423 return unknown_dialect;
426 static int traverse_connections_stdout(struct traverse_state *state,
427 const char *servicename,
428 char *server_id,
429 const char *machine,
430 const char *timestr,
431 const char *encryption,
432 const char *signing)
434 d_printf("%-12s %-7s %-13s %-32s %-12s %-12s\n",
435 servicename, server_id, machine, timestr, encryption, signing);
437 return 0;
440 static int prepare_connections(struct traverse_state *state)
442 if (!state->json_output) {
443 /* always print header line */
444 d_printf("\n%-12s %-7s %-13s %-32s %-12s %-12s\n", "Service", "pid", "Machine", "Connected at", "Encryption", "Signing");
445 d_printf("---------------------------------------------------------------------------------------------\n");
446 } else {
447 add_section_to_json(state, "tcons");
449 return 0;
452 static int traverse_connections(const struct connections_data *crec,
453 void *private_data)
455 struct server_id_buf tmp;
456 char *timestr = NULL;
457 int result = 0;
458 const char *encryption = "-";
459 enum crypto_degree encryption_degree = CRYPTO_DEGREE_NONE;
460 const char *signing = "-";
461 enum crypto_degree signing_degree = CRYPTO_DEGREE_NONE;
462 struct traverse_state *state = (struct traverse_state *)private_data;
464 TALLOC_CTX *tmp_ctx = talloc_stackframe();
465 if (tmp_ctx == NULL) {
466 return -1;
469 if (crec->cnum == TID_FIELD_INVALID) {
470 TALLOC_FREE(tmp_ctx);
471 return 0;
474 if (do_checks &&
475 (!process_exists(crec->pid) || !Ucrit_checkUid(crec->uid))) {
476 TALLOC_FREE(tmp_ctx);
477 return 0;
480 timestr = timestring(tmp_ctx, nt_time_to_unix(crec->start));
481 if (timestr == NULL) {
482 TALLOC_FREE(tmp_ctx);
483 return -1;
486 if (smbXsrv_is_encrypted(crec->encryption_flags)) {
487 switch (crec->cipher) {
488 case SMB_ENCRYPTION_GSSAPI:
489 encryption = "GSSAPI";
490 break;
491 case SMB2_ENCRYPTION_AES128_CCM:
492 encryption = "AES-128-CCM";
493 break;
494 case SMB2_ENCRYPTION_AES128_GCM:
495 encryption = "AES-128-GCM";
496 break;
497 default:
498 encryption = "???";
499 result = -1;
500 break;
502 encryption_degree = CRYPTO_DEGREE_FULL;
505 if (smbXsrv_is_signed(crec->signing_flags)) {
506 switch (crec->signing) {
507 case SMB2_SIGNING_MD5_SMB1:
508 signing = "HMAC-MD5";
509 break;
510 case SMB2_SIGNING_HMAC_SHA256:
511 signing = "HMAC-SHA256";
512 break;
513 case SMB2_SIGNING_AES128_CMAC:
514 signing = "AES-128-CMAC";
515 break;
516 case SMB2_SIGNING_AES128_GMAC:
517 signing = "AES-128-GMAC";
518 break;
519 default:
520 signing = "???";
521 result = -1;
522 break;
524 signing_degree = CRYPTO_DEGREE_FULL;
527 if (!state->json_output) {
528 result = traverse_connections_stdout(state,
529 crec->servicename,
530 server_id_str_buf(crec->pid, &tmp),
531 crec->machine,
532 timestr,
533 encryption,
534 signing);
535 } else {
536 result = traverse_connections_json(state,
537 crec,
538 encryption,
539 encryption_degree,
540 signing,
541 signing_degree);
544 TALLOC_FREE(timestr);
545 TALLOC_FREE(tmp_ctx);
547 return result;
550 static int traverse_sessionid_stdout(struct traverse_state *state,
551 char *server_id,
552 char *uid_gid_str,
553 char *machine_hostname,
554 const char *dialect,
555 const char *encryption_cipher,
556 enum crypto_degree encryption_degree,
557 const char *signing_cipher,
558 enum crypto_degree signing_degree)
560 fstring encryption;
561 fstring signing;
563 if (encryption_degree == CRYPTO_DEGREE_FULL) {
564 fstr_sprintf(encryption, "%s", encryption_cipher);
565 } else if (encryption_degree == CRYPTO_DEGREE_PARTIAL) {
566 fstr_sprintf(encryption, "partial(%s)", encryption_cipher);
567 } else {
568 fstr_sprintf(encryption, "-");
570 if (signing_degree == CRYPTO_DEGREE_FULL) {
571 fstr_sprintf(signing, "%s", signing_cipher);
572 } else if (signing_degree == CRYPTO_DEGREE_PARTIAL) {
573 fstr_sprintf(signing, "partial(%s)", signing_cipher);
574 } else {
575 fstr_sprintf(signing, "-");
578 d_printf("%-7s %-25s %-41s %-17s %-20s %-21s\n",
579 server_id, uid_gid_str, machine_hostname, dialect, encryption,
580 signing);
582 return 0;
585 static int prepare_sessionid(struct traverse_state *state)
587 if (!state->json_output) {
588 /* always print header line */
589 d_printf("\nSamba version %s\n",samba_version_string());
590 d_printf("%-7s %-12s %-12s %-41s %-17s %-20s %-21s\n", "PID", "Username", "Group", "Machine", "Protocol Version", "Encryption", "Signing");
591 d_printf("----------------------------------------------------------------------------------------------------------------------------------------\n");
592 } else {
593 add_section_to_json(state, "sessions");
595 return 0;
599 static int traverse_sessionid(const char *key, struct sessionid *session,
600 void *private_data)
602 fstring uid_gid_str;
603 fstring uid_str;
604 fstring gid_str;
605 struct server_id_buf tmp;
606 char *machine_hostname = NULL;
607 int result = 0;
608 const char *encryption = "-";
609 enum crypto_degree encryption_degree = CRYPTO_DEGREE_NONE;
610 const char *signing = "-";
611 enum crypto_degree signing_degree = CRYPTO_DEGREE_NONE;
612 struct traverse_state *state = (struct traverse_state *)private_data;
614 TALLOC_CTX *tmp_ctx = talloc_stackframe();
615 if (tmp_ctx == NULL) {
616 return -1;
619 if (do_checks &&
620 (!process_exists(session->pid) ||
621 !Ucrit_checkUid(session->uid))) {
622 TALLOC_FREE(tmp_ctx);
623 return 0;
626 Ucrit_addPid(session->pid);
628 if (numeric_only) {
629 fstr_sprintf(gid_str, "%u", (unsigned int)session->gid);
630 fstr_sprintf(uid_str, "%u", (unsigned int)session->uid);
631 fstr_sprintf(uid_gid_str, "%-12u %-12u",
632 (unsigned int)session->uid,
633 (unsigned int)session->gid);
634 } else {
635 if (session->uid == -1 && session->gid == -1) {
637 * The session is not fully authenticated yet.
639 fstrcpy(uid_gid_str, "(auth in progress)");
640 fstrcpy(gid_str, "(auth in progress)");
641 fstrcpy(uid_str, "(auth in progress)");
642 } else {
644 * In theory it should not happen that one of
645 * session->uid and session->gid is valid (ie != -1)
646 * while the other is not (ie = -1), so we a check for
647 * that case that bails out would be reasonable.
649 const char *uid_name = "-1";
650 const char *gid_name = "-1";
652 if (session->uid != -1) {
653 uid_name = uidtoname(session->uid);
654 if (uid_name == NULL) {
655 TALLOC_FREE(tmp_ctx);
656 return -1;
659 if (session->gid != -1) {
660 gid_name = gidtoname(session->gid);
661 if (gid_name == NULL) {
662 TALLOC_FREE(tmp_ctx);
663 return -1;
666 fstr_sprintf(gid_str, "%s", gid_name);
667 fstr_sprintf(uid_str, "%s", uid_name);
668 fstr_sprintf(uid_gid_str, "%-12s %-12s",
669 uid_name, gid_name);
673 machine_hostname = talloc_asprintf(tmp_ctx, "%s (%s)",
674 session->remote_machine,
675 session->hostname);
676 if (machine_hostname == NULL) {
677 TALLOC_FREE(tmp_ctx);
678 return -1;
681 if (smbXsrv_is_encrypted(session->encryption_flags) ||
682 smbXsrv_is_partially_encrypted(session->encryption_flags)) {
683 switch (session->cipher) {
684 case SMB2_ENCRYPTION_AES128_CCM:
685 encryption = "AES-128-CCM";
686 break;
687 case SMB2_ENCRYPTION_AES128_GCM:
688 encryption = "AES-128-GCM";
689 break;
690 case SMB2_ENCRYPTION_AES256_CCM:
691 encryption = "AES-256-CCM";
692 break;
693 case SMB2_ENCRYPTION_AES256_GCM:
694 encryption = "AES-256-GCM";
695 break;
696 default:
697 encryption = "???";
698 result = -1;
699 break;
701 if (smbXsrv_is_encrypted(session->encryption_flags)) {
702 encryption_degree = CRYPTO_DEGREE_FULL;
703 } else if (smbXsrv_is_partially_encrypted(session->encryption_flags)) {
704 encryption_degree = CRYPTO_DEGREE_PARTIAL;
708 if (smbXsrv_is_signed(session->signing_flags) ||
709 smbXsrv_is_partially_signed(session->signing_flags)) {
710 switch (session->signing) {
711 case SMB2_SIGNING_MD5_SMB1:
712 signing = "HMAC-MD5";
713 break;
714 case SMB2_SIGNING_HMAC_SHA256:
715 signing = "HMAC-SHA256";
716 break;
717 case SMB2_SIGNING_AES128_CMAC:
718 signing = "AES-128-CMAC";
719 break;
720 case SMB2_SIGNING_AES128_GMAC:
721 signing = "AES-128-GMAC";
722 break;
723 default:
724 signing = "???";
725 result = -1;
726 break;
728 if (smbXsrv_is_signed(session->signing_flags)) {
729 signing_degree = CRYPTO_DEGREE_FULL;
730 } else if (smbXsrv_is_partially_signed(session->signing_flags)) {
731 signing_degree = CRYPTO_DEGREE_PARTIAL;
736 if (!state->json_output) {
737 traverse_sessionid_stdout(state,
738 server_id_str_buf(session->pid, &tmp),
739 uid_gid_str,
740 machine_hostname,
741 session_dialect_str(session->connection_dialect),
742 encryption,
743 encryption_degree,
744 signing,
745 signing_degree);
746 } else {
747 result = traverse_sessionid_json(state,
748 session,
749 uid_str,
750 gid_str,
751 session_dialect_str(session->connection_dialect));
754 TALLOC_FREE(machine_hostname);
755 TALLOC_FREE(tmp_ctx);
757 return result;
761 static bool print_notify_rec_stdout(struct traverse_state *state,
762 const char *path,
763 char *server_id_str,
764 unsigned filter,
765 unsigned subdir_filter)
767 d_printf("%s\\%s\\%x\\%x\n", path, server_id_str,
768 filter, subdir_filter);
770 return true;
773 static int prepare_notify(struct traverse_state *state)
775 /* don't print header line */
777 return 0;
780 static bool print_notify_rec(const char *path, struct server_id server,
781 const struct notify_instance *instance,
782 void *private_data)
784 struct server_id_buf idbuf;
785 struct traverse_state *state = (struct traverse_state *)private_data;
786 bool result;
788 result = print_notify_rec_stdout(state,
789 path,
790 server_id_str_buf(server, &idbuf),
791 (unsigned)instance->filter,
792 (unsigned)instance->subdir_filter);
794 return result;
797 enum {
798 OPT_RESOLVE_UIDS = 1000,
801 int main(int argc, const char *argv[])
803 int c;
804 int profile_only = 0;
805 bool show_processes, show_locks, show_shares;
806 bool show_notify = false;
807 poptContext pc = NULL;
808 struct traverse_state state = {0};
809 struct poptOption long_options[] = {
810 POPT_AUTOHELP
812 .longName = "processes",
813 .shortName = 'p',
814 .argInfo = POPT_ARG_NONE,
815 .arg = NULL,
816 .val = 'p',
817 .descrip = "Show processes only",
820 .longName = "verbose",
821 .shortName = 'v',
822 .argInfo = POPT_ARG_NONE,
823 .arg = NULL,
824 .val = 'v',
825 .descrip = "Be verbose",
828 .longName = "locks",
829 .shortName = 'L',
830 .argInfo = POPT_ARG_NONE,
831 .arg = NULL,
832 .val = 'L',
833 .descrip = "Show locks only",
836 .longName = "shares",
837 .shortName = 'S',
838 .argInfo = POPT_ARG_NONE,
839 .arg = NULL,
840 .val = 'S',
841 .descrip = "Show shares only",
844 .longName = "notify",
845 .shortName = 'N',
846 .argInfo = POPT_ARG_NONE,
847 .arg = NULL,
848 .val = 'N',
849 .descrip = "Show notifies",
852 .longName = "user",
853 .shortName = 'u',
854 .argInfo = POPT_ARG_STRING,
855 .arg = &username,
856 .val = 'u',
857 .descrip = "Switch to user",
860 .longName = "brief",
861 .shortName = 'b',
862 .argInfo = POPT_ARG_NONE,
863 .arg = NULL,
864 .val = 'b',
865 .descrip = "Be brief",
868 .longName = "profile",
869 .shortName = 'P',
870 .argInfo = POPT_ARG_NONE,
871 .arg = NULL,
872 .val = 'P',
873 .descrip = "Do profiling",
876 .longName = "profile-rates",
877 .shortName = 'R',
878 .argInfo = POPT_ARG_NONE,
879 .arg = NULL,
880 .val = 'R',
881 .descrip = "Show call rates",
884 .longName = "byterange",
885 .shortName = 'B',
886 .argInfo = POPT_ARG_NONE,
887 .arg = NULL,
888 .val = 'B',
889 .descrip = "Include byte range locks"
892 .longName = "numeric",
893 .shortName = 'n',
894 .argInfo = POPT_ARG_NONE,
895 .arg = NULL,
896 .val = 'n',
897 .descrip = "Numeric uid/gid"
900 .longName = "fast",
901 .shortName = 'f',
902 .argInfo = POPT_ARG_NONE,
903 .arg = NULL,
904 .val = 'f',
905 .descrip = "Skip checks if processes still exist"
908 .longName = "resolve-uids",
909 .shortName = 0,
910 .argInfo = POPT_ARG_NONE,
911 .arg = NULL,
912 .val = OPT_RESOLVE_UIDS,
913 .descrip = "Try to resolve UIDs to usernames"
915 POPT_COMMON_SAMBA
916 POPT_COMMON_VERSION
917 POPT_TABLEEND
919 TALLOC_CTX *frame = talloc_stackframe();
920 int ret = 0;
921 struct messaging_context *msg_ctx = NULL;
922 char *db_path;
923 bool ok;
925 state.first = true;
926 state.json_output = false;
927 state.resolve_uids = false;
929 smb_init_locale();
931 ok = samba_cmdline_init(frame,
932 SAMBA_CMDLINE_CONFIG_CLIENT,
933 false /* require_smbconf */);
934 if (!ok) {
935 DBG_ERR("Failed to init cmdline parser!\n");
936 TALLOC_FREE(frame);
937 exit(1);
939 lp_set_cmdline("log level", "0");
941 pc = samba_popt_get_context(getprogname(),
942 argc,
943 argv,
944 long_options,
945 POPT_CONTEXT_KEEP_FIRST);
946 if (pc == NULL) {
947 DBG_ERR("Failed to setup popt context!\n");
948 TALLOC_FREE(frame);
949 exit(1);
952 while ((c = poptGetNextOpt(pc)) != -1) {
953 switch (c) {
954 case 'p':
955 processes_only = true;
956 break;
957 case 'v':
958 verbose = true;
959 break;
960 case 'L':
961 locks_only = true;
962 break;
963 case 'S':
964 shares_only = true;
965 break;
966 case 'N':
967 show_notify = true;
968 break;
969 case 'b':
970 brief = true;
971 break;
972 case 'u':
973 Ucrit_addUid(nametouid(poptGetOptArg(pc)));
974 break;
975 case 'P':
976 case 'R':
977 profile_only = c;
978 break;
979 case 'B':
980 show_brl = true;
981 break;
982 case 'n':
983 numeric_only = true;
984 break;
985 case 'f':
986 do_checks = false;
987 break;
988 case OPT_RESOLVE_UIDS:
989 state.resolve_uids = true;
990 break;
991 case POPT_ERROR_BADOPT:
992 fprintf(stderr, "\nInvalid option %s: %s\n\n",
993 poptBadOption(pc, 0), poptStrerror(c));
994 poptPrintUsage(pc, stderr, 0);
995 exit(1);
999 sec_init();
1001 #ifdef HAVE_JANSSON
1002 state.root_json = json_new_object();
1003 add_general_information_to_json(&state);
1004 #endif /* HAVE_JANSSON */
1006 if (getuid() != geteuid()) {
1007 fprintf(stderr, "smbstatus should not be run setuid\n");
1008 ret = 1;
1009 goto done;
1012 if (getuid() != 0) {
1013 fprintf(stderr, "smbstatus only works as root!\n");
1014 ret = 1;
1015 goto done;
1018 /* setup the flags based on the possible combincations */
1020 show_processes = !(shares_only || locks_only || profile_only) || processes_only;
1021 show_locks = !(shares_only || processes_only || profile_only) || locks_only;
1022 show_shares = !(processes_only || locks_only || profile_only) || shares_only;
1024 if ( username )
1025 Ucrit_addUid( nametouid(username) );
1027 if (verbose) {
1028 d_printf("using configfile = %s\n", get_dyn_CONFIGFILE());
1031 msg_ctx = cmdline_messaging_context(get_dyn_CONFIGFILE());
1032 if (msg_ctx == NULL) {
1033 fprintf(stderr, "Could not initialize messaging, not root?\n");
1034 ret = -1;
1035 goto done;
1038 switch (profile_only) {
1039 case 'P':
1040 /* Dump profile data */
1041 ok = status_profile_dump(verbose);
1042 ret = ok ? 0 : 1;
1043 goto done;
1044 case 'R':
1045 /* Continuously display rate-converted data */
1046 ok = status_profile_rates(verbose);
1047 ret = ok ? 0 : 1;
1048 goto done;
1049 default:
1050 break;
1053 if ( show_processes ) {
1054 prepare_sessionid(&state);
1055 sessionid_traverse_read(traverse_sessionid, &state);
1057 if (processes_only) {
1058 goto done;
1062 if ( show_shares ) {
1063 if (brief) {
1064 goto done;
1066 prepare_connections(&state);
1067 connections_forall_read(traverse_connections, &state);
1069 d_printf("\n");
1071 if ( shares_only ) {
1072 goto done;
1076 if ( show_locks ) {
1077 int result;
1078 struct db_context *db;
1080 db_path = lock_path(talloc_tos(), "locking.tdb");
1081 if (db_path == NULL) {
1082 fprintf(stderr, "Out of memory - exiting\n");
1083 ret = -1;
1084 goto done;
1087 db = db_open(NULL, db_path, 0,
1088 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDONLY, 0,
1089 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
1091 if (!db) {
1092 fprintf(stderr, "%s not initialised\n", db_path);
1093 fprintf(stderr, "This is normal if an SMB client has never "
1094 "connected to your server.\n");
1095 TALLOC_FREE(db_path);
1096 exit(0);
1097 } else {
1098 TALLOC_FREE(db);
1099 TALLOC_FREE(db_path);
1102 if (!locking_init_readonly()) {
1103 fprintf(stderr, "Can't initialise locking module - exiting\n");
1104 ret = 1;
1105 goto done;
1108 prepare_share_mode(&state);
1109 result = share_entry_forall(print_share_mode, &state);
1111 if (result == 0) {
1112 fprintf(stderr, "No locked files\n");
1113 } else if (result < 0) {
1114 fprintf(stderr, "locked file list truncated\n");
1117 d_printf("\n");
1119 if (show_brl) {
1120 prepare_brl(&state);
1121 brl_forall(print_brl, &state);
1124 locking_end();
1127 if (show_notify) {
1128 prepare_notify(&state);
1129 notify_walk(msg_ctx, print_notify_rec, &state);
1132 done:
1133 cmdline_messaging_context_free();
1134 poptFreeContext(pc);
1135 TALLOC_FREE(frame);
1136 return ret;