smbd: Ensure we grant owner sid in check_parent_access_fsp()
[samba.git] / source3 / utils / status.c
index 2b2fab672579d481e3aafe995f968ec63f89eed5..02a5f6dbaba15613e1f635e8429fe96fd8705a48 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    status reporting
    Copyright (C) Andrew Tridgell 1994-1998
@@ -54,6 +54,7 @@
 #include "cmdline_contexts.h"
 #include "locking/leases_db.h"
 #include "lib/util/string_wrappers.h"
+#include "lib/param/param.h"
 
 #ifdef HAVE_JANSSON
 #include <jansson.h>
@@ -86,10 +87,10 @@ static void Ucrit_addUid(uid_t uid)
 
 static unsigned int Ucrit_checkUid(uid_t uid)
 {
-       if ( !Ucrit_IsActive ) 
+       if ( !Ucrit_IsActive )
                return 1;
 
-       if ( uid == Ucrit_uid ) 
+       if ( uid == Ucrit_uid )
                return 1;
 
        return 0;
@@ -99,7 +100,7 @@ static unsigned int Ucrit_checkPid(struct server_id pid)
 {
        int i;
 
-       if ( !Ucrit_IsActive ) 
+       if ( !Ucrit_IsActive )
                return 1;
 
        for (i=0;i<Ucrit_MaxPid;i++) {
@@ -164,6 +165,28 @@ static int prepare_share_mode(struct traverse_state *state)
        return 0;
 }
 
+static uint32_t map_share_mode_to_deny_mode(
+       uint32_t share_access, uint32_t private_options)
+{
+       switch (share_access & ~FILE_SHARE_DELETE) {
+       case FILE_SHARE_NONE:
+               return DENY_ALL;
+       case FILE_SHARE_READ:
+               return DENY_WRITE;
+       case FILE_SHARE_WRITE:
+               return DENY_READ;
+       case FILE_SHARE_READ|FILE_SHARE_WRITE:
+               return DENY_NONE;
+       }
+       if (private_options & NTCREATEX_FLAG_DENY_DOS) {
+               return DENY_DOS;
+       } else if (private_options & NTCREATEX_FLAG_DENY_FCB) {
+               return DENY_FCB;
+       }
+
+       return (uint32_t)-1;
+}
+
 static int print_share_mode(struct file_id fid,
                            const struct share_mode_data *d,
                            const struct share_mode_entry *e,
@@ -359,7 +382,7 @@ static int prepare_brl(struct traverse_state *state)
 }
 
 static void print_brl(struct file_id id,
-                       struct server_id pid, 
+                       struct server_id pid,
                        enum brl_type lock_type,
                        enum brl_flavour lock_flav,
                        br_off start,
@@ -411,6 +434,12 @@ static void print_brl(struct file_id id,
                                 fname);
        } else {
                print_brl_json(state,
+                              pid,
+                              id,
+                              desc,
+                              lock_flav,
+                              (intmax_t)start,
+                              (intmax_t)size,
                               sharepath,
                               fname);
 
@@ -454,9 +483,33 @@ static int traverse_connections_stdout(struct traverse_state *state,
                                       char *server_id,
                                       const char *machine,
                                       const char *timestr,
-                                      const char *encryption,
-                                      const char *signing)
+                                      const char *encryption_cipher,
+                                      enum crypto_degree encryption_degree,
+                                      const char *signing_cipher,
+                                      enum crypto_degree signing_degree)
 {
+       fstring encryption;
+       fstring signing;
+
+       if (encryption_degree == CRYPTO_DEGREE_FULL) {
+               fstr_sprintf(encryption, "%s", encryption_cipher);
+       } else if (encryption_degree == CRYPTO_DEGREE_ANONYMOUS) {
+               fstr_sprintf(encryption, "anonymous(%s)", encryption_cipher);
+       } else if (encryption_degree == CRYPTO_DEGREE_PARTIAL) {
+               fstr_sprintf(encryption, "partial(%s)", encryption_cipher);
+       } else {
+               fstr_sprintf(encryption, "-");
+       }
+       if (signing_degree == CRYPTO_DEGREE_FULL) {
+               fstr_sprintf(signing, "%s", signing_cipher);
+       } else if (signing_degree == CRYPTO_DEGREE_ANONYMOUS) {
+               fstr_sprintf(signing, "anonymous(%s)", signing_cipher);
+       } else if (signing_degree == CRYPTO_DEGREE_PARTIAL) {
+               fstr_sprintf(signing, "partial(%s)", signing_cipher);
+       } else {
+               fstr_sprintf(signing, "-");
+       }
+
        d_printf("%-12s %-7s %-13s %-32s %-12s %-12s\n",
                 servicename, server_id, machine, timestr, encryption, signing);
 
@@ -509,7 +562,9 @@ static int traverse_connections(const struct connections_data *crec,
                return -1;
        }
 
-       if (smbXsrv_is_encrypted(crec->encryption_flags)) {
+       if (smbXsrv_is_encrypted(crec->encryption_flags) ||
+           smbXsrv_is_partially_encrypted(crec->encryption_flags))
+       {
                switch (crec->cipher) {
                case SMB_ENCRYPTION_GSSAPI:
                        encryption = "GSSAPI";
@@ -520,15 +575,31 @@ static int traverse_connections(const struct connections_data *crec,
                case SMB2_ENCRYPTION_AES128_GCM:
                        encryption = "AES-128-GCM";
                        break;
+               case SMB2_ENCRYPTION_AES256_CCM:
+                       encryption = "AES-256-CCM";
+                       break;
+               case SMB2_ENCRYPTION_AES256_GCM:
+                       encryption = "AES-256-GCM";
+                       break;
                default:
                        encryption = "???";
-                       result = -1;
                        break;
                }
-               encryption_degree = CRYPTO_DEGREE_FULL;
+               if (smbXsrv_is_encrypted(crec->encryption_flags)) {
+                       encryption_degree = CRYPTO_DEGREE_FULL;
+               } else if (smbXsrv_is_partially_encrypted(crec->encryption_flags)) {
+                       encryption_degree = CRYPTO_DEGREE_PARTIAL;
+               }
+               if (encryption_degree != CRYPTO_DEGREE_NONE &&
+                   !crec->authenticated)
+               {
+                       encryption_degree = CRYPTO_DEGREE_ANONYMOUS;
+               }
        }
 
-       if (smbXsrv_is_signed(crec->signing_flags)) {
+       if (smbXsrv_is_signed(crec->signing_flags) ||
+           smbXsrv_is_partially_signed(crec->signing_flags))
+       {
                switch (crec->signing) {
                case SMB2_SIGNING_MD5_SMB1:
                        signing = "HMAC-MD5";
@@ -544,10 +615,18 @@ static int traverse_connections(const struct connections_data *crec,
                        break;
                default:
                        signing = "???";
-                       result = -1;
                        break;
                }
-               signing_degree = CRYPTO_DEGREE_FULL;
+               if (smbXsrv_is_signed(crec->signing_flags)) {
+                       signing_degree = CRYPTO_DEGREE_FULL;
+               } else if (smbXsrv_is_partially_signed(crec->signing_flags)) {
+                       signing_degree = CRYPTO_DEGREE_PARTIAL;
+               }
+               if (signing_degree != CRYPTO_DEGREE_NONE &&
+                   !crec->authenticated)
+               {
+                       signing_degree = CRYPTO_DEGREE_ANONYMOUS;
+               }
        }
 
        if (!state->json_output) {
@@ -557,7 +636,9 @@ static int traverse_connections(const struct connections_data *crec,
                                                     crec->machine,
                                                     timestr,
                                                     encryption,
-                                                    signing);
+                                                    encryption_degree,
+                                                    signing,
+                                                    signing_degree);
        } else {
                result = traverse_connections_json(state,
                                                   crec,
@@ -588,6 +669,8 @@ static int traverse_sessionid_stdout(struct traverse_state *state,
 
        if (encryption_degree == CRYPTO_DEGREE_FULL) {
                fstr_sprintf(encryption, "%s", encryption_cipher);
+       } else if (encryption_degree == CRYPTO_DEGREE_ANONYMOUS) {
+               fstr_sprintf(encryption, "anonymous(%s)", encryption_cipher);
        } else if (encryption_degree == CRYPTO_DEGREE_PARTIAL) {
                fstr_sprintf(encryption, "partial(%s)", encryption_cipher);
        } else {
@@ -595,6 +678,8 @@ static int traverse_sessionid_stdout(struct traverse_state *state,
        }
        if (signing_degree == CRYPTO_DEGREE_FULL) {
                fstr_sprintf(signing, "%s", signing_cipher);
+       } else if (signing_degree == CRYPTO_DEGREE_ANONYMOUS) {
+               fstr_sprintf(signing, "anonymous(%s)", signing_cipher);
        } else if (signing_degree == CRYPTO_DEGREE_PARTIAL) {
                fstr_sprintf(signing, "partial(%s)", signing_cipher);
        } else {
@@ -729,6 +814,11 @@ static int traverse_sessionid(const char *key, struct sessionid *session,
                } else if (smbXsrv_is_partially_encrypted(session->encryption_flags)) {
                        encryption_degree = CRYPTO_DEGREE_PARTIAL;
                }
+               if (encryption_degree != CRYPTO_DEGREE_NONE &&
+                   !session->authenticated)
+               {
+                       encryption_degree = CRYPTO_DEGREE_ANONYMOUS;
+               }
        }
 
        if (smbXsrv_is_signed(session->signing_flags) ||
@@ -756,6 +846,11 @@ static int traverse_sessionid(const char *key, struct sessionid *session,
                } else if (smbXsrv_is_partially_signed(session->signing_flags)) {
                        signing_degree = CRYPTO_DEGREE_PARTIAL;
                }
+               if (signing_degree != CRYPTO_DEGREE_NONE &&
+                   !session->authenticated)
+               {
+                       signing_degree = CRYPTO_DEGREE_ANONYMOUS;
+               }
        }
 
 
@@ -802,8 +897,11 @@ static bool print_notify_rec_stdout(struct traverse_state *state,
 
 static int prepare_notify(struct traverse_state *state)
 {
-       /* don't print header line */
-
+       if (!state->json_output) {
+               /* don't print header line */
+       } else {
+               add_section_to_json(state, "notifies");
+       }
        return 0;
 }
 
@@ -815,11 +913,19 @@ static bool print_notify_rec(const char *path, struct server_id server,
        struct traverse_state *state = (struct traverse_state *)private_data;
        bool result;
 
-       result = print_notify_rec_stdout(state,
-                                        path,
-                                        server_id_str_buf(server, &idbuf),
-                                        (unsigned)instance->filter,
-                                        (unsigned)instance->subdir_filter);
+       if (!state->json_output) {
+               result = print_notify_rec_stdout(state,
+                                                path,
+                                                server_id_str_buf(server, &idbuf),
+                                                (unsigned)instance->filter,
+                                                (unsigned)instance->subdir_filter);
+
+       } else {
+               result = print_notify_rec_json(state,
+                                              instance,
+                                              server,
+                                              path);
+       }
 
        return result;
 }
@@ -926,6 +1032,14 @@ int main(int argc, const char *argv[])
                        .val        = 'n',
                        .descrip    = "Numeric uid/gid"
                },
+               {
+                       .longName   = "json",
+                       .shortName  = 'j',
+                       .argInfo    = POPT_ARG_NONE,
+                       .arg        = NULL,
+                       .val        = 'j',
+                       .descrip    = "JSON output"
+               },
                {
                        .longName   = "fast",
                        .shortName  = 'f',
@@ -951,6 +1065,7 @@ int main(int argc, const char *argv[])
        struct messaging_context *msg_ctx = NULL;
        char *db_path;
        bool ok;
+       struct loadparm_context *lp_ctx = NULL;
 
        state.first = true;
        state.json_output = false;
@@ -966,7 +1081,8 @@ int main(int argc, const char *argv[])
                TALLOC_FREE(frame);
                exit(1);
        }
-       lp_set_cmdline("log level", "0");
+       lp_ctx = samba_cmdline_get_lp_ctx();
+       lpcfg_set_cmdline(lp_ctx, "log level", "0");
 
        pc = samba_popt_get_context(getprogname(),
                                    argc,
@@ -1012,6 +1128,9 @@ int main(int argc, const char *argv[])
                case 'n':
                        numeric_only = true;
                        break;
+               case 'j':
+                       state.json_output = true;
+                       break;
                case 'f':
                        do_checks = false;
                        break;
@@ -1030,7 +1149,14 @@ int main(int argc, const char *argv[])
 
 #ifdef HAVE_JANSSON
        state.root_json = json_new_object();
-       add_general_information_to_json(&state);
+       if (!json_is_invalid(&state.root_json)) {
+               add_general_information_to_json(&state);
+       }
+#else /* HAVE_JANSSON */
+       if (state.json_output) {
+               fprintf(stderr, "JSON support not available, please install lib Jansson\n");
+               goto done;
+       }
 #endif /* HAVE_JANSSON */
 
        if (getuid() != geteuid()) {
@@ -1054,7 +1180,7 @@ int main(int argc, const char *argv[])
        if ( username )
                Ucrit_addUid( nametouid(username) );
 
-       if (verbose) {
+       if (verbose && !state.json_output) {
                d_printf("using configfile = %s\n", get_dyn_CONFIGFILE());
        }
 
@@ -1068,13 +1194,18 @@ int main(int argc, const char *argv[])
        switch (profile_only) {
                case 'P':
                        /* Dump profile data */
-                       ok = status_profile_dump(verbose);
+                       ok = status_profile_dump(verbose, &state);
                        ret = ok ? 0 : 1;
                        goto done;
                case 'R':
                        /* Continuously display rate-converted data */
-                       ok = status_profile_rates(verbose);
-                       ret = ok ? 0 : 1;
+                       if (!state.json_output) {
+                               ok = status_profile_rates(verbose);
+                               ret = ok ? 0 : 1;
+                       } else {
+                               fprintf(stderr, "Call rates not available in a json output.\n");
+                               ret = 1;
+                       }
                        goto done;
                default:
                        break;
@@ -1096,7 +1227,9 @@ int main(int argc, const char *argv[])
                prepare_connections(&state);
                connections_forall_read(traverse_connections, &state);
 
-               d_printf("\n");
+               if (!state.json_output) {
+                       d_printf("\n");
+               }
 
                if ( shares_only ) {
                        goto done;
@@ -1123,7 +1256,8 @@ int main(int argc, const char *argv[])
                        fprintf(stderr, "This is normal if an SMB client has never "
                                 "connected to your server.\n");
                        TALLOC_FREE(db_path);
-                       exit(0);
+                       ret = 0;
+                       goto done;
                } else {
                        TALLOC_FREE(db);
                        TALLOC_FREE(db_path);
@@ -1138,13 +1272,15 @@ int main(int argc, const char *argv[])
                prepare_share_mode(&state);
                result = share_entry_forall(print_share_mode, &state);
 
-               if (result == 0) {
+               if (result == 0 && !state.json_output) {
                        fprintf(stderr, "No locked files\n");
-               } else if (result < 0) {
+               } else if (result < 0 && !state.json_output) {
                        fprintf(stderr, "locked file list truncated\n");
                }
 
-               d_printf("\n");
+               if (!state.json_output) {
+                       d_printf("\n");
+               }
 
                if (show_brl) {
                        prepare_brl(&state);
@@ -1162,6 +1298,12 @@ int main(int argc, const char *argv[])
 done:
        cmdline_messaging_context_free();
        poptFreeContext(pc);
+#ifdef HAVE_JANSSON
+       if (state.json_output) {
+               d_printf("%s\n", json_to_string(frame, &state.root_json));
+       }
+       json_free(&state.root_json);
+#endif /* HAVE_JANSSON */
        TALLOC_FREE(frame);
        return ret;
 }