smbstatus: add service path to byte-range locks
[samba.git] / source3 / utils / status.c
1 /* 
2    Unix SMB/CIFS implementation.
3    status reporting
4    Copyright (C) Andrew Tridgell 1994-1998
5
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.
10
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.
15
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/>.
18
19    Revision History:
20
21    12 aug 96: Erik.Devriendt@te6.siemens.be
22    added support for shared memory implementation of share mode locking
23
24    21-Jul-1998: rsharpe@ns.aus.com (Richard Sharpe)
25    Added -L (locks only) -S (shares only) flags and code
26
27 */
28
29 /*
30  * This program reports current SMB connections
31  */
32
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"
57
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 */
63
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 */
69
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;
77
78 const char *username = NULL;
79
80 /* added by OH */
81 static void Ucrit_addUid(uid_t uid)
82 {
83         Ucrit_uid = uid;
84         Ucrit_IsActive = 1;
85 }
86
87 static unsigned int Ucrit_checkUid(uid_t uid)
88 {
89         if ( !Ucrit_IsActive ) 
90                 return 1;
91
92         if ( uid == Ucrit_uid ) 
93                 return 1;
94
95         return 0;
96 }
97
98 static unsigned int Ucrit_checkPid(struct server_id pid)
99 {
100         int i;
101
102         if ( !Ucrit_IsActive ) 
103                 return 1;
104
105         for (i=0;i<Ucrit_MaxPid;i++) {
106                 if (server_id_equal(&pid, &Ucrit_pid[i])) {
107                         return 1;
108                 }
109         }
110
111         return 0;
112 }
113
114 static bool Ucrit_addPid( struct server_id pid )
115 {
116         if ( !Ucrit_IsActive )
117                 return True;
118
119         if ( Ucrit_MaxPid >= SMB_MAXPIDS ) {
120                 fprintf(stderr, "ERROR: More than %d pids for user %s!\n",
121                          SMB_MAXPIDS, uidtoname(Ucrit_uid));
122
123                 return False;
124         }
125
126         Ucrit_pid[Ucrit_MaxPid++] = pid;
127
128         return True;
129 }
130
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)
141 {
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");
146
147                 state->first = false;
148         }
149
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;
154 }
155
156 static int prepare_share_mode(struct traverse_state *state)
157 {
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");
163         }
164         return 0;
165 }
166
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)
171 {
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         uint32_t lstate;
181         struct traverse_state *state = (struct traverse_state *)private_data;
182
183         TALLOC_CTX *tmp_ctx = talloc_stackframe();
184         if (tmp_ctx == NULL) {
185                 return -1;
186         }
187
188         if (do_checks && !is_valid_share_mode_entry(e)) {
189                 TALLOC_FREE(tmp_ctx);
190                 return 0;
191         }
192
193         if (do_checks && !serverid_exists(&e->pid)) {
194                 /* the process for this entry does not exist any more */
195                 TALLOC_FREE(tmp_ctx);
196                 return 0;
197         }
198
199         if (Ucrit_checkPid(e->pid)) {
200                 struct server_id_buf tmp;
201                 pid = server_id_str_buf(e->pid, &tmp);
202                 if (state->resolve_uids) {
203                         user_str = talloc_asprintf(tmp_ctx, "%s", uidtoname(e->uid));
204                 } else {
205                         user_str = talloc_asprintf(tmp_ctx, "%u", (unsigned int)e->uid);
206                 }
207                 if (user_str == NULL) {
208                         TALLOC_FREE(tmp_ctx);
209                         return -1;
210                 }
211
212                 denymode_int = map_share_mode_to_deny_mode(e->share_access,
213                                                            e->private_options);
214                 switch (denymode_int) {
215                         case DENY_NONE:
216                                 denymode = "DENY_NONE";
217                                 break;
218                         case DENY_ALL:
219                                 denymode = "DENY_ALL";
220                                 break;
221                         case DENY_DOS:
222                                 denymode = "DENY_DOS";
223                                 break;
224                         case DENY_READ:
225                                 denymode = "DENY_READ";
226                                 break;
227                         case DENY_WRITE:
228                                 denymode = "DENY_WRITE";
229                                 break;
230                         case DENY_FCB:
231                                 denymode = "DENY_FCB";
232                                 break;
233                         default: {
234                                 denymode = talloc_asprintf(tmp_ctx,
235                                                            "UNKNOWN(0x%08x)",
236                                                            denymode_int);
237                                 if (denymode == NULL) {
238                                         TALLOC_FREE(tmp_ctx);
239                                         return -1;
240                                 }
241                                 fprintf(stderr,
242                                         "unknown-please report ! "
243                                         "e->share_access = 0x%x, "
244                                         "e->private_options = 0x%x\n",
245                                         (unsigned int)e->share_access,
246                                         (unsigned int)e->private_options);
247                                 break;
248                         }
249                 }
250                 filename = talloc_asprintf(tmp_ctx,
251                                            "%s%s",
252                                            d->base_name,
253                                            (d->stream_name != NULL) ? d->stream_name : "");
254                 if (filename == NULL) {
255                         TALLOC_FREE(tmp_ctx);
256                         return -1;
257                 }
258                 if ((e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))==
259                                 (FILE_READ_DATA|FILE_WRITE_DATA)) {
260                         rw = "RDWR";
261                 } else if (e->access_mask & FILE_WRITE_DATA) {
262                         rw = "WRONLY";
263                 } else {
264                         rw = "RDONLY";
265                 }
266
267                 if (e->op_type & BATCH_OPLOCK) {
268                         oplock = "BATCH";
269                 } else if (e->op_type & EXCLUSIVE_OPLOCK) {
270                         oplock = "EXCLUSIVE";
271                 } else if (e->op_type & LEVEL_II_OPLOCK) {
272                         oplock = "LEVEL_II";
273                 } else if (e->op_type == LEASE_OPLOCK) {
274                         NTSTATUS status;
275
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 */
286
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";
297                         }
298                 } else {
299                         oplock = "NONE";
300                 }
301
302                 timestr = time_to_asc((time_t)e->time.tv_sec);
303
304                 if (!state->json_output) {
305                         print_share_mode_stdout(state,
306                                                 pid,
307                                                 user_str,
308                                                 denymode,
309                                                 (unsigned int)e->access_mask,
310                                                 rw,
311                                                 oplock,
312                                                 d->servicepath,
313                                                 filename,
314                                                 timestr);
315                 } else {
316                         print_share_mode_json(state,
317                                               d,
318                                               e,
319                                               fid,
320                                               user_str,
321                                               oplock,
322                                               lstate,
323                                               filename);
324                 }
325         }
326         TALLOC_FREE(tmp_ctx);
327         return 0;
328 }
329
330 static void print_brl_stdout(struct traverse_state *state,
331                              char *pid,
332                              char *id,
333                              const char *desc,
334                              intmax_t start,
335                              intmax_t size,
336                              const char *sharepath,
337                              char *fname)
338 {
339         if (state->first) {
340                 d_printf("Byte range locks:\n");
341                 d_printf("Pid        dev:inode       R/W  start     size      SharePath               Name\n");
342                 d_printf("--------------------------------------------------------------------------------\n");
343
344                 state->first = false;
345         }
346         d_printf("%-10s %-15s %-4s %-9jd %-9jd %-24s %-24s\n",
347                  pid, id, desc, start, size, sharepath, fname);
348 }
349
350 static int prepare_brl(struct traverse_state *state)
351 {
352         /* only print header line if there are locked files */
353         state->first = true;
354
355         return 0;
356 }
357
358 static void print_brl(struct file_id id,
359                         struct server_id pid, 
360                         enum brl_type lock_type,
361                         enum brl_flavour lock_flav,
362                         br_off start,
363                         br_off size,
364                         void *private_data)
365 {
366         unsigned int i;
367         static const struct {
368                 enum brl_type lock_type;
369                 const char *desc;
370         } lock_types[] = {
371                 { READ_LOCK, "R" },
372                 { WRITE_LOCK, "W" },
373                 { UNLOCK_LOCK, "U" }
374         };
375         const char *desc="X";
376         const char *sharepath = "";
377         char *fname = NULL;
378         struct share_mode_lock *share_mode;
379         struct server_id_buf tmp;
380         struct file_id_buf ftmp;
381         struct traverse_state *state = (struct traverse_state *)private_data;
382
383         share_mode = fetch_share_mode_unlocked(NULL, id);
384         if (share_mode) {
385                 fname = share_mode_filename(NULL, share_mode);
386                 sharepath = share_mode_servicepath(share_mode);
387         } else {
388                 fname = talloc_strdup(NULL, "");
389                 if (fname == NULL) {
390                         return;
391                 }
392         }
393
394         for (i=0;i<ARRAY_SIZE(lock_types);i++) {
395                 if (lock_type == lock_types[i].lock_type) {
396                         desc = lock_types[i].desc;
397                 }
398         }
399
400         print_brl_stdout(state,
401                          server_id_str_buf(pid, &tmp),
402                          file_id_str_buf(id, &ftmp),
403                          desc,
404                          (intmax_t)start,
405                          (intmax_t)size,
406                          sharepath,
407                          fname);
408
409         TALLOC_FREE(fname);
410         TALLOC_FREE(share_mode);
411 }
412
413 static const char *session_dialect_str(uint16_t dialect)
414 {
415         static fstring unknown_dialect;
416
417         switch(dialect){
418         case SMB2_DIALECT_REVISION_000:
419                 return "NT1";
420         case SMB2_DIALECT_REVISION_202:
421                 return "SMB2_02";
422         case SMB2_DIALECT_REVISION_210:
423                 return "SMB2_10";
424         case SMB2_DIALECT_REVISION_222:
425                 return "SMB2_22";
426         case SMB2_DIALECT_REVISION_224:
427                 return "SMB2_24";
428         case SMB3_DIALECT_REVISION_300:
429                 return "SMB3_00";
430         case SMB3_DIALECT_REVISION_302:
431                 return "SMB3_02";
432         case SMB3_DIALECT_REVISION_310:
433                 return "SMB3_10";
434         case SMB3_DIALECT_REVISION_311:
435                 return "SMB3_11";
436         }
437
438         fstr_sprintf(unknown_dialect, "Unknown (0x%04x)", dialect);
439         return unknown_dialect;
440 }
441
442 static int traverse_connections_stdout(struct traverse_state *state,
443                                        const char *servicename,
444                                        char *server_id,
445                                        const char *machine,
446                                        const char *timestr,
447                                        const char *encryption,
448                                        const char *signing)
449 {
450         d_printf("%-12s %-7s %-13s %-32s %-12s %-12s\n",
451                  servicename, server_id, machine, timestr, encryption, signing);
452
453         return 0;
454 }
455
456 static int prepare_connections(struct traverse_state *state)
457 {
458         if (!state->json_output) {
459                 /* always print header line */
460                 d_printf("\n%-12s %-7s %-13s %-32s %-12s %-12s\n", "Service", "pid", "Machine", "Connected at", "Encryption", "Signing");
461                 d_printf("---------------------------------------------------------------------------------------------\n");
462         } else {
463                 add_section_to_json(state, "tcons");
464         }
465         return 0;
466 }
467
468 static int traverse_connections(const struct connections_data *crec,
469                                 void *private_data)
470 {
471         struct server_id_buf tmp;
472         char *timestr = NULL;
473         int result = 0;
474         const char *encryption = "-";
475         enum crypto_degree encryption_degree = CRYPTO_DEGREE_NONE;
476         const char *signing = "-";
477         enum crypto_degree signing_degree = CRYPTO_DEGREE_NONE;
478         struct traverse_state *state = (struct traverse_state *)private_data;
479
480         TALLOC_CTX *tmp_ctx = talloc_stackframe();
481         if (tmp_ctx == NULL) {
482                 return -1;
483         }
484
485         if (crec->cnum == TID_FIELD_INVALID) {
486                 TALLOC_FREE(tmp_ctx);
487                 return 0;
488         }
489
490         if (do_checks &&
491             (!process_exists(crec->pid) || !Ucrit_checkUid(crec->uid))) {
492                 TALLOC_FREE(tmp_ctx);
493                 return 0;
494         }
495
496         timestr = timestring(tmp_ctx, nt_time_to_unix(crec->start));
497         if (timestr == NULL) {
498                 TALLOC_FREE(tmp_ctx);
499                 return -1;
500         }
501
502         if (smbXsrv_is_encrypted(crec->encryption_flags)) {
503                 switch (crec->cipher) {
504                 case SMB_ENCRYPTION_GSSAPI:
505                         encryption = "GSSAPI";
506                         break;
507                 case SMB2_ENCRYPTION_AES128_CCM:
508                         encryption = "AES-128-CCM";
509                         break;
510                 case SMB2_ENCRYPTION_AES128_GCM:
511                         encryption = "AES-128-GCM";
512                         break;
513                 default:
514                         encryption = "???";
515                         result = -1;
516                         break;
517                 }
518                 encryption_degree = CRYPTO_DEGREE_FULL;
519         }
520
521         if (smbXsrv_is_signed(crec->signing_flags)) {
522                 switch (crec->signing) {
523                 case SMB2_SIGNING_MD5_SMB1:
524                         signing = "HMAC-MD5";
525                         break;
526                 case SMB2_SIGNING_HMAC_SHA256:
527                         signing = "HMAC-SHA256";
528                         break;
529                 case SMB2_SIGNING_AES128_CMAC:
530                         signing = "AES-128-CMAC";
531                         break;
532                 case SMB2_SIGNING_AES128_GMAC:
533                         signing = "AES-128-GMAC";
534                         break;
535                 default:
536                         signing = "???";
537                         result = -1;
538                         break;
539                 }
540                 signing_degree = CRYPTO_DEGREE_FULL;
541         }
542
543         if (!state->json_output) {
544                 result = traverse_connections_stdout(state,
545                                                      crec->servicename,
546                                                      server_id_str_buf(crec->pid, &tmp),
547                                                      crec->machine,
548                                                      timestr,
549                                                      encryption,
550                                                      signing);
551         } else {
552                 result = traverse_connections_json(state,
553                                                    crec,
554                                                    encryption,
555                                                    encryption_degree,
556                                                    signing,
557                                                    signing_degree);
558         }
559
560         TALLOC_FREE(timestr);
561         TALLOC_FREE(tmp_ctx);
562
563         return result;
564 }
565
566 static int traverse_sessionid_stdout(struct traverse_state *state,
567                                      char *server_id,
568                                      char *uid_gid_str,
569                                      char *machine_hostname,
570                                      const char *dialect,
571                                      const char *encryption_cipher,
572                                      enum crypto_degree encryption_degree,
573                                      const char *signing_cipher,
574                                      enum crypto_degree signing_degree)
575 {
576         fstring encryption;
577         fstring signing;
578
579         if (encryption_degree == CRYPTO_DEGREE_FULL) {
580                 fstr_sprintf(encryption, "%s", encryption_cipher);
581         } else if (encryption_degree == CRYPTO_DEGREE_PARTIAL) {
582                 fstr_sprintf(encryption, "partial(%s)", encryption_cipher);
583         } else {
584                 fstr_sprintf(encryption, "-");
585         }
586         if (signing_degree == CRYPTO_DEGREE_FULL) {
587                 fstr_sprintf(signing, "%s", signing_cipher);
588         } else if (signing_degree == CRYPTO_DEGREE_PARTIAL) {
589                 fstr_sprintf(signing, "partial(%s)", signing_cipher);
590         } else {
591                 fstr_sprintf(signing, "-");
592         }
593
594         d_printf("%-7s %-25s %-41s %-17s %-20s %-21s\n",
595                  server_id, uid_gid_str, machine_hostname, dialect, encryption,
596                  signing);
597
598         return 0;
599 }
600
601 static int prepare_sessionid(struct traverse_state *state)
602 {
603         if (!state->json_output) {
604                 /* always print header line */
605                 d_printf("\nSamba version %s\n",samba_version_string());
606                 d_printf("%-7s %-12s %-12s %-41s %-17s %-20s %-21s\n", "PID", "Username", "Group", "Machine", "Protocol Version", "Encryption", "Signing");
607                 d_printf("----------------------------------------------------------------------------------------------------------------------------------------\n");
608         } else {
609                 add_section_to_json(state, "sessions");
610         }
611         return 0;
612
613 }
614
615 static int traverse_sessionid(const char *key, struct sessionid *session,
616                               void *private_data)
617 {
618         fstring uid_gid_str;
619         fstring uid_str;
620         fstring gid_str;
621         struct server_id_buf tmp;
622         char *machine_hostname = NULL;
623         int result = 0;
624         const char *encryption = "-";
625         enum crypto_degree encryption_degree = CRYPTO_DEGREE_NONE;
626         const char *signing = "-";
627         enum crypto_degree signing_degree = CRYPTO_DEGREE_NONE;
628         struct traverse_state *state = (struct traverse_state *)private_data;
629
630         TALLOC_CTX *tmp_ctx = talloc_stackframe();
631         if (tmp_ctx == NULL) {
632                 return -1;
633         }
634
635         if (do_checks &&
636             (!process_exists(session->pid) ||
637              !Ucrit_checkUid(session->uid))) {
638                 TALLOC_FREE(tmp_ctx);
639                 return 0;
640         }
641
642         Ucrit_addPid(session->pid);
643
644         if (numeric_only) {
645                 fstr_sprintf(gid_str, "%u", (unsigned int)session->gid);
646                 fstr_sprintf(uid_str, "%u", (unsigned int)session->uid);
647                 fstr_sprintf(uid_gid_str, "%-12u %-12u",
648                              (unsigned int)session->uid,
649                              (unsigned int)session->gid);
650         } else {
651                 if (session->uid == -1 && session->gid == -1) {
652                         /*
653                          * The session is not fully authenticated yet.
654                          */
655                         fstrcpy(uid_gid_str, "(auth in progress)");
656                         fstrcpy(gid_str, "(auth in progress)");
657                         fstrcpy(uid_str, "(auth in progress)");
658                 } else {
659                         /*
660                          * In theory it should not happen that one of
661                          * session->uid and session->gid is valid (ie != -1)
662                          * while the other is not (ie = -1), so we a check for
663                          * that case that bails out would be reasonable.
664                          */
665                         const char *uid_name = "-1";
666                         const char *gid_name = "-1";
667
668                         if (session->uid != -1) {
669                                 uid_name = uidtoname(session->uid);
670                                 if (uid_name == NULL) {
671                                         TALLOC_FREE(tmp_ctx);
672                                         return -1;
673                                 }
674                         }
675                         if (session->gid != -1) {
676                                 gid_name = gidtoname(session->gid);
677                                 if (gid_name == NULL) {
678                                         TALLOC_FREE(tmp_ctx);
679                                         return -1;
680                                 }
681                         }
682                         fstr_sprintf(gid_str, "%s", gid_name);
683                         fstr_sprintf(uid_str, "%s", uid_name);
684                         fstr_sprintf(uid_gid_str, "%-12s %-12s",
685                                      uid_name, gid_name);
686                 }
687         }
688
689         machine_hostname = talloc_asprintf(tmp_ctx, "%s (%s)",
690                                            session->remote_machine,
691                                            session->hostname);
692         if (machine_hostname == NULL) {
693                 TALLOC_FREE(tmp_ctx);
694                 return -1;
695         }
696
697         if (smbXsrv_is_encrypted(session->encryption_flags) ||
698                         smbXsrv_is_partially_encrypted(session->encryption_flags)) {
699                 switch (session->cipher) {
700                 case SMB2_ENCRYPTION_AES128_CCM:
701                         encryption = "AES-128-CCM";
702                         break;
703                 case SMB2_ENCRYPTION_AES128_GCM:
704                         encryption = "AES-128-GCM";
705                         break;
706                 case SMB2_ENCRYPTION_AES256_CCM:
707                         encryption = "AES-256-CCM";
708                         break;
709                 case SMB2_ENCRYPTION_AES256_GCM:
710                         encryption = "AES-256-GCM";
711                         break;
712                 default:
713                         encryption = "???";
714                         result = -1;
715                         break;
716                 }
717                 if (smbXsrv_is_encrypted(session->encryption_flags)) {
718                         encryption_degree = CRYPTO_DEGREE_FULL;
719                 } else if (smbXsrv_is_partially_encrypted(session->encryption_flags)) {
720                         encryption_degree = CRYPTO_DEGREE_PARTIAL;
721                 }
722         }
723
724         if (smbXsrv_is_signed(session->signing_flags) ||
725                         smbXsrv_is_partially_signed(session->signing_flags)) {
726                 switch (session->signing) {
727                 case SMB2_SIGNING_MD5_SMB1:
728                         signing = "HMAC-MD5";
729                         break;
730                 case SMB2_SIGNING_HMAC_SHA256:
731                         signing = "HMAC-SHA256";
732                         break;
733                 case SMB2_SIGNING_AES128_CMAC:
734                         signing = "AES-128-CMAC";
735                         break;
736                 case SMB2_SIGNING_AES128_GMAC:
737                         signing = "AES-128-GMAC";
738                         break;
739                 default:
740                         signing = "???";
741                         result = -1;
742                         break;
743                 }
744                 if (smbXsrv_is_signed(session->signing_flags)) {
745                         signing_degree = CRYPTO_DEGREE_FULL;
746                 } else if (smbXsrv_is_partially_signed(session->signing_flags)) {
747                         signing_degree = CRYPTO_DEGREE_PARTIAL;
748                 }
749         }
750
751
752         if (!state->json_output) {
753                 traverse_sessionid_stdout(state,
754                          server_id_str_buf(session->pid, &tmp),
755                          uid_gid_str,
756                          machine_hostname,
757                          session_dialect_str(session->connection_dialect),
758                          encryption,
759                          encryption_degree,
760                          signing,
761                          signing_degree);
762         } else {
763                 result = traverse_sessionid_json(state,
764                                                  session,
765                                                  uid_str,
766                                                  gid_str,
767                                                  encryption,
768                                                  encryption_degree,
769                                                  signing,
770                                                  signing_degree,
771                                                  session_dialect_str(session->connection_dialect));
772         }
773
774         TALLOC_FREE(machine_hostname);
775         TALLOC_FREE(tmp_ctx);
776
777         return result;
778 }
779
780
781 static bool print_notify_rec_stdout(struct traverse_state *state,
782                                     const char *path,
783                                     char *server_id_str,
784                                     unsigned filter,
785                                     unsigned subdir_filter)
786 {
787         d_printf("%s\\%s\\%x\\%x\n", path, server_id_str,
788                  filter, subdir_filter);
789
790         return true;
791 }
792
793 static int prepare_notify(struct traverse_state *state)
794 {
795         /* don't print header line */
796
797         return 0;
798 }
799
800 static bool print_notify_rec(const char *path, struct server_id server,
801                              const struct notify_instance *instance,
802                              void *private_data)
803 {
804         struct server_id_buf idbuf;
805         struct traverse_state *state = (struct traverse_state *)private_data;
806         bool result;
807
808         result = print_notify_rec_stdout(state,
809                                          path,
810                                          server_id_str_buf(server, &idbuf),
811                                          (unsigned)instance->filter,
812                                          (unsigned)instance->subdir_filter);
813
814         return result;
815 }
816
817 enum {
818         OPT_RESOLVE_UIDS = 1000,
819 };
820
821 int main(int argc, const char *argv[])
822 {
823         int c;
824         int profile_only = 0;
825         bool show_processes, show_locks, show_shares;
826         bool show_notify = false;
827         poptContext pc = NULL;
828         struct traverse_state state = {0};
829         struct poptOption long_options[] = {
830                 POPT_AUTOHELP
831                 {
832                         .longName   = "processes",
833                         .shortName  = 'p',
834                         .argInfo    = POPT_ARG_NONE,
835                         .arg        = NULL,
836                         .val        = 'p',
837                         .descrip    = "Show processes only",
838                 },
839                 {
840                         .longName   = "verbose",
841                         .shortName  = 'v',
842                         .argInfo    = POPT_ARG_NONE,
843                         .arg        = NULL,
844                         .val        = 'v',
845                         .descrip    = "Be verbose",
846                 },
847                 {
848                         .longName   = "locks",
849                         .shortName  = 'L',
850                         .argInfo    = POPT_ARG_NONE,
851                         .arg        = NULL,
852                         .val        = 'L',
853                         .descrip    = "Show locks only",
854                 },
855                 {
856                         .longName   = "shares",
857                         .shortName  = 'S',
858                         .argInfo    = POPT_ARG_NONE,
859                         .arg        = NULL,
860                         .val        = 'S',
861                         .descrip    = "Show shares only",
862                 },
863                 {
864                         .longName   = "notify",
865                         .shortName  = 'N',
866                         .argInfo    = POPT_ARG_NONE,
867                         .arg        = NULL,
868                         .val        = 'N',
869                         .descrip    = "Show notifies",
870                 },
871                 {
872                         .longName   = "user",
873                         .shortName  = 'u',
874                         .argInfo    = POPT_ARG_STRING,
875                         .arg        = &username,
876                         .val        = 'u',
877                         .descrip    = "Switch to user",
878                 },
879                 {
880                         .longName   = "brief",
881                         .shortName  = 'b',
882                         .argInfo    = POPT_ARG_NONE,
883                         .arg        = NULL,
884                         .val        = 'b',
885                         .descrip    = "Be brief",
886                 },
887                 {
888                         .longName   = "profile",
889                         .shortName  =     'P',
890                         .argInfo    = POPT_ARG_NONE,
891                         .arg        = NULL,
892                         .val        = 'P',
893                         .descrip    = "Do profiling",
894                 },
895                 {
896                         .longName   = "profile-rates",
897                         .shortName  = 'R',
898                         .argInfo    = POPT_ARG_NONE,
899                         .arg        = NULL,
900                         .val        = 'R',
901                         .descrip    = "Show call rates",
902                 },
903                 {
904                         .longName   = "byterange",
905                         .shortName  = 'B',
906                         .argInfo    = POPT_ARG_NONE,
907                         .arg        = NULL,
908                         .val        = 'B',
909                         .descrip    = "Include byte range locks"
910                 },
911                 {
912                         .longName   = "numeric",
913                         .shortName  = 'n',
914                         .argInfo    = POPT_ARG_NONE,
915                         .arg        = NULL,
916                         .val        = 'n',
917                         .descrip    = "Numeric uid/gid"
918                 },
919                 {
920                         .longName   = "fast",
921                         .shortName  = 'f',
922                         .argInfo    = POPT_ARG_NONE,
923                         .arg        = NULL,
924                         .val        = 'f',
925                         .descrip    = "Skip checks if processes still exist"
926                 },
927                 {
928                         .longName   = "resolve-uids",
929                         .shortName  = 0,
930                         .argInfo    = POPT_ARG_NONE,
931                         .arg        = NULL,
932                         .val        = OPT_RESOLVE_UIDS,
933                         .descrip    = "Try to resolve UIDs to usernames"
934                 },
935                 POPT_COMMON_SAMBA
936                 POPT_COMMON_VERSION
937                 POPT_TABLEEND
938         };
939         TALLOC_CTX *frame = talloc_stackframe();
940         int ret = 0;
941         struct messaging_context *msg_ctx = NULL;
942         char *db_path;
943         bool ok;
944
945         state.first = true;
946         state.json_output = false;
947         state.resolve_uids = false;
948
949         smb_init_locale();
950
951         ok = samba_cmdline_init(frame,
952                                 SAMBA_CMDLINE_CONFIG_CLIENT,
953                                 false /* require_smbconf */);
954         if (!ok) {
955                 DBG_ERR("Failed to init cmdline parser!\n");
956                 TALLOC_FREE(frame);
957                 exit(1);
958         }
959         lp_set_cmdline("log level", "0");
960
961         pc = samba_popt_get_context(getprogname(),
962                                     argc,
963                                     argv,
964                                     long_options,
965                                     POPT_CONTEXT_KEEP_FIRST);
966         if (pc == NULL) {
967                 DBG_ERR("Failed to setup popt context!\n");
968                 TALLOC_FREE(frame);
969                 exit(1);
970         }
971
972         while ((c = poptGetNextOpt(pc)) != -1) {
973                 switch (c) {
974                 case 'p':
975                         processes_only = true;
976                         break;
977                 case 'v':
978                         verbose = true;
979                         break;
980                 case 'L':
981                         locks_only = true;
982                         break;
983                 case 'S':
984                         shares_only = true;
985                         break;
986                 case 'N':
987                         show_notify = true;
988                         break;
989                 case 'b':
990                         brief = true;
991                         break;
992                 case 'u':
993                         Ucrit_addUid(nametouid(poptGetOptArg(pc)));
994                         break;
995                 case 'P':
996                 case 'R':
997                         profile_only = c;
998                         break;
999                 case 'B':
1000                         show_brl = true;
1001                         break;
1002                 case 'n':
1003                         numeric_only = true;
1004                         break;
1005                 case 'f':
1006                         do_checks = false;
1007                         break;
1008                 case OPT_RESOLVE_UIDS:
1009                         state.resolve_uids = true;
1010                         break;
1011                 case POPT_ERROR_BADOPT:
1012                         fprintf(stderr, "\nInvalid option %s: %s\n\n",
1013                                 poptBadOption(pc, 0), poptStrerror(c));
1014                         poptPrintUsage(pc, stderr, 0);
1015                         exit(1);
1016                 }
1017         }
1018
1019         sec_init();
1020
1021 #ifdef HAVE_JANSSON
1022         state.root_json = json_new_object();
1023         add_general_information_to_json(&state);
1024 #endif /* HAVE_JANSSON */
1025
1026         if (getuid() != geteuid()) {
1027                 fprintf(stderr, "smbstatus should not be run setuid\n");
1028                 ret = 1;
1029                 goto done;
1030         }
1031
1032         if (getuid() != 0) {
1033                 fprintf(stderr, "smbstatus only works as root!\n");
1034                 ret = 1;
1035                 goto done;
1036         }
1037
1038         /* setup the flags based on the possible combincations */
1039
1040         show_processes = !(shares_only || locks_only || profile_only) || processes_only;
1041         show_locks     = !(shares_only || processes_only || profile_only) || locks_only;
1042         show_shares    = !(processes_only || locks_only || profile_only) || shares_only;
1043
1044         if ( username )
1045                 Ucrit_addUid( nametouid(username) );
1046
1047         if (verbose) {
1048                 d_printf("using configfile = %s\n", get_dyn_CONFIGFILE());
1049         }
1050
1051         msg_ctx = cmdline_messaging_context(get_dyn_CONFIGFILE());
1052         if (msg_ctx == NULL) {
1053                 fprintf(stderr, "Could not initialize messaging, not root?\n");
1054                 ret = -1;
1055                 goto done;
1056         }
1057
1058         switch (profile_only) {
1059                 case 'P':
1060                         /* Dump profile data */
1061                         ok = status_profile_dump(verbose);
1062                         ret = ok ? 0 : 1;
1063                         goto done;
1064                 case 'R':
1065                         /* Continuously display rate-converted data */
1066                         ok = status_profile_rates(verbose);
1067                         ret = ok ? 0 : 1;
1068                         goto done;
1069                 default:
1070                         break;
1071         }
1072
1073         if ( show_processes ) {
1074                 prepare_sessionid(&state);
1075                 sessionid_traverse_read(traverse_sessionid, &state);
1076
1077                 if (processes_only) {
1078                         goto done;
1079                 }
1080         }
1081
1082         if ( show_shares ) {
1083                 if (brief) {
1084                         goto done;
1085                 }
1086                 prepare_connections(&state);
1087                 connections_forall_read(traverse_connections, &state);
1088
1089                 d_printf("\n");
1090
1091                 if ( shares_only ) {
1092                         goto done;
1093                 }
1094         }
1095
1096         if ( show_locks ) {
1097                 int result;
1098                 struct db_context *db;
1099
1100                 db_path = lock_path(talloc_tos(), "locking.tdb");
1101                 if (db_path == NULL) {
1102                         fprintf(stderr, "Out of memory - exiting\n");
1103                         ret = -1;
1104                         goto done;
1105                 }
1106
1107                 db = db_open(NULL, db_path, 0,
1108                              TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDONLY, 0,
1109                              DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
1110
1111                 if (!db) {
1112                         fprintf(stderr, "%s not initialised\n", db_path);
1113                         fprintf(stderr, "This is normal if an SMB client has never "
1114                                  "connected to your server.\n");
1115                         TALLOC_FREE(db_path);
1116                         exit(0);
1117                 } else {
1118                         TALLOC_FREE(db);
1119                         TALLOC_FREE(db_path);
1120                 }
1121
1122                 if (!locking_init_readonly()) {
1123                         fprintf(stderr, "Can't initialise locking module - exiting\n");
1124                         ret = 1;
1125                         goto done;
1126                 }
1127
1128                 prepare_share_mode(&state);
1129                 result = share_entry_forall(print_share_mode, &state);
1130
1131                 if (result == 0) {
1132                         fprintf(stderr, "No locked files\n");
1133                 } else if (result < 0) {
1134                         fprintf(stderr, "locked file list truncated\n");
1135                 }
1136
1137                 d_printf("\n");
1138
1139                 if (show_brl) {
1140                         prepare_brl(&state);
1141                         brl_forall(print_brl, &state);
1142                 }
1143
1144                 locking_end();
1145         }
1146
1147         if (show_notify) {
1148                 prepare_notify(&state);
1149                 notify_walk(msg_ctx, print_notify_rec, &state);
1150         }
1151
1152 done:
1153         cmdline_messaging_context_free();
1154         poptFreeContext(pc);
1155         TALLOC_FREE(frame);
1156         return ret;
1157 }