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