[RFC PATCH v3 5/5] s3: net: implement json output for ads lookup

Gary Lockyer gary at catalyst.net.nz
Thu Jul 12 19:30:58 UTC 2018


See comments in line.

But looks good.
Gary

On 12/07/18 19:04, Philipp Gesang via samba-technical wrote:
> 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 | 270 +++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 244 insertions(+), 26 deletions(-)
> 
> diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
> index c2350ca027f..ef0f4ee44f8 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,239 @@ 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)
> +{
> +	char *json = NULL;
> +
> +	if (json_is_invalid(jsobj)) {
> +		return -1;
> +	}
> +
Should be no need for this, json_is_invalid should be sufficient.
json_object should really be an opaque pointer and I'd like code not to
rely on it's internals.

> +	if (jsobj->root == NULL) {
> +		return -1;
> +	}
> +
        Use json_to_string here.
> +	json = json_dumps(jsobj->root, 0);
> +	if (!json) {
> +		d_fprintf(stderr, _("error encoding to JSON\n"));
> +		return -1;
> +	}
> +
> +	d_printf("%s\n", json);
> +	free (json);
> +
> +	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 +309,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 +417,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)
>  {
> @@ -245,24 +480,7 @@ static int net_ads_info_json(ADS_STRUCT *ads)
>  		goto failure;
>  	}
>  
> -	if (json_is_invalid(&jsobj)) {
> -		ret = -1;
> -		goto failure;
> -	}
> -
> -	if (jsobj.root == NULL) {
> -		ret = -1;
> -		goto failure;
> -	}
> -
> -	json = json_dumps(jsobj.root, 0);
> -	if (json) {
> -		d_printf("%s\n", json);
> -		free (json);
> -	} else {
> -		ret = -1;
> -		d_fprintf(stderr, _("error encoding to JSON\n"));
> -	}
> +	ret = output_json(&jsobj);
>  
>  failure:
>  	json_free(&jsobj);
> 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20180713/367fbe67/signature.sig>


More information about the samba-technical mailing list