s3:open_files.idl: add data structures for SMB2.1 and SMB3.0 leases.
[metze/samba/wip.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 "system/filesys.h"
35 #include "popt_common.h"
36 #include "dbwrap/dbwrap.h"
37 #include "dbwrap/dbwrap_open.h"
38 #include "../libcli/security/security.h"
39 #include "session.h"
40 #include "locking/proto.h"
41 #include "messages.h"
42 #include "librpc/gen_ndr/open_files.h"
43 #include "smbd/smbd.h"
44 #include "librpc/gen_ndr/notify.h"
45 #include "lib/conn_tdb.h"
46 #include "serverid.h"
47 #include "status_profile.h"
48
49 #define SMB_MAXPIDS             2048
50 static uid_t            Ucrit_uid = 0;               /* added by OH */
51 static struct server_id Ucrit_pid[SMB_MAXPIDS];  /* Ugly !!! */   /* added by OH */
52 static int              Ucrit_MaxPid=0;                    /* added by OH */
53 static unsigned int     Ucrit_IsActive = 0;                /* added by OH */
54
55 static bool verbose, brief;
56 static bool shares_only;            /* Added by RJS */
57 static bool locks_only;            /* Added by RJS */
58 static bool processes_only;
59 static bool show_brl;
60 static bool numeric_only;
61 static bool do_checks = true;
62
63 const char *username = NULL;
64
65 /* added by OH */
66 static void Ucrit_addUid(uid_t uid)
67 {
68         Ucrit_uid = uid;
69         Ucrit_IsActive = 1;
70 }
71
72 static unsigned int Ucrit_checkUid(uid_t uid)
73 {
74         if ( !Ucrit_IsActive ) 
75                 return 1;
76
77         if ( uid == Ucrit_uid ) 
78                 return 1;
79
80         return 0;
81 }
82
83 static unsigned int Ucrit_checkPid(struct server_id pid)
84 {
85         int i;
86
87         if ( !Ucrit_IsActive ) 
88                 return 1;
89
90         for (i=0;i<Ucrit_MaxPid;i++) {
91                 if (serverid_equal(&pid, &Ucrit_pid[i])) {
92                         return 1;
93                 }
94         }
95
96         return 0;
97 }
98
99 static bool Ucrit_addPid( struct server_id pid )
100 {
101         if ( !Ucrit_IsActive )
102                 return True;
103
104         if ( Ucrit_MaxPid >= SMB_MAXPIDS ) {
105                 d_printf("ERROR: More than %d pids for user %s!\n",
106                          SMB_MAXPIDS, uidtoname(Ucrit_uid));
107
108                 return False;
109         }
110
111         Ucrit_pid[Ucrit_MaxPid++] = pid;
112
113         return True;
114 }
115
116 static int print_share_mode(const struct share_mode_entry *e,
117                             const char *sharepath,
118                             const char *fname,
119                             void *dummy)
120 {
121         static int count;
122
123         if (do_checks && !is_valid_share_mode_entry(e)) {
124                 return 0;
125         }
126
127         if (count==0) {
128                 d_printf("Locked files:\n");
129                 d_printf("Pid          Uid        DenyMode   Access      R/W        Oplock           SharePath   Name   Time\n");
130                 d_printf("--------------------------------------------------------------------------------------------------\n");
131         }
132         count++;
133
134         if (do_checks && !serverid_exists(&e->pid)) {
135                 /* the process for this entry does not exist any more */
136                 return 0;
137         }
138
139         if (Ucrit_checkPid(e->pid)) {
140                 d_printf("%-11s  ",procid_str_static(&e->pid));
141                 d_printf("%-9u  ", (unsigned int)e->uid);
142                 switch (map_share_mode_to_deny_mode(e->share_access,
143                                                     e->private_options)) {
144                         case DENY_NONE: d_printf("DENY_NONE  "); break;
145                         case DENY_ALL:  d_printf("DENY_ALL   "); break;
146                         case DENY_DOS:  d_printf("DENY_DOS   "); break;
147                         case DENY_READ: d_printf("DENY_READ  "); break;
148                         case DENY_WRITE:printf("DENY_WRITE "); break;
149                         case DENY_FCB:  d_printf("DENY_FCB "); break;
150                         default: {
151                                 d_printf("unknown-please report ! "
152                                          "e->share_access = 0x%x, "
153                                          "e->private_options = 0x%x\n",
154                                          (unsigned int)e->share_access,
155                                          (unsigned int)e->private_options );
156                                 break;
157                         }
158                 }
159                 d_printf("0x%-8x  ",(unsigned int)e->access_mask);
160                 if ((e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))==
161                                 (FILE_READ_DATA|FILE_WRITE_DATA)) {
162                         d_printf("RDWR       ");
163                 } else if (e->access_mask & FILE_WRITE_DATA) {
164                         d_printf("WRONLY     ");
165                 } else {
166                         d_printf("RDONLY     ");
167                 }
168
169                 if((e->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == 
170                                         (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) {
171                         d_printf("EXCLUSIVE+BATCH ");
172                 } else if (e->op_type & EXCLUSIVE_OPLOCK) {
173                         d_printf("EXCLUSIVE       ");
174                 } else if (e->op_type & BATCH_OPLOCK) {
175                         d_printf("BATCH           ");
176                 } else if (e->op_type & LEVEL_II_OPLOCK) {
177                         d_printf("LEVEL_II        ");
178                 } else if (e->op_type == LEASE_OPLOCK) {
179                         uint32_t lstate = e->lease->current_state;
180                         d_printf("LEASE(%s%s%s)%s%s%s      ",
181                                  (lstate & SMB2_LEASE_READ)?"R":"",
182                                  (lstate & SMB2_LEASE_WRITE)?"W":"",
183                                  (lstate & SMB2_LEASE_HANDLE)?"H":"",
184                                  (lstate & SMB2_LEASE_READ)?"":" ",
185                                  (lstate & SMB2_LEASE_WRITE)?"":" ",
186                                  (lstate & SMB2_LEASE_HANDLE)?"":" ");
187                 } else {
188                         d_printf("NONE            ");
189                 }
190
191                 d_printf(" %s   %s   %s",sharepath, fname, time_to_asc((time_t)e->time.tv_sec));
192         }
193
194         return 0;
195 }
196
197 static void print_brl(struct file_id id,
198                         struct server_id pid, 
199                         enum brl_type lock_type,
200                         enum brl_flavour lock_flav,
201                         br_off start,
202                         br_off size,
203                         void *private_data)
204 {
205         static int count;
206         unsigned int i;
207         static const struct {
208                 enum brl_type lock_type;
209                 const char *desc;
210         } lock_types[] = {
211                 { READ_LOCK, "R" },
212                 { WRITE_LOCK, "W" },
213                 { PENDING_READ_LOCK, "PR" },
214                 { PENDING_WRITE_LOCK, "PW" },
215                 { UNLOCK_LOCK, "U" }
216         };
217         const char *desc="X";
218         const char *sharepath = "";
219         char *fname = NULL;
220         struct share_mode_lock *share_mode;
221
222         if (count==0) {
223                 d_printf("Byte range locks:\n");
224                 d_printf("Pid        dev:inode       R/W  start     size      SharePath               Name\n");
225                 d_printf("--------------------------------------------------------------------------------\n");
226         }
227         count++;
228
229         share_mode = fetch_share_mode_unlocked(NULL, id);
230         if (share_mode) {
231                 bool has_stream = share_mode->data->stream_name != NULL;
232
233                 fname = talloc_asprintf(NULL, "%s%s%s",
234                                         share_mode->data->base_name,
235                                         has_stream ? ":" : "",
236                                         has_stream ?
237                                         share_mode->data->stream_name :
238                                         "");
239         } else {
240                 fname = talloc_strdup(NULL, "");
241                 if (fname == NULL) {
242                         return;
243                 }
244         }
245
246         for (i=0;i<ARRAY_SIZE(lock_types);i++) {
247                 if (lock_type == lock_types[i].lock_type) {
248                         desc = lock_types[i].desc;
249                 }
250         }
251
252         d_printf("%-10s %-15s %-4s %-9jd %-9jd %-24s %-24s\n",
253                  procid_str_static(&pid), file_id_string_tos(&id),
254                  desc,
255                  (intmax_t)start, (intmax_t)size,
256                  sharepath, fname);
257
258         TALLOC_FREE(fname);
259         TALLOC_FREE(share_mode);
260 }
261
262 static int traverse_connections(const struct connections_key *key,
263                                 const struct connections_data *crec,
264                                 void *state)
265 {
266         if (crec->cnum == TID_FIELD_INVALID)
267                 return 0;
268
269         if (do_checks &&
270             (!process_exists(crec->pid) || !Ucrit_checkUid(crec->uid))) {
271                 return 0;
272         }
273
274         d_printf("%-10s   %s   %-12s  %s",
275                  crec->servicename,procid_str_static(&crec->pid),
276                  crec->machine,
277                  time_to_asc(crec->start));
278
279         return 0;
280 }
281
282 static int traverse_sessionid(const char *key, struct sessionid *session,
283                               void *private_data)
284 {
285         fstring uid_str, gid_str;
286
287         if (do_checks &&
288             (!process_exists(session->pid) ||
289              !Ucrit_checkUid(session->uid))) {
290                 return 0;
291         }
292
293         Ucrit_addPid(session->pid);
294
295         fstrcpy(uid_str, "-1");
296
297         if (session->uid != -1) {
298                 if (numeric_only) {
299                         fstr_sprintf(uid_str, "%u", (unsigned int)session->uid);
300                 } else {
301                         fstrcpy(uid_str, uidtoname(session->uid));
302                 }
303         }
304
305         fstrcpy(gid_str, "-1");
306
307         if (session->gid != -1) {
308                 if (numeric_only) {
309                         fstr_sprintf(gid_str, "%u", (unsigned int)session->gid);
310                 } else {
311                         fstrcpy(gid_str, gidtoname(session->gid));
312                 }
313         }
314
315         d_printf("%-7s   %-12s  %-12s  %-12s (%s) %-12s\n",
316                  procid_str_static(&session->pid),
317                  uid_str, gid_str,
318                  session->remote_machine, session->hostname, session->protocol_ver);
319
320         return 0;
321 }
322
323
324 static void print_notify_recs(const char *path,
325                               struct notify_db_entry *entries,
326                               size_t num_entries,
327                               time_t deleted_time, void *private_data)
328 {
329         size_t i;
330         d_printf("%s\n", path);
331
332         if (num_entries == 0) {
333                 d_printf("deleted %s\n", time_to_asc(deleted_time));
334         }
335
336         for (i=0; i<num_entries; i++) {
337                 struct notify_db_entry *e = &entries[i];
338                 char *str;
339
340                 str = server_id_str(talloc_tos(), &e->server);
341                 printf("%s %x %x\n", str, (unsigned)e->filter,
342                        (unsigned)e->subdir_filter);
343                 TALLOC_FREE(str);
344         }
345         printf("\n");
346 }
347
348 int main(int argc, const char *argv[])
349 {
350         int c;
351         int profile_only = 0;
352         bool show_processes, show_locks, show_shares;
353         bool show_notify = false;
354         poptContext pc;
355         struct poptOption long_options[] = {
356                 POPT_AUTOHELP
357                 {"processes",   'p', POPT_ARG_NONE,     NULL, 'p', "Show processes only" },
358                 {"verbose",     'v', POPT_ARG_NONE,     NULL, 'v', "Be verbose" },
359                 {"locks",       'L', POPT_ARG_NONE,     NULL, 'L', "Show locks only" },
360                 {"shares",      'S', POPT_ARG_NONE,     NULL, 'S', "Show shares only" },
361                 {"notify",      'N', POPT_ARG_NONE,     NULL, 'N', "Show notifies" },
362                 {"user",        'u', POPT_ARG_STRING,   &username, 'u', "Switch to user" },
363                 {"brief",       'b', POPT_ARG_NONE,     NULL, 'b', "Be brief" },
364                 {"profile",     'P', POPT_ARG_NONE, NULL, 'P', "Do profiling" },
365                 {"profile-rates", 'R', POPT_ARG_NONE, NULL, 'R', "Show call rates" },
366                 {"byterange",   'B', POPT_ARG_NONE,     NULL, 'B', "Include byte range locks"},
367                 {"numeric",     'n', POPT_ARG_NONE,     NULL, 'n', "Numeric uid/gid"},
368                 {"fast",        'f', POPT_ARG_NONE,     NULL, 'f', "Skip checks if processes still exist"},
369                 POPT_COMMON_SAMBA
370                 POPT_TABLEEND
371         };
372         TALLOC_CTX *frame = talloc_stackframe();
373         int ret = 0;
374         struct messaging_context *msg_ctx;
375         char *db_path;
376         bool ok;
377
378         sec_init();
379         load_case_tables();
380
381         setup_logging(argv[0], DEBUG_STDERR);
382
383         if (getuid() != geteuid()) {
384                 d_printf("smbstatus should not be run setuid\n");
385                 ret = 1;
386                 goto done;
387         }
388
389         pc = poptGetContext(NULL, argc, argv, long_options,
390                             POPT_CONTEXT_KEEP_FIRST);
391
392         while ((c = poptGetNextOpt(pc)) != -1) {
393                 switch (c) {
394                 case 'p':
395                         processes_only = true;
396                         break;
397                 case 'v':
398                         verbose = true;
399                         break;
400                 case 'L':
401                         locks_only = true;
402                         break;
403                 case 'S':
404                         shares_only = true;
405                         break;
406                 case 'N':
407                         show_notify = true;
408                         break;
409                 case 'b':
410                         brief = true;
411                         break;
412                 case 'u':
413                         Ucrit_addUid(nametouid(poptGetOptArg(pc)));
414                         break;
415                 case 'P':
416                 case 'R':
417                         profile_only = c;
418                         break;
419                 case 'B':
420                         show_brl = true;
421                         break;
422                 case 'n':
423                         numeric_only = true;
424                         break;
425                 case 'f':
426                         do_checks = false;
427                         break;
428                 }
429         }
430
431         /* setup the flags based on the possible combincations */
432
433         show_processes = !(shares_only || locks_only || profile_only) || processes_only;
434         show_locks     = !(shares_only || processes_only || profile_only) || locks_only;
435         show_shares    = !(processes_only || locks_only || profile_only) || shares_only;
436
437         if ( username )
438                 Ucrit_addUid( nametouid(username) );
439
440         if (verbose) {
441                 d_printf("using configfile = %s\n", get_dyn_CONFIGFILE());
442         }
443
444         if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
445                 fprintf(stderr, "Can't load %s - run testparm to debug it\n",
446                         get_dyn_CONFIGFILE());
447                 ret = -1;
448                 goto done;
449         }
450
451
452         if (lp_clustering()) {
453                 /*
454                  * This implicitly initializes the global ctdbd
455                  * connection, usable by the db_open() calls further
456                  * down.
457                  */
458                 msg_ctx = messaging_init(NULL, samba_tevent_context_init(NULL));
459                 if (msg_ctx == NULL) {
460                         fprintf(stderr, "messaging_init failed\n");
461                         ret = -1;
462                         goto done;
463                 }
464         }
465
466         if (!lp_load_global(get_dyn_CONFIGFILE())) {
467                 fprintf(stderr, "Can't load %s - run testparm to debug it\n",
468                         get_dyn_CONFIGFILE());
469                 ret = -1;
470                 goto done;
471         }
472
473         switch (profile_only) {
474                 case 'P':
475                         /* Dump profile data */
476                         ok = status_profile_dump(verbose);
477                         return ok ? 0 : 1;
478                 case 'R':
479                         /* Continuously display rate-converted data */
480                         ok = status_profile_rates(verbose);
481                         return ok ? 0 : 1;
482                 default:
483                         break;
484         }
485
486         if ( show_processes ) {
487                 d_printf("\nSamba version %s\n",samba_version_string());
488                 d_printf("PID     Username      Group         Machine            Protocol Version       \n");
489                 d_printf("------------------------------------------------------------------------------\n");
490
491                 sessionid_traverse_read(traverse_sessionid, NULL);
492
493                 if (processes_only) {
494                         goto done;
495                 }
496         }
497
498         if ( show_shares ) {
499                 if (verbose) {
500                         db_path = lock_path("connections.tdb");
501                         if (db_path == NULL) {
502                                 d_printf("Out of memory - exiting\n");
503                                 ret = -1;
504                                 goto done;
505                         }
506                         d_printf("Opened %s\n", db_path);
507                         TALLOC_FREE(db_path);
508                 }
509
510                 if (brief) {
511                         goto done;
512                 }
513
514                 d_printf("\nService      pid     machine       Connected at\n");
515                 d_printf("-------------------------------------------------------\n");
516
517                 connections_forall_read(traverse_connections, NULL);
518
519                 d_printf("\n");
520
521                 if ( shares_only ) {
522                         goto done;
523                 }
524         }
525
526         if ( show_locks ) {
527                 int result;
528                 struct db_context *db;
529
530                 db_path = lock_path("locking.tdb");
531                 if (db_path == NULL) {
532                         d_printf("Out of memory - exiting\n");
533                         ret = -1;
534                         goto done;
535                 }
536
537                 db = db_open(NULL, db_path, 0,
538                              TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDONLY, 0,
539                              DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
540
541                 if (!db) {
542                         d_printf("%s not initialised\n", db_path);
543                         d_printf("This is normal if an SMB client has never "
544                                  "connected to your server.\n");
545                         TALLOC_FREE(db_path);
546                         exit(0);
547                 } else {
548                         TALLOC_FREE(db);
549                         TALLOC_FREE(db_path);
550                 }
551
552                 if (!locking_init_readonly()) {
553                         d_printf("Can't initialise locking module - exiting\n");
554                         ret = 1;
555                         goto done;
556                 }
557
558                 result = share_entry_forall(print_share_mode, NULL);
559
560                 if (result == 0) {
561                         d_printf("No locked files\n");
562                 } else if (result < 0) {
563                         d_printf("locked file list truncated\n");
564                 }
565
566                 d_printf("\n");
567
568                 if (show_brl) {
569                         brl_forall(print_brl, NULL);
570                 }
571
572                 locking_end();
573         }
574
575         if (show_notify) {
576                 struct notify_context *n;
577
578                 n = notify_init(talloc_tos(), NULL, NULL);
579                 if (n == NULL) {
580                         goto done;
581                 }
582                 notify_walk(n, print_notify_recs, NULL);
583                 TALLOC_FREE(n);
584         }
585
586 done:
587         TALLOC_FREE(frame);
588         return ret;
589 }