s3-rpc_client: Move client pipe functions to own header.
[samba.git] / source3 / utils / net_ads.c
index 8e9f412d6c85b72d74b013f539d991a1832c226b..45238049a6bb694cb258e8c4a0171373eebf199e 100644 (file)
 
 #include "includes.h"
 #include "utils/net.h"
+#include "rpc_client/cli_pipe.h"
 #include "librpc/gen_ndr/ndr_krb5pac.h"
-#include "../librpc/gen_ndr/cli_spoolss.h"
+#include "../librpc/gen_ndr/ndr_spoolss.h"
 #include "nsswitch/libwbclient/wbclient.h"
+#include "ads.h"
+#include "libads/cldap.h"
+#include "libads/dns.h"
+#include "../libds/common/flags.h"
+#include "librpc/gen_ndr/libnet_join.h"
+#include "libnet/libnet_join.h"
+#include "smb_krb5.h"
+#include "secrets.h"
+#include "krb5_env.h"
+#include "../libcli/security/security.h"
 
 #ifdef HAVE_ADS
 
@@ -103,7 +114,7 @@ static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
        printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
        printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
 
-       printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain);
+       printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
        printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
 
        if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
@@ -128,9 +139,11 @@ static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
        int ret;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
-                          "net ads lookup\n"
-                          "    ",_("Find the ADS DC using CLDAP lookup.\n"));
+               d_printf("%s\n"
+                        "net ads lookup\n"
+                        "    %s",
+                        _("Usage:"),
+                        _("Find the ADS DC using CLDAP lookup.\n"));
                return 0;
        }
 
@@ -158,10 +171,11 @@ static int net_ads_info(struct net_context *c, int argc, const char **argv)
        char addr[INET6_ADDRSTRLEN];
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
-                          "net ads info\n",
-                          "    ",
-                          _("Display information about an Active Directory "
+               d_printf("%s\n"
+                        "net ads info\n"
+                        "    %s",
+                        _("Usage:"),
+                        _("Display information about an Active Directory "
                           "server.\n"));
                return 0;
        }
@@ -373,9 +387,11 @@ static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
        struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf  ("%s\n"
                           "net ads workgroup\n"
-                          "    ",_("Print the workgroup name\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Print the workgroup name"));
                return 0;
        }
 
@@ -396,7 +412,7 @@ static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
                return -1;
        }
 
-       d_printf(_("Workgroup: %s\n"), reply.domain);
+       d_printf(_("Workgroup: %s\n"), reply.domain_name);
 
        ads_destroy(&ads);
 
@@ -470,7 +486,7 @@ static int ads_user_add(struct net_context *c, int argc, const char **argv)
        if (c->opt_container) {
                ou_str = SMB_STRDUP(c->opt_container);
        } else {
-               ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
+               ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
        }
 
        status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
@@ -534,9 +550,9 @@ static int ads_user_info(struct net_context *c, int argc, const char **argv)
        char **grouplist;
        char *primary_group;
        char *escaped_user;
-       DOM_SID primary_group_sid;
+       struct dom_sid primary_group_sid;
        uint32_t group_rid;
-       enum SID_NAME_USE type;
+       enum wbcSidType type;
 
        if (argc < 1 || c->display_usage) {
                return net_ads_user_usage(c, argc, argv);
@@ -591,7 +607,7 @@ static int ads_user_info(struct net_context *c, int argc, const char **argv)
        wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
                                  NULL, /* don't look up domain */
                                  &primary_group,
-                                 (enum wbcSidType *) &type);
+                                 &type);
        if (!WBC_ERROR_IS_OK(wbc_status)) {
                d_fprintf(stderr, "wbcLookupSid: %s\n",
                          wbcErrorString(wbc_status));
@@ -698,9 +714,11 @@ int net_ads_user(struct net_context *c, int argc, const char **argv)
 
        if (argc == 0) {
                if (c->display_usage) {
-                       d_printf(_("Usage:\n"),
+                       d_printf(  "%s\n"
                                   "net ads user\n"
-                                  "    ",_("List AD users\n"));
+                                  "    %s\n",
+                                _("Usage:"),
+                                _("List AD users"));
                        net_display_usage_from_functable(func);
                        return 0;
                }
@@ -762,7 +780,7 @@ static int ads_group_add(struct net_context *c, int argc, const char **argv)
        if (c->opt_container) {
                ou_str = SMB_STRDUP(c->opt_container);
        } else {
-               ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
+               ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
        }
 
        status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
@@ -849,9 +867,11 @@ int net_ads_group(struct net_context *c, int argc, const char **argv)
 
        if (argc == 0) {
                if (c->display_usage) {
-                       d_printf(_("Usage:\n"),
+                       d_printf(  "%s\n"
                                   "net ads group\n"
-                                  "    ", _("List AD groups\n"));
+                                  "    %s\n",
+                                _("Usage:"),
+                                _("List AD groups"));
                        net_display_usage_from_functable(func);
                        return 0;
                }
@@ -883,9 +903,11 @@ static int net_ads_status(struct net_context *c, int argc, const char **argv)
        LDAPMessage *res;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
                           "net ads status\n"
-                          "    ",_("Display machine account details\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Display machine account details"));
                return 0;
        }
 
@@ -925,9 +947,11 @@ static int net_ads_leave(struct net_context *c, int argc, const char **argv)
        WERROR werr;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
                           "net ads leave\n"
-                          "    ", _("Leave an AD domain\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Leave an AD domain"));
                return 0;
        }
 
