smbstatus: add json items to traverse_struct
[Samba.git] / source3 / utils / status.c
blob20a49a69b6765a8cd1fc47aea1c355c0c44eeca0
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 /* always print header line */
443 d_printf("\n%-12s %-7s %-13s %-32s %-12s %-12s\n", "Service", "pid", "Machine", "Connected at", "Encryption", "Signing");
444 d_printf("---------------------------------------------------------------------------------------------\n");
446 return 0;
449 static int traverse_connections(const struct connections_data *crec,
450 void *private_data)
452 struct server_id_buf tmp;
453 char *timestr = NULL;
454 int result = 0;
455 const char *encryption = "-";
456 const char *signing = "-";
457 struct traverse_state *state = (struct traverse_state *)private_data;
459 TALLOC_CTX *tmp_ctx = talloc_stackframe();
460 if (tmp_ctx == NULL) {
461 return -1;
464 if (crec->cnum == TID_FIELD_INVALID) {
465 TALLOC_FREE(tmp_ctx);
466 return 0;
469 if (do_checks &&
470 (!process_exists(crec->pid) || !Ucrit_checkUid(crec->uid))) {
471 TALLOC_FREE(tmp_ctx);
472 return 0;
475 timestr = timestring(tmp_ctx, crec->start);
476 if (timestr == NULL) {
477 TALLOC_FREE(tmp_ctx);
478 return -1;
481 if (smbXsrv_is_encrypted(crec->encryption_flags)) {
482 switch (crec->cipher) {
483 case SMB_ENCRYPTION_GSSAPI:
484 encryption = "GSSAPI";
485 break;
486 case SMB2_ENCRYPTION_AES128_CCM:
487 encryption = "AES-128-CCM";
488 break;
489 case SMB2_ENCRYPTION_AES128_GCM:
490 encryption = "AES-128-GCM";
491 break;
492 default:
493 encryption = "???";
494 result = -1;
495 break;
499 if (smbXsrv_is_signed(crec->signing_flags)) {
500 switch (crec->signing) {
501 case SMB2_SIGNING_MD5_SMB1:
502 signing = "HMAC-MD5";
503 break;
504 case SMB2_SIGNING_HMAC_SHA256:
505 signing = "HMAC-SHA256";
506 break;
507 case SMB2_SIGNING_AES128_CMAC:
508 signing = "AES-128-CMAC";
509 break;
510 case SMB2_SIGNING_AES128_GMAC:
511 signing = "AES-128-GMAC";
512 break;
513 default:
514 signing = "???";
515 result = -1;
516 break;
520 result = traverse_connections_stdout(state,
521 crec->servicename,
522 server_id_str_buf(crec->pid, &tmp),
523 crec->machine,
524 timestr,
525 encryption,
526 signing);
528 TALLOC_FREE(timestr);
529 TALLOC_FREE(tmp_ctx);
531 return result;
534 static int traverse_sessionid_stdout(struct traverse_state *state,
535 char *server_id,
536 char *uid_gid_str,
537 char *machine_hostname,
538 const char *dialect,
539 const char *encryption_cipher,
540 enum crypto_degree encryption_degree,
541 const char *signing_cipher,
542 enum crypto_degree signing_degree)
544 fstring encryption;
545 fstring signing;
547 if (encryption_degree == CRYPTO_DEGREE_FULL) {
548 fstr_sprintf(encryption, "%s", encryption_cipher);
549 } else if (encryption_degree == CRYPTO_DEGREE_PARTIAL) {
550 fstr_sprintf(encryption, "partial(%s)", encryption_cipher);
551 } else {
552 fstr_sprintf(encryption, "-");
554 if (signing_degree == CRYPTO_DEGREE_FULL) {
555 fstr_sprintf(signing, "%s", signing_cipher);
556 } else if (signing_degree == CRYPTO_DEGREE_PARTIAL) {
557 fstr_sprintf(signing, "partial(%s)", signing_cipher);
558 } else {
559 fstr_sprintf(signing, "-");
562 d_printf("%-7s %-25s %-41s %-17s %-20s %-21s\n",
563 server_id, uid_gid_str, machine_hostname, dialect, encryption,
564 signing);
566 return 0;
569 static int prepare_sessionid(struct traverse_state *state)
571 /* always print header line */
572 d_printf("\nSamba version %s\n",samba_version_string());
573 d_printf("%-7s %-12s %-12s %-41s %-17s %-20s %-21s\n", "PID", "Username", "Group", "Machine", "Protocol Version", "Encryption", "Signing");
574 d_printf("----------------------------------------------------------------------------------------------------------------------------------------\n");
576 return 0;
580 static int traverse_sessionid(const char *key, struct sessionid *session,
581 void *private_data)
583 fstring uid_gid_str;
584 struct server_id_buf tmp;
585 char *machine_hostname = NULL;
586 int result = 0;
587 const char *encryption = "-";
588 enum crypto_degree encryption_degree = CRYPTO_DEGREE_NONE;
589 const char *signing = "-";
590 enum crypto_degree signing_degree = CRYPTO_DEGREE_NONE;
591 struct traverse_state *state = (struct traverse_state *)private_data;
593 TALLOC_CTX *tmp_ctx = talloc_stackframe();
594 if (tmp_ctx == NULL) {
595 return -1;
598 if (do_checks &&
599 (!process_exists(session->pid) ||
600 !Ucrit_checkUid(session->uid))) {
601 TALLOC_FREE(tmp_ctx);
602 return 0;
605 Ucrit_addPid(session->pid);
607 if (numeric_only) {
608 fstr_sprintf(uid_gid_str, "%-12u %-12u",
609 (unsigned int)session->uid,
610 (unsigned int)session->gid);
611 } else {
612 if (session->uid == -1 && session->gid == -1) {
614 * The session is not fully authenticated yet.
616 fstrcpy(uid_gid_str, "(auth in progress)");
617 } else {
619 * In theory it should not happen that one of
620 * session->uid and session->gid is valid (ie != -1)
621 * while the other is not (ie = -1), so we a check for
622 * that case that bails out would be reasonable.
624 const char *uid_name = "-1";
625 const char *gid_name = "-1";
627 if (session->uid != -1) {
628 uid_name = uidtoname(session->uid);
629 if (uid_name == NULL) {
630 TALLOC_FREE(tmp_ctx);
631 return -1;
634 if (session->gid != -1) {
635 gid_name = gidtoname(session->gid);
636 if (gid_name == NULL) {
637 TALLOC_FREE(tmp_ctx);
638 return -1;
641 fstr_sprintf(uid_gid_str, "%-12s %-12s",
642 uid_name, gid_name);
646 machine_hostname = talloc_asprintf(tmp_ctx, "%s (%s)",
647 session->remote_machine,
648 session->hostname);
649 if (machine_hostname == NULL) {
650 TALLOC_FREE(tmp_ctx);
651 return -1;
654 if (smbXsrv_is_encrypted(session->encryption_flags) ||
655 smbXsrv_is_partially_encrypted(session->encryption_flags)) {
656 switch (session->cipher) {
657 case SMB2_ENCRYPTION_AES128_CCM:
658 encryption = "AES-128-CCM";
659 break;
660 case SMB2_ENCRYPTION_AES128_GCM:
661 encryption = "AES-128-GCM";
662 break;
663 case SMB2_ENCRYPTION_AES256_CCM:
664 encryption = "AES-256-CCM";
665 break;
666 case SMB2_ENCRYPTION_AES256_GCM:
667 encryption = "AES-256-GCM";
668 break;
669 default:
670 encryption = "???";
671 result = -1;
672 break;
674 if (smbXsrv_is_encrypted(session->encryption_flags)) {
675 encryption_degree = CRYPTO_DEGREE_FULL;
676 } else if (smbXsrv_is_partially_encrypted(session->encryption_flags)) {
677 encryption_degree = CRYPTO_DEGREE_PARTIAL;
681 if (smbXsrv_is_signed(session->signing_flags) ||
682 smbXsrv_is_partially_signed(session->signing_flags)) {
683 switch (session->signing) {
684 case SMB2_SIGNING_MD5_SMB1:
685 signing = "HMAC-MD5";
686 break;
687 case SMB2_SIGNING_HMAC_SHA256:
688 signing = "HMAC-SHA256";
689 break;
690 case SMB2_SIGNING_AES128_CMAC:
691 signing = "AES-128-CMAC";
692 break;
693 case SMB2_SIGNING_AES128_GMAC:
694 signing = "AES-128-GMAC";
695 break;
696 default:
697 signing = "???";
698 result = -1;
699 break;
701 if (smbXsrv_is_signed(session->signing_flags)) {
702 signing_degree = CRYPTO_DEGREE_FULL;
703 } else if (smbXsrv_is_partially_signed(session->signing_flags)) {
704 signing_degree = CRYPTO_DEGREE_PARTIAL;
709 traverse_sessionid_stdout(state,
710 server_id_str_buf(session->pid, &tmp),
711 uid_gid_str,
712 machine_hostname,
713 session_dialect_str(session->connection_dialect),
714 encryption,
715 encryption_degree,
716 signing,
717 signing_degree);
719 TALLOC_FREE(machine_hostname);
720 TALLOC_FREE(tmp_ctx);
722 return result;
726 static bool print_notify_rec_stdout(struct traverse_state *state,
727 const char *path,
728 char *server_id_str,
729 unsigned filter,
730 unsigned subdir_filter)
732 d_printf("%s\\%s\\%x\\%x\n", path, server_id_str,
733 filter, subdir_filter);
735 return true;
738 static int prepare_notify(struct traverse_state *state)
740 /* don't print header line */
742 return 0;
745 static bool print_notify_rec(const char *path, struct server_id server,
746 const struct notify_instance *instance,
747 void *private_data)
749 struct server_id_buf idbuf;
750 struct traverse_state *state = (struct traverse_state *)private_data;
751 bool result;
753 result = print_notify_rec_stdout(state,
754 path,
755 server_id_str_buf(server, &idbuf),
756 (unsigned)instance->filter,
757 (unsigned)instance->subdir_filter);
759 return result;
762 enum {
763 OPT_RESOLVE_UIDS = 1000,
766 int main(int argc, const char *argv[])
768 int c;
769 int profile_only = 0;
770 bool show_processes, show_locks, show_shares;
771 bool show_notify = false;
772 poptContext pc = NULL;
773 struct traverse_state state = {0};
774 struct poptOption long_options[] = {
775 POPT_AUTOHELP
777 .longName = "processes",
778 .shortName = 'p',
779 .argInfo = POPT_ARG_NONE,
780 .arg = NULL,
781 .val = 'p',
782 .descrip = "Show processes only",
785 .longName = "verbose",
786 .shortName = 'v',
787 .argInfo = POPT_ARG_NONE,
788 .arg = NULL,
789 .val = 'v',
790 .descrip = "Be verbose",
793 .longName = "locks",
794 .shortName = 'L',
795 .argInfo = POPT_ARG_NONE,
796 .arg = NULL,
797 .val = 'L',
798 .descrip = "Show locks only",
801 .longName = "shares",
802 .shortName = 'S',
803 .argInfo = POPT_ARG_NONE,
804 .arg = NULL,
805 .val = 'S',
806 .descrip = "Show shares only",
809 .longName = "notify",
810 .shortName = 'N',
811 .argInfo = POPT_ARG_NONE,
812 .arg = NULL,
813 .val = 'N',
814 .descrip = "Show notifies",
817 .longName = "user",
818 .shortName = 'u',
819 .argInfo = POPT_ARG_STRING,
820 .arg = &username,
821 .val = 'u',
822 .descrip = "Switch to user",
825 .longName = "brief",
826 .shortName = 'b',
827 .argInfo = POPT_ARG_NONE,
828 .arg = NULL,
829 .val = 'b',
830 .descrip = "Be brief",
833 .longName = "profile",
834 .shortName = 'P',
835 .argInfo = POPT_ARG_NONE,
836 .arg = NULL,
837 .val = 'P',
838 .descrip = "Do profiling",
841 .longName = "profile-rates",
842 .shortName = 'R',
843 .argInfo = POPT_ARG_NONE,
844 .arg = NULL,
845 .val = 'R',
846 .descrip = "Show call rates",
849 .longName = "byterange",
850 .shortName = 'B',
851 .argInfo = POPT_ARG_NONE,
852 .arg = NULL,
853 .val = 'B',
854 .descrip = "Include byte range locks"
857 .longName = "numeric",
858 .shortName = 'n',
859 .argInfo = POPT_ARG_NONE,
860 .arg = NULL,
861 .val = 'n',
862 .descrip = "Numeric uid/gid"
865 .longName = "fast",
866 .shortName = 'f',
867 .argInfo = POPT_ARG_NONE,
868 .arg = NULL,
869 .val = 'f',
870 .descrip = "Skip checks if processes still exist"
873 .longName = "resolve-uids",
874 .shortName = 0,
875 .argInfo = POPT_ARG_NONE,
876 .arg = NULL,
877 .val = OPT_RESOLVE_UIDS,
878 .descrip = "Try to resolve UIDs to usernames"
880 POPT_COMMON_SAMBA
881 POPT_COMMON_VERSION
882 POPT_TABLEEND
884 TALLOC_CTX *frame = talloc_stackframe();
885 int ret = 0;
886 struct messaging_context *msg_ctx = NULL;
887 char *db_path;
888 bool ok;
890 state.first = true;
891 state.json_output = false;
892 state.resolve_uids = false;
894 smb_init_locale();
896 ok = samba_cmdline_init(frame,
897 SAMBA_CMDLINE_CONFIG_CLIENT,
898 false /* require_smbconf */);
899 if (!ok) {
900 DBG_ERR("Failed to init cmdline parser!\n");
901 TALLOC_FREE(frame);
902 exit(1);
904 lp_set_cmdline("log level", "0");
906 pc = samba_popt_get_context(getprogname(),
907 argc,
908 argv,
909 long_options,
910 POPT_CONTEXT_KEEP_FIRST);
911 if (pc == NULL) {
912 DBG_ERR("Failed to setup popt context!\n");
913 TALLOC_FREE(frame);
914 exit(1);
917 while ((c = poptGetNextOpt(pc)) != -1) {
918 switch (c) {
919 case 'p':
920 processes_only = true;
921 break;
922 case 'v':
923 verbose = true;
924 break;
925 case 'L':
926 locks_only = true;
927 break;
928 case 'S':
929 shares_only = true;
930 break;
931 case 'N':
932 show_notify = true;
933 break;
934 case 'b':
935 brief = true;
936 break;
937 case 'u':
938 Ucrit_addUid(nametouid(poptGetOptArg(pc)));
939 break;
940 case 'P':
941 case 'R':
942 profile_only = c;
943 break;
944 case 'B':
945 show_brl = true;
946 break;
947 case 'n':
948 numeric_only = true;
949 break;
950 case 'f':
951 do_checks = false;
952 break;
953 case OPT_RESOLVE_UIDS:
954 state.resolve_uids = true;
955 break;
956 case POPT_ERROR_BADOPT:
957 fprintf(stderr, "\nInvalid option %s: %s\n\n",
958 poptBadOption(pc, 0), poptStrerror(c));
959 poptPrintUsage(pc, stderr, 0);
960 exit(1);
964 sec_init();
966 #ifdef HAVE_JANSSON
967 state.root_json = json_new_object();
968 #endif /* HAVE_JANSSON */
970 if (getuid() != geteuid()) {
971 fprintf(stderr, "smbstatus should not be run setuid\n");
972 ret = 1;
973 goto done;
976 if (getuid() != 0) {
977 fprintf(stderr, "smbstatus only works as root!\n");
978 ret = 1;
979 goto done;
982 /* setup the flags based on the possible combincations */
984 show_processes = !(shares_only || locks_only || profile_only) || processes_only;
985 show_locks = !(shares_only || processes_only || profile_only) || locks_only;
986 show_shares = !(processes_only || locks_only || profile_only) || shares_only;
988 if ( username )
989 Ucrit_addUid( nametouid(username) );
991 if (verbose) {
992 d_printf("using configfile = %s\n", get_dyn_CONFIGFILE());
995 msg_ctx = cmdline_messaging_context(get_dyn_CONFIGFILE());
996 if (msg_ctx == NULL) {
997 fprintf(stderr, "Could not initialize messaging, not root?\n");
998 ret = -1;
999 goto done;
1002 switch (profile_only) {
1003 case 'P':
1004 /* Dump profile data */
1005 ok = status_profile_dump(verbose);
1006 ret = ok ? 0 : 1;
1007 goto done;
1008 case 'R':
1009 /* Continuously display rate-converted data */
1010 ok = status_profile_rates(verbose);
1011 ret = ok ? 0 : 1;
1012 goto done;
1013 default:
1014 break;
1017 if ( show_processes ) {
1018 prepare_sessionid(&state);
1019 sessionid_traverse_read(traverse_sessionid, &state);
1021 if (processes_only) {
1022 goto done;
1026 if ( show_shares ) {
1027 if (brief) {
1028 goto done;
1030 prepare_connections(&state);
1031 connections_forall_read(traverse_connections, &state);
1033 d_printf("\n");
1035 if ( shares_only ) {
1036 goto done;
1040 if ( show_locks ) {
1041 int result;
1042 struct db_context *db;
1044 db_path = lock_path(talloc_tos(), "locking.tdb");
1045 if (db_path == NULL) {
1046 fprintf(stderr, "Out of memory - exiting\n");
1047 ret = -1;
1048 goto done;
1051 db = db_open(NULL, db_path, 0,
1052 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDONLY, 0,
1053 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
1055 if (!db) {
1056 fprintf(stderr, "%s not initialised\n", db_path);
1057 fprintf(stderr, "This is normal if an SMB client has never "
1058 "connected to your server.\n");
1059 TALLOC_FREE(db_path);
1060 exit(0);
1061 } else {
1062 TALLOC_FREE(db);
1063 TALLOC_FREE(db_path);
1066 if (!locking_init_readonly()) {
1067 fprintf(stderr, "Can't initialise locking module - exiting\n");
1068 ret = 1;
1069 goto done;
1072 prepare_share_mode(&state);
1073 result = share_entry_forall(print_share_mode, &state);
1075 if (result == 0) {
1076 fprintf(stderr, "No locked files\n");
1077 } else if (result < 0) {
1078 fprintf(stderr, "locked file list truncated\n");
1081 d_printf("\n");
1083 if (show_brl) {
1084 prepare_brl(&state);
1085 brl_forall(print_brl, &state);
1088 locking_end();
1091 if (show_notify) {
1092 prepare_notify(&state);
1093 notify_walk(msg_ctx, print_notify_rec, &state);
1096 done:
1097 cmdline_messaging_context_free();
1098 poptFreeContext(pc);
1099 TALLOC_FREE(frame);
1100 return ret;