smbstatus: add a basic dictionary with open files
[Samba.git] / source3 / utils / status.c
blob1b9729e562a782f32496e1e67d98f9ea311171b4
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 if (!state->json_output) {
159 /* only print header line if there are open files */
160 state->first = true;
161 } else {
162 add_section_to_json(state, "open_files");
164 return 0;
167 static int print_share_mode(struct file_id fid,
168 const struct share_mode_data *d,
169 const struct share_mode_entry *e,
170 void *private_data)
172 const char *denymode = NULL;
173 uint denymode_int;
174 const char *oplock = NULL;
175 const char *pid = NULL;
176 const char *rw = NULL;
177 const char *filename = NULL;
178 const char *timestr = NULL;
179 const char *user_str = NULL;
180 struct traverse_state *state = (struct traverse_state *)private_data;
182 TALLOC_CTX *tmp_ctx = talloc_stackframe();
183 if (tmp_ctx == NULL) {
184 return -1;
187 if (do_checks && !is_valid_share_mode_entry(e)) {
188 TALLOC_FREE(tmp_ctx);
189 return 0;
192 if (do_checks && !serverid_exists(&e->pid)) {
193 /* the process for this entry does not exist any more */
194 TALLOC_FREE(tmp_ctx);
195 return 0;
198 if (Ucrit_checkPid(e->pid)) {
199 struct server_id_buf tmp;
200 pid = server_id_str_buf(e->pid, &tmp);
201 if (state->resolve_uids) {
202 user_str = talloc_asprintf(tmp_ctx, "%s", uidtoname(e->uid));
203 } else {
204 user_str = talloc_asprintf(tmp_ctx, "%u", (unsigned int)e->uid);
206 if (user_str == NULL) {
207 TALLOC_FREE(tmp_ctx);
208 return -1;
211 denymode_int = map_share_mode_to_deny_mode(e->share_access,
212 e->private_options);
213 switch (denymode_int) {
214 case DENY_NONE:
215 denymode = "DENY_NONE";
216 break;
217 case DENY_ALL:
218 denymode = "DENY_ALL";
219 break;
220 case DENY_DOS:
221 denymode = "DENY_DOS";
222 break;
223 case DENY_READ:
224 denymode = "DENY_READ";
225 break;
226 case DENY_WRITE:
227 denymode = "DENY_WRITE";
228 break;
229 case DENY_FCB:
230 denymode = "DENY_FCB";
231 break;
232 default: {
233 denymode = talloc_asprintf(tmp_ctx,
234 "UNKNOWN(0x%08x)",
235 denymode_int);
236 if (denymode == NULL) {
237 TALLOC_FREE(tmp_ctx);
238 return -1;
240 fprintf(stderr,
241 "unknown-please report ! "
242 "e->share_access = 0x%x, "
243 "e->private_options = 0x%x\n",
244 (unsigned int)e->share_access,
245 (unsigned int)e->private_options);
246 break;
249 filename = talloc_asprintf(tmp_ctx,
250 "%s%s",
251 d->base_name,
252 (d->stream_name != NULL) ? d->stream_name : "");
253 if (filename == NULL) {
254 TALLOC_FREE(tmp_ctx);
255 return -1;
257 if ((e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))==
258 (FILE_READ_DATA|FILE_WRITE_DATA)) {
259 rw = "RDWR";
260 } else if (e->access_mask & FILE_WRITE_DATA) {
261 rw = "WRONLY";
262 } else {
263 rw = "RDONLY";
266 if (e->op_type & BATCH_OPLOCK) {
267 oplock = "BATCH";
268 } else if (e->op_type & EXCLUSIVE_OPLOCK) {
269 oplock = "EXCLUSIVE";
270 } else if (e->op_type & LEVEL_II_OPLOCK) {
271 oplock = "LEVEL_II";
272 } else if (e->op_type == LEASE_OPLOCK) {
273 NTSTATUS status;
274 uint32_t lstate;
276 status = leases_db_get(
277 &e->client_guid,
278 &e->lease_key,
279 &d->id,
280 &lstate, /* current_state */
281 NULL, /* breaking */
282 NULL, /* breaking_to_requested */
283 NULL, /* breaking_to_required */
284 NULL, /* lease_version */
285 NULL); /* epoch */
287 if (NT_STATUS_IS_OK(status)) {
288 oplock = talloc_asprintf(tmp_ctx, "LEASE(%s%s%s)%s%s%s",
289 (lstate & SMB2_LEASE_READ)?"R":"",
290 (lstate & SMB2_LEASE_WRITE)?"W":"",
291 (lstate & SMB2_LEASE_HANDLE)?"H":"",
292 (lstate & SMB2_LEASE_READ)?"":" ",
293 (lstate & SMB2_LEASE_WRITE)?"":" ",
294 (lstate & SMB2_LEASE_HANDLE)?"":" ");
295 } else {
296 oplock = "LEASE STATE UNKNOWN";
298 } else {
299 oplock = "NONE";
302 timestr = time_to_asc((time_t)e->time.tv_sec);
304 if (!state->json_output) {
305 print_share_mode_stdout(state,
306 pid,
307 user_str,
308 denymode,
309 (unsigned int)e->access_mask,
311 oplock,
312 d->servicepath,
313 filename,
314 timestr);
315 } else {
316 print_share_mode_json(state,
318 filename);
321 TALLOC_FREE(tmp_ctx);
322 return 0;
325 static void print_brl_stdout(struct traverse_state *state,
326 char *pid,
327 char *id,
328 const char *desc,
329 intmax_t start,
330 intmax_t size,
331 const char *sharepath,
332 char *fname)
334 if (state->first) {
335 d_printf("Byte range locks:\n");
336 d_printf("Pid dev:inode R/W start size SharePath Name\n");
337 d_printf("--------------------------------------------------------------------------------\n");
339 state->first = false;
341 d_printf("%-10s %-15s %-4s %-9jd %-9jd %-24s %-24s\n",
342 pid, id, desc, start, size, sharepath, fname);
345 static int prepare_brl(struct traverse_state *state)
347 /* only print header line if there are locked files */
348 state->first = true;
350 return 0;
353 static void print_brl(struct file_id id,
354 struct server_id pid,
355 enum brl_type lock_type,
356 enum brl_flavour lock_flav,
357 br_off start,
358 br_off size,
359 void *private_data)
361 unsigned int i;
362 static const struct {
363 enum brl_type lock_type;
364 const char *desc;
365 } lock_types[] = {
366 { READ_LOCK, "R" },
367 { WRITE_LOCK, "W" },
368 { UNLOCK_LOCK, "U" }
370 const char *desc="X";
371 const char *sharepath = "";
372 char *fname = NULL;
373 struct share_mode_lock *share_mode;
374 struct server_id_buf tmp;
375 struct file_id_buf ftmp;
376 struct traverse_state *state = (struct traverse_state *)private_data;
378 share_mode = fetch_share_mode_unlocked(NULL, id);
379 if (share_mode) {
380 fname = share_mode_filename(NULL, share_mode);
381 } else {
382 fname = talloc_strdup(NULL, "");
383 if (fname == NULL) {
384 return;
388 for (i=0;i<ARRAY_SIZE(lock_types);i++) {
389 if (lock_type == lock_types[i].lock_type) {
390 desc = lock_types[i].desc;
394 print_brl_stdout(state,
395 server_id_str_buf(pid, &tmp),
396 file_id_str_buf(id, &ftmp),
397 desc,
398 (intmax_t)start,
399 (intmax_t)size,
400 sharepath,
401 fname);
403 TALLOC_FREE(fname);
404 TALLOC_FREE(share_mode);
407 static const char *session_dialect_str(uint16_t dialect)
409 static fstring unknown_dialect;
411 switch(dialect){
412 case SMB2_DIALECT_REVISION_000:
413 return "NT1";
414 case SMB2_DIALECT_REVISION_202:
415 return "SMB2_02";
416 case SMB2_DIALECT_REVISION_210:
417 return "SMB2_10";
418 case SMB2_DIALECT_REVISION_222:
419 return "SMB2_22";
420 case SMB2_DIALECT_REVISION_224:
421 return "SMB2_24";
422 case SMB3_DIALECT_REVISION_300:
423 return "SMB3_00";
424 case SMB3_DIALECT_REVISION_302:
425 return "SMB3_02";
426 case SMB3_DIALECT_REVISION_310:
427 return "SMB3_10";
428 case SMB3_DIALECT_REVISION_311:
429 return "SMB3_11";
432 fstr_sprintf(unknown_dialect, "Unknown (0x%04x)", dialect);
433 return unknown_dialect;
436 static int traverse_connections_stdout(struct traverse_state *state,
437 const char *servicename,
438 char *server_id,
439 const char *machine,
440 const char *timestr,
441 const char *encryption,
442 const char *signing)
444 d_printf("%-12s %-7s %-13s %-32s %-12s %-12s\n",
445 servicename, server_id, machine, timestr, encryption, signing);
447 return 0;
450 static int prepare_connections(struct traverse_state *state)
452 if (!state->json_output) {
453 /* always print header line */
454 d_printf("\n%-12s %-7s %-13s %-32s %-12s %-12s\n", "Service", "pid", "Machine", "Connected at", "Encryption", "Signing");
455 d_printf("---------------------------------------------------------------------------------------------\n");
456 } else {
457 add_section_to_json(state, "tcons");
459 return 0;
462 static int traverse_connections(const struct connections_data *crec,
463 void *private_data)
465 struct server_id_buf tmp;
466 char *timestr = NULL;
467 int result = 0;
468 const char *encryption = "-";
469 enum crypto_degree encryption_degree = CRYPTO_DEGREE_NONE;
470 const char *signing = "-";
471 enum crypto_degree signing_degree = CRYPTO_DEGREE_NONE;
472 struct traverse_state *state = (struct traverse_state *)private_data;
474 TALLOC_CTX *tmp_ctx = talloc_stackframe();
475 if (tmp_ctx == NULL) {
476 return -1;
479 if (crec->cnum == TID_FIELD_INVALID) {
480 TALLOC_FREE(tmp_ctx);
481 return 0;
484 if (do_checks &&
485 (!process_exists(crec->pid) || !Ucrit_checkUid(crec->uid))) {
486 TALLOC_FREE(tmp_ctx);
487 return 0;
490 timestr = timestring(tmp_ctx, nt_time_to_unix(crec->start));
491 if (timestr == NULL) {
492 TALLOC_FREE(tmp_ctx);
493 return -1;
496 if (smbXsrv_is_encrypted(crec->encryption_flags)) {
497 switch (crec->cipher) {
498 case SMB_ENCRYPTION_GSSAPI:
499 encryption = "GSSAPI";
500 break;
501 case SMB2_ENCRYPTION_AES128_CCM:
502 encryption = "AES-128-CCM";
503 break;
504 case SMB2_ENCRYPTION_AES128_GCM:
505 encryption = "AES-128-GCM";
506 break;
507 default:
508 encryption = "???";
509 result = -1;
510 break;
512 encryption_degree = CRYPTO_DEGREE_FULL;
515 if (smbXsrv_is_signed(crec->signing_flags)) {
516 switch (crec->signing) {
517 case SMB2_SIGNING_MD5_SMB1:
518 signing = "HMAC-MD5";
519 break;
520 case SMB2_SIGNING_HMAC_SHA256:
521 signing = "HMAC-SHA256";
522 break;
523 case SMB2_SIGNING_AES128_CMAC:
524 signing = "AES-128-CMAC";
525 break;
526 case SMB2_SIGNING_AES128_GMAC:
527 signing = "AES-128-GMAC";
528 break;
529 default:
530 signing = "???";
531 result = -1;
532 break;
534 signing_degree = CRYPTO_DEGREE_FULL;
537 if (!state->json_output) {
538 result = traverse_connections_stdout(state,
539 crec->servicename,
540 server_id_str_buf(crec->pid, &tmp),
541 crec->machine,
542 timestr,
543 encryption,
544 signing);
545 } else {
546 result = traverse_connections_json(state,
547 crec,
548 encryption,
549 encryption_degree,
550 signing,
551 signing_degree);
554 TALLOC_FREE(timestr);
555 TALLOC_FREE(tmp_ctx);
557 return result;
560 static int traverse_sessionid_stdout(struct traverse_state *state,
561 char *server_id,
562 char *uid_gid_str,
563 char *machine_hostname,
564 const char *dialect,
565 const char *encryption_cipher,
566 enum crypto_degree encryption_degree,
567 const char *signing_cipher,
568 enum crypto_degree signing_degree)
570 fstring encryption;
571 fstring signing;
573 if (encryption_degree == CRYPTO_DEGREE_FULL) {
574 fstr_sprintf(encryption, "%s", encryption_cipher);
575 } else if (encryption_degree == CRYPTO_DEGREE_PARTIAL) {
576 fstr_sprintf(encryption, "partial(%s)", encryption_cipher);
577 } else {
578 fstr_sprintf(encryption, "-");
580 if (signing_degree == CRYPTO_DEGREE_FULL) {
581 fstr_sprintf(signing, "%s", signing_cipher);
582 } else if (signing_degree == CRYPTO_DEGREE_PARTIAL) {
583 fstr_sprintf(signing, "partial(%s)", signing_cipher);
584 } else {
585 fstr_sprintf(signing, "-");
588 d_printf("%-7s %-25s %-41s %-17s %-20s %-21s\n",
589 server_id, uid_gid_str, machine_hostname, dialect, encryption,
590 signing);
592 return 0;
595 static int prepare_sessionid(struct traverse_state *state)
597 if (!state->json_output) {
598 /* always print header line */
599 d_printf("\nSamba version %s\n",samba_version_string());
600 d_printf("%-7s %-12s %-12s %-41s %-17s %-20s %-21s\n", "PID", "Username", "Group", "Machine", "Protocol Version", "Encryption", "Signing");
601 d_printf("----------------------------------------------------------------------------------------------------------------------------------------\n");
602 } else {
603 add_section_to_json(state, "sessions");
605 return 0;
609 static int traverse_sessionid(const char *key, struct sessionid *session,
610 void *private_data)
612 fstring uid_gid_str;
613 fstring uid_str;
614 fstring gid_str;
615 struct server_id_buf tmp;
616 char *machine_hostname = NULL;
617 int result = 0;
618 const char *encryption = "-";
619 enum crypto_degree encryption_degree = CRYPTO_DEGREE_NONE;
620 const char *signing = "-";
621 enum crypto_degree signing_degree = CRYPTO_DEGREE_NONE;
622 struct traverse_state *state = (struct traverse_state *)private_data;
624 TALLOC_CTX *tmp_ctx = talloc_stackframe();
625 if (tmp_ctx == NULL) {
626 return -1;
629 if (do_checks &&
630 (!process_exists(session->pid) ||
631 !Ucrit_checkUid(session->uid))) {
632 TALLOC_FREE(tmp_ctx);
633 return 0;
636 Ucrit_addPid(session->pid);
638 if (numeric_only) {
639 fstr_sprintf(gid_str, "%u", (unsigned int)session->gid);
640 fstr_sprintf(uid_str, "%u", (unsigned int)session->uid);
641 fstr_sprintf(uid_gid_str, "%-12u %-12u",
642 (unsigned int)session->uid,
643 (unsigned int)session->gid);
644 } else {
645 if (session->uid == -1 && session->gid == -1) {
647 * The session is not fully authenticated yet.
649 fstrcpy(uid_gid_str, "(auth in progress)");
650 fstrcpy(gid_str, "(auth in progress)");
651 fstrcpy(uid_str, "(auth in progress)");
652 } else {
654 * In theory it should not happen that one of
655 * session->uid and session->gid is valid (ie != -1)
656 * while the other is not (ie = -1), so we a check for
657 * that case that bails out would be reasonable.
659 const char *uid_name = "-1";
660 const char *gid_name = "-1";
662 if (session->uid != -1) {
663 uid_name = uidtoname(session->uid);
664 if (uid_name == NULL) {
665 TALLOC_FREE(tmp_ctx);
666 return -1;
669 if (session->gid != -1) {
670 gid_name = gidtoname(session->gid);
671 if (gid_name == NULL) {
672 TALLOC_FREE(tmp_ctx);
673 return -1;
676 fstr_sprintf(gid_str, "%s", gid_name);
677 fstr_sprintf(uid_str, "%s", uid_name);
678 fstr_sprintf(uid_gid_str, "%-12s %-12s",
679 uid_name, gid_name);
683 machine_hostname = talloc_asprintf(tmp_ctx, "%s (%s)",
684 session->remote_machine,
685 session->hostname);
686 if (machine_hostname == NULL) {
687 TALLOC_FREE(tmp_ctx);
688 return -1;
691 if (smbXsrv_is_encrypted(session->encryption_flags) ||
692 smbXsrv_is_partially_encrypted(session->encryption_flags)) {
693 switch (session->cipher) {
694 case SMB2_ENCRYPTION_AES128_CCM:
695 encryption = "AES-128-CCM";
696 break;
697 case SMB2_ENCRYPTION_AES128_GCM:
698 encryption = "AES-128-GCM";
699 break;
700 case SMB2_ENCRYPTION_AES256_CCM:
701 encryption = "AES-256-CCM";
702 break;
703 case SMB2_ENCRYPTION_AES256_GCM:
704 encryption = "AES-256-GCM";
705 break;
706 default:
707 encryption = "???";
708 result = -1;
709 break;
711 if (smbXsrv_is_encrypted(session->encryption_flags)) {
712 encryption_degree = CRYPTO_DEGREE_FULL;
713 } else if (smbXsrv_is_partially_encrypted(session->encryption_flags)) {
714 encryption_degree = CRYPTO_DEGREE_PARTIAL;
718 if (smbXsrv_is_signed(session->signing_flags) ||
719 smbXsrv_is_partially_signed(session->signing_flags)) {
720 switch (session->signing) {
721 case SMB2_SIGNING_MD5_SMB1:
722 signing = "HMAC-MD5";
723 break;
724 case SMB2_SIGNING_HMAC_SHA256:
725 signing = "HMAC-SHA256";
726 break;
727 case SMB2_SIGNING_AES128_CMAC:
728 signing = "AES-128-CMAC";
729 break;
730 case SMB2_SIGNING_AES128_GMAC:
731 signing = "AES-128-GMAC";
732 break;
733 default:
734 signing = "???";
735 result = -1;
736 break;
738 if (smbXsrv_is_signed(session->signing_flags)) {
739 signing_degree = CRYPTO_DEGREE_FULL;
740 } else if (smbXsrv_is_partially_signed(session->signing_flags)) {
741 signing_degree = CRYPTO_DEGREE_PARTIAL;
746 if (!state->json_output) {
747 traverse_sessionid_stdout(state,
748 server_id_str_buf(session->pid, &tmp),
749 uid_gid_str,
750 machine_hostname,
751 session_dialect_str(session->connection_dialect),
752 encryption,
753 encryption_degree,
754 signing,
755 signing_degree);
756 } else {
757 result = traverse_sessionid_json(state,
758 session,
759 uid_str,
760 gid_str,
761 encryption,
762 encryption_degree,
763 signing,
764 signing_degree,
765 session_dialect_str(session->connection_dialect));
768 TALLOC_FREE(machine_hostname);
769 TALLOC_FREE(tmp_ctx);
771 return result;
775 static bool print_notify_rec_stdout(struct traverse_state *state,
776 const char *path,
777 char *server_id_str,
778 unsigned filter,
779 unsigned subdir_filter)
781 d_printf("%s\\%s\\%x\\%x\n", path, server_id_str,
782 filter, subdir_filter);
784 return true;
787 static int prepare_notify(struct traverse_state *state)
789 /* don't print header line */
791 return 0;
794 static bool print_notify_rec(const char *path, struct server_id server,
795 const struct notify_instance *instance,
796 void *private_data)
798 struct server_id_buf idbuf;
799 struct traverse_state *state = (struct traverse_state *)private_data;
800 bool result;
802 result = print_notify_rec_stdout(state,
803 path,
804 server_id_str_buf(server, &idbuf),
805 (unsigned)instance->filter,
806 (unsigned)instance->subdir_filter);
808 return result;
811 enum {
812 OPT_RESOLVE_UIDS = 1000,
815 int main(int argc, const char *argv[])
817 int c;
818 int profile_only = 0;
819 bool show_processes, show_locks, show_shares;
820 bool show_notify = false;
821 poptContext pc = NULL;
822 struct traverse_state state = {0};
823 struct poptOption long_options[] = {
824 POPT_AUTOHELP
826 .longName = "processes",
827 .shortName = 'p',
828 .argInfo = POPT_ARG_NONE,
829 .arg = NULL,
830 .val = 'p',
831 .descrip = "Show processes only",
834 .longName = "verbose",
835 .shortName = 'v',
836 .argInfo = POPT_ARG_NONE,
837 .arg = NULL,
838 .val = 'v',
839 .descrip = "Be verbose",
842 .longName = "locks",
843 .shortName = 'L',
844 .argInfo = POPT_ARG_NONE,
845 .arg = NULL,
846 .val = 'L',
847 .descrip = "Show locks only",
850 .longName = "shares",
851 .shortName = 'S',
852 .argInfo = POPT_ARG_NONE,
853 .arg = NULL,
854 .val = 'S',
855 .descrip = "Show shares only",
858 .longName = "notify",
859 .shortName = 'N',
860 .argInfo = POPT_ARG_NONE,
861 .arg = NULL,
862 .val = 'N',
863 .descrip = "Show notifies",
866 .longName = "user",
867 .shortName = 'u',
868 .argInfo = POPT_ARG_STRING,
869 .arg = &username,
870 .val = 'u',
871 .descrip = "Switch to user",
874 .longName = "brief",
875 .shortName = 'b',
876 .argInfo = POPT_ARG_NONE,
877 .arg = NULL,
878 .val = 'b',
879 .descrip = "Be brief",
882 .longName = "profile",
883 .shortName = 'P',
884 .argInfo = POPT_ARG_NONE,
885 .arg = NULL,
886 .val = 'P',
887 .descrip = "Do profiling",
890 .longName = "profile-rates",
891 .shortName = 'R',
892 .argInfo = POPT_ARG_NONE,
893 .arg = NULL,
894 .val = 'R',
895 .descrip = "Show call rates",
898 .longName = "byterange",
899 .shortName = 'B',
900 .argInfo = POPT_ARG_NONE,
901 .arg = NULL,
902 .val = 'B',
903 .descrip = "Include byte range locks"
906 .longName = "numeric",
907 .shortName = 'n',
908 .argInfo = POPT_ARG_NONE,
909 .arg = NULL,
910 .val = 'n',
911 .descrip = "Numeric uid/gid"
914 .longName = "fast",
915 .shortName = 'f',
916 .argInfo = POPT_ARG_NONE,
917 .arg = NULL,
918 .val = 'f',
919 .descrip = "Skip checks if processes still exist"
922 .longName = "resolve-uids",
923 .shortName = 0,
924 .argInfo = POPT_ARG_NONE,
925 .arg = NULL,
926 .val = OPT_RESOLVE_UIDS,
927 .descrip = "Try to resolve UIDs to usernames"
929 POPT_COMMON_SAMBA
930 POPT_COMMON_VERSION
931 POPT_TABLEEND
933 TALLOC_CTX *frame = talloc_stackframe();
934 int ret = 0;
935 struct messaging_context *msg_ctx = NULL;
936 char *db_path;
937 bool ok;
939 state.first = true;
940 state.json_output = false;
941 state.resolve_uids = false;
943 smb_init_locale();
945 ok = samba_cmdline_init(frame,
946 SAMBA_CMDLINE_CONFIG_CLIENT,
947 false /* require_smbconf */);
948 if (!ok) {
949 DBG_ERR("Failed to init cmdline parser!\n");
950 TALLOC_FREE(frame);
951 exit(1);
953 lp_set_cmdline("log level", "0");
955 pc = samba_popt_get_context(getprogname(),
956 argc,
957 argv,
958 long_options,
959 POPT_CONTEXT_KEEP_FIRST);
960 if (pc == NULL) {
961 DBG_ERR("Failed to setup popt context!\n");
962 TALLOC_FREE(frame);
963 exit(1);
966 while ((c = poptGetNextOpt(pc)) != -1) {
967 switch (c) {
968 case 'p':
969 processes_only = true;
970 break;
971 case 'v':
972 verbose = true;
973 break;
974 case 'L':
975 locks_only = true;
976 break;
977 case 'S':
978 shares_only = true;
979 break;
980 case 'N':
981 show_notify = true;
982 break;
983 case 'b':
984 brief = true;
985 break;
986 case 'u':
987 Ucrit_addUid(nametouid(poptGetOptArg(pc)));
988 break;
989 case 'P':
990 case 'R':
991 profile_only = c;
992 break;
993 case 'B':
994 show_brl = true;
995 break;
996 case 'n':
997 numeric_only = true;
998 break;
999 case 'f':
1000 do_checks = false;
1001 break;
1002 case OPT_RESOLVE_UIDS:
1003 state.resolve_uids = true;
1004 break;
1005 case POPT_ERROR_BADOPT:
1006 fprintf(stderr, "\nInvalid option %s: %s\n\n",
1007 poptBadOption(pc, 0), poptStrerror(c));
1008 poptPrintUsage(pc, stderr, 0);
1009 exit(1);
1013 sec_init();
1015 #ifdef HAVE_JANSSON
1016 state.root_json = json_new_object();
1017 add_general_information_to_json(&state);
1018 #endif /* HAVE_JANSSON */
1020 if (getuid() != geteuid()) {
1021 fprintf(stderr, "smbstatus should not be run setuid\n");
1022 ret = 1;
1023 goto done;
1026 if (getuid() != 0) {
1027 fprintf(stderr, "smbstatus only works as root!\n");
1028 ret = 1;
1029 goto done;
1032 /* setup the flags based on the possible combincations */
1034 show_processes = !(shares_only || locks_only || profile_only) || processes_only;
1035 show_locks = !(shares_only || processes_only || profile_only) || locks_only;
1036 show_shares = !(processes_only || locks_only || profile_only) || shares_only;
1038 if ( username )
1039 Ucrit_addUid( nametouid(username) );
1041 if (verbose) {
1042 d_printf("using configfile = %s\n", get_dyn_CONFIGFILE());
1045 msg_ctx = cmdline_messaging_context(get_dyn_CONFIGFILE());
1046 if (msg_ctx == NULL) {
1047 fprintf(stderr, "Could not initialize messaging, not root?\n");
1048 ret = -1;
1049 goto done;
1052 switch (profile_only) {
1053 case 'P':
1054 /* Dump profile data */
1055 ok = status_profile_dump(verbose);
1056 ret = ok ? 0 : 1;
1057 goto done;
1058 case 'R':
1059 /* Continuously display rate-converted data */
1060 ok = status_profile_rates(verbose);
1061 ret = ok ? 0 : 1;
1062 goto done;
1063 default:
1064 break;
1067 if ( show_processes ) {
1068 prepare_sessionid(&state);
1069 sessionid_traverse_read(traverse_sessionid, &state);
1071 if (processes_only) {
1072 goto done;
1076 if ( show_shares ) {
1077 if (brief) {
1078 goto done;
1080 prepare_connections(&state);
1081 connections_forall_read(traverse_connections, &state);
1083 d_printf("\n");
1085 if ( shares_only ) {
1086 goto done;
1090 if ( show_locks ) {
1091 int result;
1092 struct db_context *db;
1094 db_path = lock_path(talloc_tos(), "locking.tdb");
1095 if (db_path == NULL) {
1096 fprintf(stderr, "Out of memory - exiting\n");
1097 ret = -1;
1098 goto done;
1101 db = db_open(NULL, db_path, 0,
1102 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDONLY, 0,
1103 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
1105 if (!db) {
1106 fprintf(stderr, "%s not initialised\n", db_path);
1107 fprintf(stderr, "This is normal if an SMB client has never "
1108 "connected to your server.\n");
1109 TALLOC_FREE(db_path);
1110 exit(0);
1111 } else {
1112 TALLOC_FREE(db);
1113 TALLOC_FREE(db_path);
1116 if (!locking_init_readonly()) {
1117 fprintf(stderr, "Can't initialise locking module - exiting\n");
1118 ret = 1;
1119 goto done;
1122 prepare_share_mode(&state);
1123 result = share_entry_forall(print_share_mode, &state);
1125 if (result == 0) {
1126 fprintf(stderr, "No locked files\n");
1127 } else if (result < 0) {
1128 fprintf(stderr, "locked file list truncated\n");
1131 d_printf("\n");
1133 if (show_brl) {
1134 prepare_brl(&state);
1135 brl_forall(print_brl, &state);
1138 locking_end();
1141 if (show_notify) {
1142 prepare_notify(&state);
1143 notify_walk(msg_ctx, print_notify_rec, &state);
1146 done:
1147 cmdline_messaging_context_free();
1148 poptFreeContext(pc);
1149 TALLOC_FREE(frame);
1150 return ret;