@@ -945,6 +969,12 @@ static int net_ads_leave(struct net_context *c, int argc, const char **argv)
                use_in_memory_ccache();
        }
 
+       if (!c->msg_ctx) {
+               d_fprintf(stderr, _("Could not initialise message context. "
+                       "Try running as root\n"));
+               return -1;
+       }
+
        werr = libnet_init_UnjoinCtx(ctx, &r);
        if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
@@ -964,6 +994,7 @@ static int net_ads_leave(struct net_context *c, int argc, const char **argv)
        r->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
                                  WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
        r->in.delete_machine_account = true;
+       r->in.msg_ctx           = c->msg_ctx;
 
        werr = libnet_Unjoin(ctx, r);
        if (!W_ERROR_IS_OK(werr)) {
@@ -1038,9 +1069,11 @@ int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
        use_in_memory_ccache();
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
                           "net ads testjoin\n"
-                          "    ", _("Test if the existing join is ok\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Test if the existing join is ok"));
                return 0;
        }
 
@@ -1100,7 +1133,7 @@ static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
                                        int num_addrs)
 {
        struct dns_rr_ns *nameservers = NULL;
-       int ns_count = 0;
+       int ns_count = 0, i;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
        DNS_ERROR dns_err;
        fstring dns_server;
@@ -1165,14 +1198,31 @@ static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
 
        }
 
-       /* Now perform the dns update - we'll try non-secure and if we fail,
-          we'll follow it up with a secure update */
+       for (i=0; i < ns_count; i++) {
+
+               /* Now perform the dns update - we'll try non-secure and if we fail,
+                  we'll follow it up with a secure update */
 
-       fstrcpy( dns_server, nameservers[0].hostname );
+               fstrcpy( dns_server, nameservers[i].hostname );
+
+               dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
+               if (ERR_DNS_IS_OK(dns_err)) {
+                       status = NT_STATUS_OK;
+                       goto done;
+               }
 
-       dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
-       if (!ERR_DNS_IS_OK(dns_err)) {
+               if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
+                   ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
+                   ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
+                       DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
+                               dns_errstr(dns_err)));
+                       continue;
+               }
+
+               d_printf(_("DNS Update for %s failed: %s\n"),
+                       machine_name, dns_errstr(dns_err));
                status = NT_STATUS_UNSUCCESSFUL;
+               goto done;
        }
 
 done:
@@ -1182,29 +1232,48 @@ done:
        return status;
 }
 
-static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
+static NTSTATUS net_update_dns_ext(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
+                                  const char *hostname,
+                                  struct sockaddr_storage *iplist,
+                                  int num_addrs)
 {
-       int num_addrs;
-       struct sockaddr_storage *iplist = NULL;
+       struct sockaddr_storage *iplist_alloc = NULL;
        fstring machine_name;
        NTSTATUS status;
 
-       name_to_fqdn( machine_name, global_myname() );
+       if (hostname) {
+               fstrcpy(machine_name, hostname);
+       } else {
+               name_to_fqdn( machine_name, global_myname() );
+       }
        strlower_m( machine_name );
 
-       /* Get our ip address (not the 127.0.0.x address but a real ip
-        * address) */
-
-       num_addrs = get_my_ip_address( &iplist );
-       if ( num_addrs <= 0 ) {
-               DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
-                        "addresses!\n"));
-               return NT_STATUS_INVALID_PARAMETER;
+       if (num_addrs == 0 || iplist == NULL) {
+               /*
+                * Get our ip address
+                * (not the 127.0.0.x address but a real ip address)
+                */
+               num_addrs = get_my_ip_address(&iplist_alloc);
+               if ( num_addrs <= 0 ) {
+                       DEBUG(4, ("net_update_dns_ext: Failed to find my "
+                                 "non-loopback IP addresses!\n"));
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+               iplist = iplist_alloc;
        }
 
        status = net_update_dns_internal(mem_ctx, ads, machine_name,
                                         iplist, num_addrs);
-       SAFE_FREE( iplist );
+
+       SAFE_FREE(iplist_alloc);
+       return status;
+}
+
+static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
+{
+       NTSTATUS status;
+
+       status = net_update_dns_ext(mem_ctx, ads, hostname, NULL, 0);
        return status;
 }
 #endif
