[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Sat Sep 22 07:21:02 UTC 2018


The branch, master has been updated
       via  6dc9f70 tests/blackbox: add test for net ads JSON output
       via  2a19b4e s3: net: normalize output of lookup subcommand
       via  5534b92 s3: net: implement json output for ads lookup
       via  2e00ad4 s3: net: implement json output for ads info
       via  d50aafe lib/audit_logging: make json_{is_invalid,to_string}() accept a const*
      from  1885410 selftest: Tweak PSO test-suite name

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 6dc9f70bbb733519bcd57a69cc87133224a9d2fe
Author: Philipp Gesang <philipp.gesang at intra2net.com>
Date:   Mon Aug 20 14:50:39 2018 +0200

    tests/blackbox: add test for net ads JSON output
    
    Implement blackbox tests for
    
        $ net ads info --json
        $ net ads lookup --json
    
    that validate
    
        a) JSON wellformedness (by feeding it into the JSON library
           that ships with Python), and
        b) equality of the set of keys printed to that of the
           non-JSON version.
    
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>
    Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Sat Sep 22 09:20:09 CEST 2018 on sn-devel-144

commit 2a19b4e31b52d5d58ff3266b758ec8294d6c497c
Author: Philipp Gesang <philipp.gesang at intra2net.com>
Date:   Mon Aug 20 15:10:31 2018 +0200

    s3: net: normalize output of lookup subcommand
    
    Use spaces and tabs consistently following the majority of the
    printed output: tabs only for indenting, no space before the
    colon separator, a single space after the separator.
    
    The irregularities in formatting date back to the original commit
    2c029a8b96..
    
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>
    Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 5534b9248fa375799ad4bc6f45a69dcf14e6419e
Author: Philipp Gesang <philipp.gesang at intra2net.com>
Date:   Tue Jul 3 12:09:17 2018 +0200

    s3: net: implement json output for ads lookup
    
    Add JSON printer (option '--json') for the 'net ads lookup'
    command. This outputs the same information as the plain version,
    with integral ({LMNT,LM20} Token, NT Version) and boolean values
    (Flags) not stringified.
    
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>
    Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 2e00ad44aa6822817f7e988cdfa7c87fc3aa5257
Author: Philipp Gesang <philipp.gesang at intra2net.com>
Date:   Mon Jul 2 16:21:59 2018 +0200

    s3: net: implement json output for ads info
    
    Add the switch '--json' to 'net' to format the output as JSON.
    
    The rationale is to supply the information in a machine-readable
    fashion to complement the text version of the output which is
    neither particularly well defined nor locale-safe.
    
    The output differs from that of plain 'info' in that times are
    not formatted as timestamps.
    
    Currently affects only the 'net ads info' subcommand.
    
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>
    Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit d50aafe932b79bc406501757e780ae1c7d9dddfc
Author: Philipp Gesang <philipp.gesang at intra2net.com>
Date:   Mon Jul 9 09:41:37 2018 +0200

    lib/audit_logging: make json_{is_invalid,to_string}() accept a const*
    
    Allow for json_is_invalid() and json_to_string() to be used on a
    const pointer. Neither function requires for the json object to
    be mutable so constraining them to non-const* is unnecessary.
    
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>
    Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 lib/audit_logging/audit_logging.c          |   4 +-
 lib/audit_logging/audit_logging.h          |   4 +-
 python/samba/tests/blackbox/netads_json.py |  83 +++++++
 source3/utils/net.c                        |   1 +
 source3/utils/net.h                        |   1 +
 source3/utils/net_ads.c                    | 374 ++++++++++++++++++++++++++++-
 source3/utils/wscript_build                |   2 +
 source4/selftest/tests.py                  |   3 +
 8 files changed, 460 insertions(+), 12 deletions(-)
 create mode 100644 python/samba/tests/blackbox/netads_json.py


Changeset truncated at 500 lines:

diff --git a/lib/audit_logging/audit_logging.c b/lib/audit_logging/audit_logging.c
index ac08863..c274e97 100644
--- a/lib/audit_logging/audit_logging.c
+++ b/lib/audit_logging/audit_logging.c
@@ -355,7 +355,7 @@ void json_free(struct json_object *object)
  * @return is the object valid?
  *
  */
-bool json_is_invalid(struct json_object *object)
+bool json_is_invalid(const struct json_object *object)
 {
 	return !object->valid;
 }
