[RFC PATCH v4] add JSON output to net ads

Philipp Gesang philipp.gesang at intra2net.com
Fri Jul 13 11:54:22 UTC 2018


Hi again,

attached is the fourth iteration of the JSON patches for “net
ads” (CI: https://gitlab.com/phgsng/samba/pipelines/25703977).

Description in lieu of a cover letter:

-8<----------------------------------------------------------->8-

Changes in v4:

* Incorporate feedback by Gary Lockyer.
* Change signature of json_to_string() too to take const*
  (necessitated by above item).
* Submit as patch bundle.


Changes in v3:

* Remove an unused variable.
* Rebase onto:
  https://gitlab.com/catalyst-samba/samba/pipelines/25428061
* Full branch available on gitlab:
  https://gitlab.com/phgsng/samba/commits/i2n-net-ads-json
* Add one tiny patch that drops an unnecessary json_free().


Changes in v2:

* Rebase onto the error handling branch:
  https://lists.samba.org/archive/samba-technical/2018-July/128973.html
* Change signature of json_is_invalid() to accept const*.
* Use json_add_guid() instead of dumping uuid manually.


V1 blurb:

The informational commands of the ``net ads'' family format their
output in an ad-hoc manner that is not specified. For automated
processing it would be useful to optionally encode the output as
JSON.

These two patches against master add such a JSON output to ``net
ads info'' and ``net ads lookup''. They have been forward-ported
from the 4.7-ish Samba that we run. Compilation succeeds with
master but I'm still in the process of getting working test
environment, so they're virtually untested.

-8<----------------------------------------------------------->8-

Best,
Philipp

-------------- next part --------------
From 7dc72313b9c8eb41efd49f15caab6c1f48d71eb2 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <philipp.gesang at intra2net.com>
Date: Wed, 11 Jul 2018 15:31:02 +0200
Subject: [PATCH v4 1/5] lib/audit_logging: heal merge damage

The ``duration'' field introduced by

    commit b282bcbb759bbb12797922e066aeb12c0df5b2f1
    Author: Gary Lockyer <gary at catalyst.net.nz>
    Date:   Wed Jun 6 15:30:44 2018 +0200

        dsdb: Log the transaction duraton.

was not part of the error handling branch:

    commit b6915bb4dac3fa010723eb009c8e39896edae80c
    Author: Gary Lockyer <gary at catalyst.net.nz>
    Date:   Mon Jun 25 16:00:28 2018 +1200

        lib audit_logging: Refactor to return an error codes

so it still uses the old style. Convert them to use the new
interface instead.

Furthermore, return code checks are missing for two string fields
in operation_json() (``status'', ``operation'') probably due to
an oversight. Fix those as well.
---
 source4/dsdb/samdb/ldb_modules/audit_log.c | 43 ++++++++++++++++++----
 1 file changed, 36 insertions(+), 7 deletions(-)

diff --git a/source4/dsdb/samdb/ldb_modules/audit_log.c b/source4/dsdb/samdb/ldb_modules/audit_log.c
index 9920a4899d5..270a19030f8 100644
--- a/source4/dsdb/samdb/ldb_modules/audit_log.c
+++ b/source4/dsdb/samdb/ldb_modules/audit_log.c
@@ -223,8 +223,14 @@ static struct json_object operation_json(
 	if (rc) {
 		goto failure;
 	}
-	json_add_string(&audit, "status", ldb_strerror(reply->error));
-	json_add_string(&audit, "operation", operation);
+	rc = json_add_string(&audit, "status", ldb_strerror(reply->error));
+	if (rc) {
+		goto failure;
+	}
+	rc = json_add_string(&audit, "operation", operation);
+	if (rc) {
+		goto failure;
+	}
 	rc = json_add_address(&audit, "remoteAddress", remote);
 	if (rc) {
 		goto failure;
@@ -462,7 +468,10 @@ static struct json_object password_change_json(
 	if (rc) {
 		goto failure;
 	}
-	json_add_string(&audit, "status", ldb_strerror(reply->error));
+	rc = json_add_string(&audit, "status", ldb_strerror(reply->error));
+	if (rc) {
+		goto failure;
+	}
 	rc = json_add_address(&audit, "remoteAddress", remote);
 	if (rc) {
 		goto failure;
@@ -555,6 +564,10 @@ static struct json_object transaction_json(
 	if (rc) {
 		goto failure;
 	}
+	rc = json_add_int(&audit, "duration", duration);
+	if (rc) {
+		goto failure;
+	}
 
 	wrapper = json_new_object();
 	rc = json_add_timestamp(&wrapper);
@@ -614,14 +627,30 @@ static struct json_object commit_failure_json(
 	if (rc) {
 		goto failure;
 	}
-	json_add_string(&audit, "action", action);
-	json_add_guid(&audit, "transactionId", transaction_id);
+	rc = json_add_string(&audit, "action", action);
+	if (rc) {
+		goto failure;
+	}
+	rc = json_add_guid(&audit, "transactionId", transaction_id);
+	if (rc) {
+		goto failure;
+	}
+	rc = json_add_int(&audit, "duration", duration);
+	if (rc) {
+		goto failure;
+	}
 	rc = json_add_int(&audit, "statusCode", status);
 	if (rc) {
 		goto failure;
 	}
-	json_add_string(&audit, "status", ldb_strerror(status));
-	json_add_string(&audit, "reason", reason);
+	rc = json_add_string(&audit, "status", ldb_strerror(status));
+	if (rc) {
+		goto failure;
+	}
+	rc = json_add_string(&audit, "reason", reason);
+	if (rc) {
+		goto failure;
+	}
 
 	wrapper = json_new_object();
 	rc = json_add_timestamp(&wrapper);
-- 
2.17.1


From f52e11b54b0c417a4730e0f82b8b92cccf307826 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <philipp.gesang at intra2net.com>
Date: Mon, 9 Jul 2018 09:41:37 +0200
Subject: [PATCH v4 2/5] 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.

Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
---
 lib/audit_logging/audit_logging.c | 4 ++--
 lib/audit_logging/audit_logging.h | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/audit_logging/audit_logging.c b/lib/audit_logging/audit_logging.c
index 293bd374866..0e9704ca434 100644
--- a/lib/audit_logging/audit_logging.c
+++ b/lib/audit_logging/audit_logging.c
@@ -354,7 +354,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;
 }
@@ -924,7 +924,7 @@ int json_add_guid(
  */
 char *json_to_string(
 	TALLOC_CTX *mem_ctx,
-	struct json_object *object)
+	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 b11597e6a1a..cefcc0af1b2 100644
--- a/lib/audit_logging/audit_logging.h
+++ b/lib/audit_logging/audit_logging.h
@@ -55,7 +55,7 @@ struct json_object json_new_object(void);
 struct json_object json_new_array(void);
 void json_free(struct json_object *object);
 void json_assert_is_array(struct json_object *array);
-bool json_is_invalid(struct json_object *object);
+bool json_is_invalid(const struct json_object *object);
 
 int json_add_int(struct json_object *object,
 		 const char* name,
@@ -92,6 +92,6 @@ struct json_object json_get_array(struct json_object *object,
 struct json_object json_get_object(struct json_object *object,
 				   const char* name);
 char *json_to_string(TALLOC_CTX *mem_ctx,
-		     struct json_object *object);
+		     const struct json_object *object);
 #endif
 #endif
-- 
2.17.1


From 0c092d8f42dcd83307815b49d76b30fe86c0fe98 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <philipp.gesang at intra2net.com>
Date: Mon, 9 Jul 2018 14:05:56 +0200
Subject: [PATCH v4 3/5] lib/audit_logging: avoid freeing unallocated json
 value

json_free() has no effect on the empty json value so the call is
redundant.

Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
---
 lib/audit_logging/audit_logging.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lib/audit_logging/audit_logging.c b/lib/audit_logging/audit_logging.c
index 0e9704ca434..67a7ad3c7d3 100644
--- a/lib/audit_logging/audit_logging.c
+++ b/lib/audit_logging/audit_logging.c
@@ -981,7 +981,6 @@ struct json_object json_get_array(
 	if (json_is_invalid(object)) {
 		DBG_ERR("Invalid JSON object, unable to get array [%s]\n",
 			name);
-		json_free(&array);
 		return array;
 	}
 
-- 
2.17.1


From 2bf2ef5b5caa5fe2e3e3aedacf6be44c8b8689ae Mon Sep 17 00:00:00 2001
From: Philipp Gesang <philipp.gesang at intra2net.com>
Date: Mon, 2 Jul 2018 16:21:59 +0200
Subject: [PATCH v4 4/5] s3: net: implement json output for ads info

Add the switch '-j' 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.

Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
---
 source3/utils/net.c         |   1 +
 source3/utils/net.h         |   1 +
 source3/utils/net_ads.c     | 118 ++++++++++++++++++++++++++++++++++++
 source3/utils/wscript_build |   2 +
 4 files changed, 122 insertions(+)

diff --git a/source3/utils/net.c b/source3/utils/net.c
index 44daa6088ca..57b853a684a 100644
--- a/source3/utils/net.c
+++ b/source3/utils/net.c
@@ -973,6 +973,7 @@ static struct functable net_func[] = {
 		{"precheck", 0, POPT_ARG_STRING, &c->opt_precheck},
 		/* Options for 'net ads join' */
 		{"no-dns-updates", 0, POPT_ARG_NONE, &c->opt_no_dns_updates},
+		{"json", 'j', 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 d6dfeb6208f..af748c0275f 100644
--- a/source3/utils/net.h
+++ b/source3/utils/net.h
@@ -85,6 +85,7 @@ struct net_context {
 	int opt_wipe;
 	const char *opt_precheck;
 	int opt_no_dns_updates;
+	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 ffa67d8f525..7ed4ab093aa 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -173,6 +173,120 @@ static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
 }
 
 
+#ifdef HAVE_JANSSON
+#include <jansson.h>
+#include "audit_logging.h" /* various JSON helpers */
+#include "auth/common_auth.h"
+
+/*
+ * note: JSON output deliberately bypasses gettext so as to provide the same
+ * output irrespective of the locale.
+ */
+
+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();
+	TALLOC_CTX *ctx = NULL;
+	char *json = NULL;
+
+	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) {
+		goto failure;
+	}
+
+	ret = json_add_string (&jsobj, "LDAP server name", ads->config.ldap_server_name);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_string (&jsobj, "Realm", ads->config.realm);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_string (&jsobj, "Bind Path", ads->config.bind_path);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_int (&jsobj, "LDAP port", ads->ldap.port);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_int (&jsobj, "Server time", ads->config.current_time);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_string (&jsobj, "KDC server", ads->auth.kdc_server);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_int (&jsobj, "Server time offset", ads->auth.time_offset);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_int (&jsobj, "Last machine account password change", pass_time);
+	if (ret) {
+		goto failure;
+	}
+
+	if (json_is_invalid(&jsobj)) {
+		ret = -1;
+		goto failure;
+	}
+
+	ctx = talloc_new(NULL);
+	if (ctx == NULL) {
+		ret = -1;
+		d_fprintf(stderr, _("Out of memory\n"));
+
+		goto failure;
+	}
+
+	json = json_to_string(ctx, &jsobj);
+	if (json) {
+		d_printf("%s\n", json);
+	} else {
+		ret = -1;
+		d_fprintf(stderr, _("error encoding to JSON\n"));
+	}
+
+	TALLOC_FREE(ctx);
+failure:
+	ads_destroy(&ads);
+
+	return ret;
+}
+
+#else /* [HAVE_JANSSON] */
+
+static int net_ads_info_json(ADS_STRUCT *)
+{
+	d_fprintf(stderr, _("JSON support not available\n"));
+
+	return -1;
+}
+
+#endif /* [HAVE_JANSSON] */
+
+
 
 static int net_ads_info(struct net_context *c, int argc, const char **argv)
 {
@@ -208,6 +322,10 @@ static int net_ads_info(struct net_context *c, int argc, const char **argv)
 		d_fprintf( stderr, _("Failed to get server's current time!\n"));
 	}
 
+	if (c->opt_json) {
+		return net_ads_info_json(ads);
+	}
+
 	pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
 
 	print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
diff --git a/source3/utils/wscript_build b/source3/utils/wscript_build
index 8b4d890d485..09b3306d0a4 100644
--- a/source3/utils/wscript_build
+++ b/source3/utils/wscript_build
@@ -248,6 +248,8 @@ bld.SAMBA3_BINARY('net',
                  printing_migrate
                  trusts_util
                  IDMAP_AUTORID_TDB
+                 jansson
+                 common_auth
                  ''')
 
 bld.SAMBA3_BINARY('mvxattr',
-- 
2.17.1


From 171d462c8d0644175c30789e72ec3cfe1b24bb7e Mon Sep 17 00:00:00 2001
From: Philipp Gesang <philipp.gesang at intra2net.com>
Date: Tue, 3 Jul 2018 12:09:17 +0200
Subject: [PATCH v4 5/5] s3: net: implement json output for ads lookup

Add JSON printer (option '-j') 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.

Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
---
 source3/utils/net_ads.c | 280 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 248 insertions(+), 32 deletions(-)

diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index 7ed4ab093aa..be23d998345 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,242 @@ 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) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Response Type", response_type);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_guid(&jsobj, "GUID", &reply->domain_uuid);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is a PDC", reply->server_type & NBT_SERVER_PDC);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is a GC of the forest", reply->server_type & NBT_SERVER_GC);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is an LDAP server", reply->server_type & NBT_SERVER_LDAP);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Supports DS", reply->server_type & NBT_SERVER_DS);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is running a KDC", reply->server_type & NBT_SERVER_KDC);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is running time services", reply->server_type & NBT_SERVER_TIMESERV);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is the closest DC", reply->server_type & NBT_SERVER_CLOSEST);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is writable", reply->server_type & NBT_SERVER_WRITABLE);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Has a hardware clock", reply->server_type & NBT_SERVER_GOOD_TIMESERV);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Is a non-domain NC serviced by LDAP server", reply->server_type & NBT_SERVER_NDNC);
+	if (ret) {
+		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) {
+		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) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Runs Active Directory Web Services", reply->server_type & NBT_SERVER_ADS_WEB_SERVICE);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_bool(&flagsobj, "Runs on Windows 2012 or later", reply->server_type & NBT_SERVER_DS_8);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Forest", reply->forest);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Domain", reply->dns_domain);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Domain Controller", reply->pdc_dns_name);
+	if (ret) {
+		goto failure;
+	}
+
+
+	ret = json_add_string(&jsobj, "Pre-Win2k Domain", reply->domain_name);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Pre-Win2k Hostname", reply->pdc_name);
+	if (ret) {
+		goto failure;
+	}
+
+	if (*reply->user_name) {
+		ret = json_add_string(&jsobj, "User name", reply->user_name);
+		if (ret) {
+			goto failure;
+		}
+	}
+
+	ret = json_add_string(&jsobj, "Server Site Name", reply->server_site);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_string(&jsobj, "Client Site Name", reply->client_site);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_int(&jsobj, "NT Version", reply->nt_version);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_int(&jsobj, "LMNT Token", reply->lmnt_token);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_int(&jsobj, "LM20 Token", reply->lm20_token);
+	if (ret) {
+		goto failure;
+	}
+
+	ret = json_add_object(&jsobj, "Flags", &flagsobj);
+	if (ret) {
+		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 +312,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);
 
@@ -174,14 +420,6 @@ static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
 
 
 #ifdef HAVE_JANSSON
-#include <jansson.h>
-#include "audit_logging.h" /* various JSON helpers */
-#include "auth/common_auth.h"
-
-/*
- * note: JSON output deliberately bypasses gettext so as to provide the same
- * output irrespective of the locale.
- */
 
 static int net_ads_info_json(ADS_STRUCT *ads)
 {
@@ -189,8 +427,6 @@ static int net_ads_info_json(ADS_STRUCT *ads)
 	char addr[INET6_ADDRSTRLEN];
 	time_t pass_time;
 	struct json_object jsobj = json_new_object();
-	TALLOC_CTX *ctx = NULL;
-	char *json = NULL;
 
 	if (json_is_invalid(&jsobj)) {
 		d_fprintf(stderr, _("error setting up JSON value\n"));
@@ -247,29 +483,9 @@ static int net_ads_info_json(ADS_STRUCT *ads)
 		goto failure;
 	}
 
-	if (json_is_invalid(&jsobj)) {
-		ret = -1;
-		goto failure;
-	}
-
-	ctx = talloc_new(NULL);
-	if (ctx == NULL) {
-		ret = -1;
-		d_fprintf(stderr, _("Out of memory\n"));
-
-		goto failure;
-	}
-
-	json = json_to_string(ctx, &jsobj);
-	if (json) {
-		d_printf("%s\n", json);
-	} else {
-		ret = -1;
-		d_fprintf(stderr, _("error encoding to JSON\n"));
-	}
-
-	TALLOC_FREE(ctx);
+	ret = output_json(&jsobj);
 failure:
+	json_free(&jsobj);
 	ads_destroy(&ads);
 
 	return ret;
-- 
2.17.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20180713/357b517b/signature.sig>


More information about the samba-technical mailing list