@@ -1316,6 +1385,13 @@ int net_ads_join(struct net_context *c, int argc, const char **argv)
                goto fail;
        }
 
+       if (!c->msg_ctx) {
+               d_fprintf(stderr, _("Could not initialise message context. "
+                       "Try running as root\n"));
+               werr = WERR_ACCESS_DENIED;
+               goto fail;
+       }
+
        /* Do the domain join here */
 
        r->in.domain_name       = domain;
@@ -1333,6 +1409,7 @@ int net_ads_join(struct net_context *c, int argc, const char **argv)
        r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
                                  WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
                                  WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
+       r->in.msg_ctx           = c->msg_ctx;
 
        werr = libnet_Join(ctx, r);
        if (!W_ERROR_IS_OK(werr)) {
@@ -1361,6 +1438,23 @@ int net_ads_join(struct net_context *c, int argc, const char **argv)
        }
 
 #if defined(WITH_DNS_UPDATES)
+       /*
+        * In a clustered environment, don't do dynamic dns updates:
+        * Registering the set of ip addresses that are assigned to
+        * the interfaces of the node that performs the join does usually
+        * not have the desired effect, since the local interfaces do not
+        * carry the complete set of the cluster's public IP addresses.
+        * And it can also contain internal addresses that should not
+        * be visible to the outside at all.
+        * In order to do dns updates in a clustererd setup, use
+        * net ads dns register.
+        */
+       if (lp_clustering()) {
+               d_fprintf(stderr, _("Not doing automatic DNS update in a"
+                                   "clustered setup.\n"));
+               goto done;
+       }
+
        if (r->out.domain_is_ad) {
                /* We enter this block with user creds */
                ADS_STRUCT *ads_dns = NULL;
@@ -1379,14 +1473,17 @@ int net_ads_join(struct net_context *c, int argc, const char **argv)
                        ads_kinit_password( ads_dns );
                }
 
-               if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
+               if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns, NULL)) ) {
                        d_fprintf( stderr, _("DNS update failed!\n") );
                }
 
                /* exit from this block using machine creds */
                ads_destroy(&ads_dns);
        }
+
+done:
 #endif
+
        TALLOC_FREE(r);
        TALLOC_FREE( ctx );
 
@@ -1410,16 +1507,31 @@ static int net_ads_dns_register(struct net_context *c, int argc, const char **ar
 #if defined(WITH_DNS_UPDATES)
        ADS_STRUCT *ads;
        ADS_STATUS status;
+       NTSTATUS ntstatus;
        TALLOC_CTX *ctx;
+       const char *hostname = NULL;
+       const char **addrs_list = NULL;
+       struct sockaddr_storage *addrs = NULL;
+       int num_addrs = 0;
+       int count;
 
 #ifdef DEVELOPER
        talloc_enable_leak_report();
 #endif
 
-       if (argc > 0 || c->display_usage) {
-               d_printf(_("Usage:\n"),
-                          "net ads dns register\n"
-                          "    ", _("Register hostname with DNS\n"));
+       if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
+               d_fprintf(stderr, _("Refusing DNS updates with automatic "
+                                   "detection of addresses in a clustered "
+                                   "setup.\n"));
+               c->display_usage = true;
+       }
+
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads dns register [hostname [IP [IP...]]]\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Register hostname with DNS\n"));
                return -1;
        }
 
@@ -1428,6 +1540,37 @@ static int net_ads_dns_register(struct net_context *c, int argc, const char **ar
                return -1;
        }
 