@@ -907,7 +907,7 @@ int json_add_guid(struct json_object *object,
  * @return A string representation of the object or NULL if the object
  *         is invalid.
  */
-char *json_to_string(TALLOC_CTX *mem_ctx, struct json_object *object)
+char *json_to_string(TALLOC_CTX *mem_ctx, const struct json_object *object)
 {
 	char *json = NULL;
 	char *json_string = NULL;
diff --git a/lib/audit_logging/audit_logging.h b/lib/audit_logging/audit_logging.h
index 4203743..5f095c0 100644
--- a/lib/audit_logging/audit_logging.h
+++ b/lib/audit_logging/audit_logging.h
@@ -55,7 +55,7 @@ _WARN_UNUSED_RESULT_ struct json_object json_new_object(void);
 _WARN_UNUSED_RESULT_ struct json_object json_new_array(void);
 void json_free(struct json_object *object);
 void json_assert_is_array(struct json_object *array);
-_WARN_UNUSED_RESULT_ bool json_is_invalid(struct json_object *object);
+_WARN_UNUSED_RESULT_ bool json_is_invalid(const struct json_object *object);
 
 _WARN_UNUSED_RESULT_ int json_add_int(struct json_object *object,
 				      const char *name,
@@ -93,6 +93,6 @@ _WARN_UNUSED_RESULT_ struct json_object json_get_array(
 _WARN_UNUSED_RESULT_ struct json_object json_get_object(
     struct json_object *object, const char *name);
 _WARN_UNUSED_RESULT_ char *json_to_string(TALLOC_CTX *mem_ctx,
-					  struct json_object *object);
+					  const struct json_object *object);
 #endif
 #endif
diff --git a/python/samba/tests/blackbox/netads_json.py b/python/samba/tests/blackbox/netads_json.py
new file mode 100644
index 0000000..ce48a2b
--- /dev/null
+++ b/python/samba/tests/blackbox/netads_json.py
@@ -0,0 +1,83 @@
+# Blackbox tests for the "net ads ... --json" commands
+# Copyright (C) 2018 Intra2net AG
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import json
+import re
+
+import samba.tests
+
+COMMAND         = "bin/net ads"
+# extract keys from non-json version
+PLAIN_KEY_REGEX = re.compile ("^([^ \t:][^:]*):")
+
+class BaseWrapper (object):
+    """
+    Guard the base so it doesn't inherit from TestCase. This prevents it from
+    being run by unittest directly.
+    """
+
+    class NetAdsJSONTests_Base(samba.tests.BlackboxTestCase):
+        """Blackbox tests for JSON output of the net ads suite of commands."""
+        subcmd = None
+
+        def setUp(self):
+            super(BaseWrapper.NetAdsJSONTests_Base, self).setUp()
+
+        def test_json_wellformed (self):
+            """The output of ``--json`` commands must parse as JSON."""
+            argv = "%s %s --json" % (COMMAND, self.subcmd)
+            try:
+                out = self.check_output(argv)
+                json.loads (out)
+            except samba.tests.BlackboxProcessError as e:
+                self.fail("Error calling [%s]: %s" % (argv, e))
+
+        def test_json_matching_entries (self):
+            """
+            The ``--json`` variants must contain the same keys as their
+            respective plain counterpart.
+
+            Does not check nested dictionaries (e. g. the ``Flags`` value of
+            ``net ads lookup``..
+            """
+            argv = "%s %s" % (COMMAND, self.subcmd)
+            try:
+                out_plain = self.check_output(argv)
+            except samba.tests.BlackboxProcessError as e:
+                self.fail("Error calling [%s]: %s" % (argv, e))
+
+            argv = "%s %s --json" % (COMMAND, self.subcmd)
+            try:
+                out_jsobj = self.check_output(argv)
+            except samba.tests.BlackboxProcessError as e:
+                self.fail("Error calling [%s]: %s" % (argv, e))
+
+            parsed = json.loads (out_jsobj)
+
+            for key in [ re.match (PLAIN_KEY_REGEX, line).group(1)
+                         for line in out_plain.split ("\n")
+                            if line != "" and line [0] not in " \t:" ]:
+                self.assertTrue (parsed.get (key) is not None)
+                del parsed [key]
+
+            self.assertTrue (len (parsed) == 0) # tolerate no leftovers
+
+class NetAdsJSONInfoTests(BaseWrapper.NetAdsJSONTests_Base):
+    subcmd = "info"
+
+class NetAdsJSONlookupTests(BaseWrapper.NetAdsJSONTests_Base):
+    subcmd = "lookup"
diff --git a/source3/utils/net.c b/source3/utils/net.c
index b3bd4b6..7f07644 100644
--- a/source3/utils/net.c
+++ b/source3/utils/net.c
@@ -973,6 +973,7 @@ static struct functable net_func[] = {
 		/* Options for 'net ads join or leave' */
 		{"no-dns-updates", 0, POPT_ARG_NONE, &c->opt_no_dns_updates},
 		{"keep-account", 0, POPT_ARG_NONE, &c->opt_keep_account},
+		{"json", 0, POPT_ARG_NONE, &c->opt_json},
 		POPT_COMMON_SAMBA
 		{ 0, 0, 0, 0}
 	};
diff --git a/source3/utils/net.h b/source3/utils/net.h
index 5e70fd3..0d01ad4 100644
--- a/source3/utils/net.h
+++ b/source3/utils/net.h
@@ -86,6 +86,7 @@ struct net_context {
 	const char *opt_precheck;
 	int opt_no_dns_updates;
 	int opt_keep_account;
+	int opt_json;
 
 	int opt_have_ip;
 	struct sockaddr_storage opt_dest_ip;
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index afe47da..77d9eec 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -41,6 +41,12 @@
 #include "lib/param/loadparm.h"
 #include "utils/net_dns.h"
 
+#ifdef HAVE_JANSSON
+#include <jansson.h>
+#include "audit_logging.h" /* various JSON helpers */
+#include "auth/common_auth.h"
+#endif /* [HAVE_JANSSON] */
+
 #ifdef HAVE_ADS
 
 /* when we do not have sufficient input parameters to contact a remote domain
@@ -55,6 +61,263 @@ static const char *assume_own_realm(struct net_context *c)
 	return NULL;
 }
 
+#ifdef HAVE_JANSSON
+
+/*
+ * note: JSON output deliberately bypasses gettext so as to provide the same
+ * output irrespective of the locale.
+ */
+
+static int output_json(const struct json_object *jsobj)
+{
+	TALLOC_CTX *ctx = NULL;
+	char *json = NULL;
+
+	if (json_is_invalid(jsobj)) {
+		return -1;
+	}
+
+	ctx = talloc_new(NULL);
+	if (ctx == NULL) {
+		d_fprintf(stderr, _("Out of memory\n"));
+		return -1;
+	}
+
+	json = json_to_string(ctx, jsobj);
+	if (!json) {
+		d_fprintf(stderr, _("error encoding to JSON\n"));
+		return -1;
+	}
+
+	d_printf("%s\n", json);
+	TALLOC_FREE(ctx);
+
+	return 0;
+}
+
+static int net_ads_cldap_netlogon_json
+	(ADS_STRUCT *ads,
+	 const char *addr,
+	 const struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply)
+{
+	struct json_object jsobj = json_new_object();
+	struct json_object flagsobj = json_new_object();
+	char response_type [32] = { '\0' };
+	int ret = 0;
+
+	if (json_is_invalid(&jsobj) || json_is_invalid(&flagsobj)) {
+		d_fprintf(stderr, _("error setting up JSON value\n"));
+
+		goto failure;
+	}
+
+	switch (reply->command) {
+		case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
+			strncpy(response_type,
+				"LOGON_SAM_LOGON_USER_UNKNOWN_EX",
+				sizeof(response_type));
+			break;
+		case LOGON_SAM_LOGON_RESPONSE_EX:
+			strncpy(response_type, "LOGON_SAM_LOGON_RESPONSE_EX",
+	      sizeof(response_type));
+			break;
+		default:
+			snprintf(response_type, sizeof(response_type), "0x%x",
+	       reply->command);
+			break;
+	}
+
+	ret = json_add_string(&jsobj, "Information for Domain Controller",
+			      addr);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Response Type", response_type);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_guid(&jsobj, "GUID", &reply->domain_uuid);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is a PDC",
+			    reply->server_type & NBT_SERVER_PDC);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is a GC of the forest",
+			    reply->server_type & NBT_SERVER_GC);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is an LDAP server",
+			    reply->server_type & NBT_SERVER_LDAP);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Supports DS",
+			    reply->server_type & NBT_SERVER_DS);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is running a KDC",
+			    reply->server_type & NBT_SERVER_KDC);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is running time services",
+			    reply->server_type & NBT_SERVER_TIMESERV);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is the closest DC",
+			    reply->server_type & NBT_SERVER_CLOSEST);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is writable",
+			    reply->server_type & NBT_SERVER_WRITABLE);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Has a hardware clock",
+			    reply->server_type & NBT_SERVER_GOOD_TIMESERV);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj,
+			    "Is a non-domain NC serviced by LDAP server",
+			    reply->server_type & NBT_SERVER_NDNC);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool
+		(&flagsobj, "Is NT6 DC that has some secrets",
+		 reply->server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool
+		(&flagsobj, "Is NT6 DC that has all secrets",
+		 reply->server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Runs Active Directory Web Services",
+			    reply->server_type & NBT_SERVER_ADS_WEB_SERVICE);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Runs on Windows 2012 or later",
+			    reply->server_type & NBT_SERVER_DS_8);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Forest", reply->forest);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Domain", reply->dns_domain);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Domain Controller", reply->pdc_dns_name);
+	if (ret != 0) {
+		goto failure;
+	}
+
+
+	ret = json_add_string(&jsobj, "Pre-Win2k Domain", reply->domain_name);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Pre-Win2k Hostname", reply->pdc_name);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	if (*reply->user_name) {
+		ret = json_add_string(&jsobj, "User name", reply->user_name);
+		if (ret != 0) {
+			goto failure;
+		}
+	}
+
+	ret = json_add_string(&jsobj, "Server Site Name", reply->server_site);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Client Site Name", reply->client_site);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_int(&jsobj, "NT Version", reply->nt_version);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_int(&jsobj, "LMNT Token", reply->lmnt_token);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_int(&jsobj, "LM20 Token", reply->lm20_token);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = json_add_object(&jsobj, "Flags", &flagsobj);
+	if (ret != 0) {
+		goto failure;
+	}
+
+	ret = output_json(&jsobj);
+	json_free(&jsobj); /* frees flagsobj recursively */
+
+	return ret;
+
+failure:
+	json_free(&flagsobj);
+	json_free(&jsobj);
+
+	return ret;
+}
+
+#else /* [HAVE_JANSSON] */
+
+static int net_ads_cldap_netlogon_json
+	(ADS_STRUCT *, const char *,
+	 const struct NETLOGON_SAM_LOGON_RESPONSE_EX *)
+{
+	d_fprintf(stderr, _("JSON support not available\n"));
+
+	return -1;
+}
+
+#endif /* [HAVE_JANSSON] */
+
 /*
   do a cldap netlogon query
 */
