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