+       if (argc >= 1) {
+               hostname = argv[0];
+       }
+
+       if (argc > 1) {
+               num_addrs = argc - 1;
+               addrs_list = &argv[1];
+       } else if (lp_clustering()) {
+               addrs_list = lp_cluster_addresses();
+               num_addrs = str_list_length(addrs_list);
+       }
+
+       if (num_addrs > 0) {
+               addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
+               if (addrs == NULL) {
+                       d_fprintf(stderr, _("Error allocating memory!\n"));
+                       talloc_free(ctx);
+                       return -1;
+               }
+       }
+
+       for (count = 0; count < num_addrs; count++) {
+               if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
+                       d_fprintf(stderr, "%s '%s'.\n",
+                                         _("Cannot interpret address"),
+                                         addrs_list[count]);
+                       talloc_free(ctx);
+                       return -1;
+               }
+       }
+
        status = ads_startup(c, true, &ads);
        if ( !ADS_ERR_OK(status) ) {
                DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
@@ -1435,7 +1578,8 @@ static int net_ads_dns_register(struct net_context *c, int argc, const char **ar
                return -1;
        }
 
-       if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
+       ntstatus = net_update_dns_ext(ctx, ads, hostname, addrs, num_addrs);
+       if (!NT_STATUS_IS_OK(ntstatus)) {
                d_fprintf( stderr, _("DNS update failed!\n") );
                ads_destroy( &ads );
                TALLOC_FREE( ctx );
@@ -1469,7 +1613,10 @@ static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char
 #endif
 
        if (argc != 2 || c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
+                          "    %s\n"
+                          "    %s\n",
+                        _("Usage:"),
                         _("net ads dns gethostbyname <server> <name>\n"),
                         _("  Look up hostname from the AD\n"
                           "    server\tName server to use\n"
@@ -1479,7 +1626,8 @@ static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char
 
        err = do_gethostbyname(argv[0], argv[1]);
 
-       d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
+       d_printf(_("do_gethostbyname returned %s (%d)\n"),
+               dns_errstr(err), ERROR_DNS_V(err));
 #endif
        return 0;
 }
@@ -1539,9 +1687,11 @@ static int net_ads_printer_search(struct net_context *c, int argc, const char **
        LDAPMessage *res = NULL;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
                           "net ads printer search\n"
-                          "    ", _("List printers in the AD\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("List printers in the AD"));
                return 0;
        }
 
@@ -1579,8 +1729,9 @@ static int net_ads_printer_info(struct net_context *c, int argc, const char **ar
        LDAPMessage *res = NULL;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
-                          _("net ads printer info [printername [servername]]\n"
+               d_printf("%s\n%s",
+                        _("Usage:"),
+                        _("net ads printer info [printername [servername]]\n"
                           "  Display printer info from AD\n"
                           "    printername\tPrinter name or wildcard\n"
                           "    servername\tName of the print server\n"));
@@ -1643,8 +1794,9 @@ static int net_ads_printer_publish(struct net_context *c, int argc, const char *
        LDAPMessage *res = NULL;
 
        if (argc < 1 || c->display_usage) {
-               d_printf(_("Usage:\n"),
-                          _("net ads printer publish <printername> [servername]\n"
+               d_printf("%s\n%s",
+                        _("Usage:"),
+                        _("net ads printer publish <printername> [servername]\n"
                           "  Publish printer in AD\n"
                           "    printername\tName of the printer\n"
                           "    servername\tName of the print server\n"));
@@ -1675,7 +1827,7 @@ static int net_ads_printer_publish(struct net_context *c, int argc, const char *
                                        c->opt_user_name, c->opt_workgroup,
                                        c->opt_password ? c->opt_password : "",
                                        CLI_FULL_CONNECTION_USE_KERBEROS,
-                                       Undefined, NULL);
+                                       Undefined);
 
        if (NT_STATUS_IS_ERR(nt_status)) {
                d_fprintf(stderr, _("Unable to open a connnection to %s to "
@@ -1769,8 +1921,9 @@ static int net_ads_printer_remove(struct net_context *c, int argc, const char **
        LDAPMessage *res = NULL;
 
        if (argc < 1 || c->display_usage) {
-               d_printf(_("Usage:\n"),
-                          _("net ads printer remove <printername> [servername]\n"
+               d_printf("%s\n%s",
+                        _("Usage:"),
+                        _("net ads printer remove <printername> [servername]\n"
                           "  Remove a printer from the AD\n"
                           "    printername\tName of the printer\n"
                           "    servername\tName of the print server\n"));
@@ -1872,8 +2025,9 @@ static int net_ads_password(struct net_context *c, int argc, const char **argv)
        ADS_STATUS ret;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
-                          _("net ads password <username>\n"
+               d_printf("%s\n%s",
+                        _("Usage:"),
+                        _("net ads password <username>\n"
                           "  Change password for user\n"
                           "    username\tName of user to change password for\n"));
                return 0;
@@ -1955,9 +2109,11 @@ int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
        ADS_STATUS ret;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
                           "net ads changetrustpw\n"
-                          "    ", _("Change the machine account's trust password\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Change the machine account's trust password"));
                return 0;
        }
 
@@ -2153,7 +2309,7 @@ static int net_ads_sid(struct net_context *c, int argc, const char **argv)
        const char *sid_string;
        const char **attrs;
        LDAPMessage *res = NULL;
-       DOM_SID sid;
+       struct dom_sid sid;
 
        if (argc < 1 || c->display_usage) {
                return net_ads_sid_usage(c, argc, argv);
@@ -2196,9 +2352,11 @@ static int net_ads_keytab_flush(struct net_context *c, int argc, const char **ar
        ADS_STRUCT *ads;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
                           "net ads keytab flush\n"
-                          "    ", _("Delete the whole keytab\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Delete the whole keytab"));
                return 0;
        }
 
@@ -2217,8 +2375,9 @@ static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv
        ADS_STRUCT *ads;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
-                          _("net ads keytab add <principal> [principal ...]\n"
+               d_printf("%s\n%s",
+                        _("Usage:"),
+                        _("net ads keytab add <principal> [principal ...]\n"
                           "  Add principals to local keytab\n"
                           "    principal\tKerberos principal to add to "
                           "keytab\n"));
@@ -2242,9 +2401,11 @@ static int net_ads_keytab_create(struct net_context *c, int argc, const char **a
        int ret;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
                           "net ads keytab create\n"
-                          "    ", _("Create new default keytab\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Create new default keytab"));
                return 0;
        }
 
@@ -2261,8 +2422,9 @@ static int net_ads_keytab_list(struct net_context *c, int argc, const char **arg
        const char *keytab = NULL;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
-                          _("net ads keytab list [keytab]\n"
+               d_printf("%s\n%s",
+                        _("Usage:"),
+                        _("net ads keytab list [keytab]\n"
                           "  List a local keytab\n"
                           "    keytab\tKeytab to list\n"));
                return 0;
@@ -2327,9 +2489,11 @@ static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **
        int ret = -1;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
                           "net ads kerberos renew\n"
-                          "    ", _("Renew TGT from existing credential cache\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Renew TGT from existing credential cache"));
                return 0;
        }
 
@@ -2343,7 +2507,6 @@ static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **
 
 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
 {
-       struct PAC_DATA *pac = NULL;
        struct PAC_LOGON_INFO *info = NULL;
        TALLOC_CTX *mem_ctx = NULL;
        NTSTATUS status;
@@ -2351,9 +2514,11 @@ static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **ar
        const char *impersonate_princ_s = NULL;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
                           "net ads kerberos pac\n"
-                          "    ", _("Dump the Kerberos PAC\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Dump the Kerberos PAC"));
                return 0;
        }
 
@@ -2371,7 +2536,7 @@ static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **ar
        status = kerberos_return_pac(mem_ctx,
                                     c->opt_user_name,
                                     c->opt_password,
-                                    0,
+                                    0,
                                     NULL,
                                     NULL,
                                     NULL,
@@ -2379,14 +2544,13 @@ static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **ar
                                     true,
                                     2592000, /* one month */
                                     impersonate_princ_s,
-                                    &pac);
+                                    &info);
        if (!NT_STATUS_IS_OK(status)) {
                d_printf(_("failed to query kerberos PAC: %s\n"),
                        nt_errstr(status));
                goto out;
        }
 
-       info = get_logon_info_from_pac(pac);
        if (info) {
                const char *s;
                s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
@@ -2406,9 +2570,11 @@ static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **
        NTSTATUS status;
 
        if (c->display_usage) {
-               d_printf(_("Usage:\n"),
+               d_printf(  "%s\n"
                           "net ads kerberos kinit\n"
-                          "    ", _("Get Ticket Granting Ticket (TGT) for the user\n"));
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Get Ticket Granting Ticket (TGT) for the user"));
                return 0;
        }
 
@@ -2670,6 +2836,11 @@ int net_ads_group(struct net_context *c, int argc, const char **argv)
        return net_ads_noads();
 }
 
+int net_ads_gpo(struct net_context *c, int argc, const char **argv)
+{
+       return net_ads_noads();
+}
+
 /* this one shouldn't display a message */
 int net_ads_check(struct net_context *c)
 {