@@ -70,6 +333,10 @@ static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
 		return -1;
 	}
 
+	if (c->opt_json) {
+		return net_ads_cldap_netlogon_json(ads, addr, &reply);
+	}
+
 	d_printf(_("Information for Domain Controller: %s\n\n"),
 		addr);
 
@@ -119,17 +386,17 @@ static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
 		   (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"));
 
 
-	printf(_("Forest:\t\t\t%s\n"), reply.forest);
-	printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
-	printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
+	printf(_("Forest: %s\n"), reply.forest);
+	printf(_("Domain: %s\n"), reply.dns_domain);
+	printf(_("Domain Controller: %s\n"), reply.pdc_dns_name);
 
-	printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
-	printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
+	printf(_("Pre-Win2k Domain: %s\n"), reply.domain_name);
+	printf(_("Pre-Win2k Hostname: %s\n"), reply.pdc_name);
 
-	if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
+	if (*reply.user_name) printf(_("User name: %s\n"), reply.user_name);
 
-	printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
-	printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
+	printf(_("Server Site Name: %s\n"), reply.server_site);
+	printf(_("Client Site Name: %s\n"), reply.client_site);
 
 	d_printf(_("NT Version: %d\n"), reply.nt_version);
 	d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
@@ -173,6 +440,93 @@ static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
 }
 
 
+#ifdef HAVE_JANSSON
+
+static int net_ads_info_json(ADS_STRUCT *ads)
+{
+	int ret = 0;
+	char addr[INET6_ADDRSTRLEN];
+	time_t pass_time;
+	struct json_object jsobj = json_new_object();
+
+	if (json_is_invalid(&jsobj)) {
+		d_fprintf(stderr, _("error setting up JSON value\n"));
+
+		goto failure;
+	}
+
+	pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
+
+	print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
+
+	ret = json_add_string (&jsobj, "LDAP server", addr);
+	if (ret != 0) {
+		goto failure;


-- 
Samba Shared Repository



More information about the samba-cvs mailing list