[PATCH v7] add JSON output to net ads
Philipp Gesang
philipp.gesang at intra2net.com
Thu Sep 13 07:14:20 UTC 2018
Ping.
-<| Quoting Philipp Gesang <philipp.gesang at intra2net.com>, on Tuesday, 2018-08-28 09:37:42 AM |>-
> Hi again,
>
> sending the latest revision of the JSON patches to “net ads”,
> addressing two issues raised by Andrew Bartlett.
>
> A full CI run is available:
> https://gitlab.com/samba-team/devel/samba/pipelines/28780982
>
> Best,
> Philipp
>
> -8<----------------------------------------------------------->8-
>
> Changes in v7:
> * Cause test failure on samba.tests.BlackboxProcessError.
> * Drop `-j' flag, retain long form `--json' only.
>
>
> Changes in v6:
> * Rebase on catalyst/master.
> * Don’t catch samba.tests.BlackboxProcessError in tests.
> * Move test to the “chgdcpass” set.
> * Wrap the test base class so unittest doesn’t attempt to run it.
>
>
> Changes in v5:
>
> * Rebase on catalyst/master; cleanup branch; resolve conflicts.
> * Add rudimentary blackbox tests.
> * Include another patch to make the non-JSON output more regular.
>
>
> 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-
> From 4d6a06e3fe1828fc06c2edfe3719811be4f32f12 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 v7 1/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 ac08863129a..c274e971925 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 4203743f315..5f095c0df9a 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
> --
> 2.17.1
>
>
> From b6d44d304238ee107561d2e14620298028b0ae50 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 v7 2/5] 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.
>
> 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 69564f65232..2b9c4a26b69 100644
> --- a/source3/utils/net.c
> +++ b/source3/utils/net.c
> @@ -974,6 +974,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 5e70fd3aafa..0d01ad45010 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 afe47dad839..15f14220831 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 != 0) {
> + goto failure;
> + }
> +
> + ret = json_add_string (&jsobj, "LDAP server name", ads->config.ldap_server_name);
> + if (ret != 0) {
> + goto failure;
> + }
> +
> + ret = json_add_string (&jsobj, "Realm", ads->config.realm);
> + if (ret != 0) {
> + goto failure;
> + }
> +
> + ret = json_add_string (&jsobj, "Bind Path", ads->config.bind_path);
> + if (ret != 0) {
> + goto failure;
> + }
> +
> + ret = json_add_int (&jsobj, "LDAP port", ads->ldap.port);
> + if (ret != 0) {
> + goto failure;
> + }
> +
> + ret = json_add_int (&jsobj, "Server time", ads->config.current_time);
> + if (ret != 0) {
> + goto failure;
> + }
> +
> + ret = json_add_string (&jsobj, "KDC server", ads->auth.kdc_server);
> + if (ret != 0) {
> + goto failure;
> + }
> +
> + ret = json_add_int (&jsobj, "Server time offset", ads->auth.time_offset);
> + if (ret != 0) {
> + goto failure;
> + }
> +
> + ret = json_add_int (&jsobj, "Last machine account password change", pass_time);
> + if (ret != 0) {
> + 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 93e6abaac0d..ba7ab1201b0 100644
> --- a/source3/utils/wscript_build
> +++ b/source3/utils/wscript_build
> @@ -249,6 +249,8 @@ bld.SAMBA3_BINARY('net',
> printing_migrate
> trusts_util
> IDMAP_AUTORID_TDB
> + jansson
> + common_auth
> ''')
>
> bld.SAMBA3_BINARY('mvxattr',
> --
> 2.17.1
>
>
> From d3b19aa3eb53744c9a181d909159eb21f52a229c 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 v7 3/5] 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.
>
> 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 15f14220831..ae83f8baa08 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 != 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 +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
>
>
> From 7df1e429e575e6afcee9ef09f6092176a91e3b73 Mon Sep 17 00:00:00 2001
> From: Philipp Gesang <philipp.gesang at intra2net.com>
> Date: Mon, 20 Aug 2018 15:10:31 +0200
> Subject: [PATCH v7 4/5] 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..
>
> Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
> ---
> source3/utils/net_ads.c | 16 ++++++++--------
> 1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
> index ae83f8baa08..0022bba18ab 100644
> --- a/source3/utils/net_ads.c
> +++ b/source3/utils/net_ads.c
> @@ -365,17 +365,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);
> --
> 2.17.1
>
>
> From 27c7a823566fc9010bde8abffc6f0507a0150026 Mon Sep 17 00:00:00 2001
> From: Philipp Gesang <philipp.gesang at intra2net.com>
> Date: Mon, 20 Aug 2018 14:50:39 +0200
> Subject: [PATCH v7 5/5] 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.
>
> Signed-off-by: Philipp Gesang <philipp.gesang at intra2net.com>
> ---
> python/samba/tests/blackbox/netads_json.py | 83 ++++++++++++++++++++++
> source4/selftest/tests.py | 2 +
> 2 files changed, 85 insertions(+)
> create mode 100644 python/samba/tests/blackbox/netads_json.py
>
> diff --git a/python/samba/tests/blackbox/netads_json.py b/python/samba/tests/blackbox/netads_json.py
> new file mode 100644
> index 00000000000..44db7cf8455
> --- /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"
> +PLAIN_KEY_REGEX = re.compile ("^([^ \t:][^:]*):") # extract keys from non-json version
> +
> +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/source4/selftest/tests.py b/source4/selftest/tests.py
> index 0af0504d13a..b7dc4b8ff8c 100755
> --- a/source4/selftest/tests.py
> +++ b/source4/selftest/tests.py
> @@ -445,6 +445,8 @@ plantestsuite("samba4.blackbox.client_etypes_legacy(ad_dc:client)", "ad_dc:clien
> plantestsuite("samba4.blackbox.client_etypes_strong(ad_dc:client)", "ad_dc:client", [os.path.join(bbdir, "test_client_etypes.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$PREFIX_ABS', 'strong', '17_18'])
> plantestsuite("samba4.blackbox.net_ads_dns(ad_member:local)", "ad_member:local", [os.path.join(bbdir, "test_net_ads_dns.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$USERNAME', '$PASSWORD'])
> plantestsuite_loadlist("samba4.rpc.echo against NetBIOS alias", "ad_dc_ntvfs", [valgrindify(smbtorture4), "$LISTOPT", "$LOADLIST", 'ncacn_np:$NETBIOSALIAS', '-U$DOMAIN/$USERNAME%$PASSWORD', 'rpc.echo'])
> +# json tests hook into ``chgdcpass'' to make them run in contributor CI on gitlab
> +planpythontestsuite("chgdcpass", "samba.tests.blackbox.netads_json")
>
> # Tests using the "Simple" NTVFS backend
> for t in ["base.rw1"]:
> --
> 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/20180913/ad2cff2e/signature.sig>
More information about the samba-technical
mailing list