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