s3-net: fix net ads dns usage calls.
[ira/wip.git] / source3 / utils / net_ads.c
index af55430fac0b8378a8f6439022b4aa33f4014b14..3cd4fd87a2dc42d58cfb86139e45749616d37d2a 100644 (file)
 
 #include "includes.h"
 #include "utils/net.h"
-
-#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_krb5pac.h"
+#include "../librpc/gen_ndr/cli_spoolss.h"
+#include "nsswitch/libwbclient/wbclient.h"
 
 #ifdef HAVE_ADS
 
-int net_ads_usage(int argc, const char **argv)
-{
-       d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
-       d_printf("    Join the local machine to a ADS realm\n");
-       d_printf("leave\n");
-       d_printf("    Remove the local machine from a ADS realm\n");
-       d_printf("testjoin\n");
-       d_printf("    Validates the machine account in the domain\n");
-       d_printf("user\n");
-       d_printf("    List, add, or delete users in the realm\n");
-       d_printf("group\n");
-       d_printf("    List, add, or delete groups in the realm\n");
-       d_printf("info\n");
-       d_printf("    Displays details regarding a specific AD server\n");
-       d_printf("status\n");
-       d_printf("    Display details regarding the machine's account in AD\n");
-       d_printf("lookup\n");
-       d_printf("    Performs CLDAP query of AD domain controllers\n");
-       d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
-       d_printf("    Change a user's password using an admin account\n");
-       d_printf("    (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
-       d_printf("changetrustpw\n");
-       d_printf("    Change the trust account password of this machine in the AD tree\n");
-       d_printf("printer [info | publish | remove] <printername> <servername>\n");
-       d_printf("    Lookup, add, or remove directory entry for a printer\n");
-       d_printf("{search,dn,sid}\n");
-       d_printf("    Issue LDAP search queries using a general filter, by DN, or by SID\n");
-       d_printf("keytab\n");
-       d_printf("    Manage a local keytab file based on the machine account in AD\n");
-       d_printf("dns\n");
-       d_printf("    Issue a dynamic DNS update request the server's hostname\n");
-       d_printf("    (using the machine credentials)\n");
-
-       return -1;
-}
-
 /* when we do not have sufficient input parameters to contact a remote domain
  * we always fall back to our own realm - Guenther*/
 
-static const char *assume_own_realm(void)
+static const char *assume_own_realm(struct net_context *c)
 {
-       if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
+       if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
                return lp_realm();
        }
 
@@ -78,72 +43,77 @@ static const char *assume_own_realm(void)
 /*
   do a cldap netlogon query
 */
-static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
+static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
 {
        char addr[INET6_ADDRSTRLEN];
-       struct nbt_cldap_netlogon_5 reply;
+       struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
 
        print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
-       if ( !ads_cldap_netlogon(addr, ads->server.realm, &reply ) ) {
-               d_fprintf(stderr, "CLDAP query failed!\n");
+       if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
+               d_fprintf(stderr, _("CLDAP query failed!\n"));
                return -1;
        }
 
-       d_printf("Information for Domain Controller: %s\n\n",
+       d_printf(_("Information for Domain Controller: %s\n\n"),
                addr);
 
-       d_printf("Response Type: ");
-       switch (reply.type) {
-       case SAMLOGON_AD_UNK_R:
-               d_printf("SAMLOGON\n");
+       d_printf(_("Response Type: "));
+       switch (reply.command) {
+       case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
+               d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
                break;
-       case SAMLOGON_AD_R:
-               d_printf("SAMLOGON_USER\n");
+       case LOGON_SAM_LOGON_RESPONSE_EX:
+               d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
                break;
        default:
-               d_printf("0x%x\n", reply.type);
+               d_printf("0x%x\n", reply.command);
                break;
        }
 
-       d_printf("GUID: %s\n", smb_uuid_string(talloc_tos(), reply.domain_uuid));
-
-       d_printf("Flags:\n"
-                "\tIs a PDC:                                   %s\n"
-                "\tIs a GC of the forest:                      %s\n"
-                "\tIs an LDAP server:                          %s\n"
-                "\tSupports DS:                                %s\n"
-                "\tIs running a KDC:                           %s\n"
-                "\tIs running time services:                   %s\n"
-                "\tIs the closest DC:                          %s\n"
-                "\tIs writable:                                %s\n"
-                "\tHas a hardware clock:                       %s\n"
-                "\tIs a non-domain NC serviced by LDAP server: %s\n",
-                (reply.server_type & ADS_PDC) ? "yes" : "no",
-                (reply.server_type & ADS_GC) ? "yes" : "no",
-                (reply.server_type & ADS_LDAP) ? "yes" : "no",
-                (reply.server_type & ADS_DS) ? "yes" : "no",
-                (reply.server_type & ADS_KDC) ? "yes" : "no",
-                (reply.server_type & ADS_TIMESERV) ? "yes" : "no",
-                (reply.server_type & ADS_CLOSEST) ? "yes" : "no",
-                (reply.server_type & ADS_WRITABLE) ? "yes" : "no",
-                (reply.server_type & ADS_GOOD_TIMESERV) ? "yes" : "no",
-                (reply.server_type & ADS_NDNC) ? "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("Pre-Win2k Domain:\t%s\n", reply.domain);
-       printf("Pre-Win2k Hostname:\t%s\n", reply.pdc_name);
-
-       if (*reply.user_name) printf("User name:\t%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);
-
-       d_printf("NT Version: %d\n", reply.nt_version);
-       d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
-       d_printf("LM20 Token: %.2x\n", reply.lm20_token);
+       d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
+
+       d_printf(_("Flags:\n"
+                  "\tIs a PDC:                                   %s\n"
+                  "\tIs a GC of the forest:                      %s\n"
+                  "\tIs an LDAP server:                          %s\n"
+                  "\tSupports DS:                                %s\n"
+                  "\tIs running a KDC:                           %s\n"
+                  "\tIs running time services:                   %s\n"
+                  "\tIs the closest DC:                          %s\n"
+                  "\tIs writable:                                %s\n"
+                  "\tHas a hardware clock:                       %s\n"
+                  "\tIs a non-domain NC serviced by LDAP server: %s\n"
+                  "\tIs NT6 DC that has some secrets:            %s\n"
+                  "\tIs NT6 DC that has all secrets:             %s\n"),
+                  (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
+                  (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("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(_("Pre-Win2k Domain:\t%s\n"), reply.domain);
+       printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
+
+       if (*reply.user_name) printf(_("User name:\t%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);
+
+       d_printf(_("NT Version: %d\n"), reply.nt_version);
+       d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
+       d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
 
        return 0;
 }
@@ -152,37 +122,61 @@ static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
   this implements the CLDAP based netlogon lookup requests
   for finding the domain controller of a ADS domain
 */
-static int net_ads_lookup(int argc, const char **argv)
+static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
+       int ret;
 
-       if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
-               d_fprintf(stderr, "Didn't find the cldap server!\n");
+       if (c->display_usage) {
+               d_printf("%s\n"
+                        "net ads lookup\n"
+                        "    %s",
+                        _("Usage:"),
+                        _("Find the ADS DC using CLDAP lookup.\n"));
+               return 0;
+       }
+
+       if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
+               d_fprintf(stderr, _("Didn't find the cldap server!\n"));
+               ads_destroy(&ads);
                return -1;
        }
 
        if (!ads->config.realm) {
-               ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
+               ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
                ads->ldap.port = 389;
        }
 
-       return net_ads_cldap_netlogon(ads);
+       ret = net_ads_cldap_netlogon(c, ads);
+       ads_destroy(&ads);
+       return ret;
 }
 
 
 
-static int net_ads_info(int argc, const char **argv)
+static int net_ads_info(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        char addr[INET6_ADDRSTRLEN];
 
-       if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
-               d_fprintf(stderr, "Didn't find the ldap server!\n");
+       if (c->display_usage) {
+               d_printf("%s\n"
+                        "net ads info\n"
+                        "    %s",
+                        _("Usage:"),
+                        _("Display information about an Active Directory "
+                          "server.\n"));
+               return 0;
+       }
+
+       if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
+               d_fprintf(stderr, _("Didn't find the ldap server!\n"));
                return -1;
        }
 
        if (!ads || !ads->config.realm) {
-               d_fprintf(stderr, "Didn't find the ldap server!\n");
+               d_fprintf(stderr, _("Didn't find the ldap server!\n"));
+               ads_destroy(&ads);
                return -1;
        }
 
@@ -190,21 +184,23 @@ static int net_ads_info(int argc, const char **argv)
           TCP LDAP session initially */
 
        if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
-               d_fprintf( stderr, "Failed to get server's current time!\n");
+               d_fprintf( stderr, _("Failed to get server's current time!\n"));
        }
 
        print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
 
-       d_printf("LDAP server: %s\n", addr);
-       d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
-       d_printf("Realm: %s\n", ads->config.realm);
-       d_printf("Bind Path: %s\n", ads->config.bind_path);
-       d_printf("LDAP port: %d\n", ads->ldap.port);
-       d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
+       d_printf(_("LDAP server: %s\n"), addr);
+       d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
+       d_printf(_("Realm: %s\n"), ads->config.realm);
+       d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
+       d_printf(_("LDAP port: %d\n"), ads->ldap.port);
+       d_printf(_("Server time: %s\n"),
+                        http_timestring(talloc_tos(), ads->config.current_time));
 
-       d_printf("KDC server: %s\n", ads->auth.kdc_server );
-       d_printf("Server time offset: %d\n", ads->auth.time_offset );
+       d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
+       d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
 
+       ads_destroy(&ads);
        return 0;
 }
 
@@ -214,15 +210,16 @@ static void use_in_memory_ccache(void) {
        setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
 }
 
-static ADS_STATUS ads_startup_int(bool only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
+static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
+                                 uint32 auth_flags, ADS_STRUCT **ads_ret)
 {
        ADS_STRUCT *ads = NULL;
        ADS_STATUS status;
-       bool need_password = False;
-       bool second_time = False;
+       bool need_password = false;
+       bool second_time = false;
        char *cp;
        const char *realm = NULL;
-       bool tried_closest_dc = False;
+       bool tried_closest_dc = false;
 
        /* lp_realm() should be handled by a command line param,
           However, the join requires that realm be set in smb.conf
@@ -235,37 +232,37 @@ retry_connect:
        if (only_own_domain) {
                realm = lp_realm();
        } else {
-               realm = assume_own_realm();
+               realm = assume_own_realm(c);
        }
 
-       ads = ads_init(realm, opt_target_workgroup, opt_host);
+       ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
 
-       if (!opt_user_name) {
-               opt_user_name = "administrator";
+       if (!c->opt_user_name) {
+               c->opt_user_name = "administrator";
        }
 
-       if (opt_user_specified) {
-               need_password = True;
+       if (c->opt_user_specified) {
+               need_password = true;
        }
 
 retry:
-       if (!opt_password && need_password && !opt_machine_pass) {
-               opt_password = net_prompt_pass(opt_user_name);
-               if (!opt_password) {
+       if (!c->opt_password && need_password && !c->opt_machine_pass) {
+               c->opt_password = net_prompt_pass(c, c->opt_user_name);
+               if (!c->opt_password) {
                        ads_destroy(&ads);
                        return ADS_ERROR(LDAP_NO_MEMORY);
                }
        }
 
-       if (opt_password) {
+       if (c->opt_password) {
                use_in_memory_ccache();
                SAFE_FREE(ads->auth.password);
-               ads->auth.password = smb_xstrdup(opt_password);
+               ads->auth.password = smb_xstrdup(c->opt_password);
        }
 
        ads->auth.flags |= auth_flags;
        SAFE_FREE(ads->auth.user_name);
-       ads->auth.user_name = smb_xstrdup(opt_user_name);
+       ads->auth.user_name = smb_xstrdup(c->opt_user_name);
 
        /*
         * If the username is of the form "name@realm",
@@ -291,8 +288,8 @@ retry:
                }
 
                if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
-                       need_password = True;
-                       second_time = True;
+                       need_password = true;
+                       second_time = true;
                        goto retry;
                } else {
                        ads_destroy(&ads);
@@ -304,11 +301,11 @@ retry:
         * This is done by reconnecting to ADS because only the first call to
         * ads_connect will give us our own sitename */
 
-       if ((only_own_domain || !opt_host) && !tried_closest_dc) {
+       if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
 
-               tried_closest_dc = True; /* avoid loop */
+               tried_closest_dc = true; /* avoid loop */
 
-               if (!ads->config.tried_closest_dc) {
+               if (!ads_closest_dc(ads)) {
 
                        namecache_delete(ads->server.realm, 0x1C);
                        namecache_delete(ads->server.workgroup, 0x1C);
@@ -324,14 +321,14 @@ retry:
        return status;
 }
 
-ADS_STATUS ads_startup(bool only_own_domain, ADS_STRUCT **ads)
+ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
 {
-       return ads_startup_int(only_own_domain, 0, ads);
+       return ads_startup_int(c, only_own_domain, 0, ads);
 }
 
-ADS_STATUS ads_startup_nobind(bool only_own_domain, ADS_STRUCT **ads)
+ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
 {
-       return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
+       return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
 }
 
 /*
@@ -359,42 +356,52 @@ static int net_ads_check_int(const char *realm, const char *workgroup, const cha
        return 0;
 }
 
-int net_ads_check_our_domain(void)
+int net_ads_check_our_domain(struct net_context *c)
 {
        return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
 }
 
-int net_ads_check(void)
+int net_ads_check(struct net_context *c)
 {
-       return net_ads_check_int(NULL, opt_workgroup, opt_host);
+       return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
 }
 
 /*
    determine the netbios workgroup name for a domain
  */
-static int net_ads_workgroup(int argc, const char **argv)
+static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        char addr[INET6_ADDRSTRLEN];
-       struct nbt_cldap_netlogon_5 reply;
+       struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
+
+       if (c->display_usage) {
+               d_printf  ("%s\n"
+                          "net ads workgroup\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Print the workgroup name"));
+               return 0;
+       }
 
-       if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
-               d_fprintf(stderr, "Didn't find the cldap server!\n");
+       if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
+               d_fprintf(stderr, _("Didn't find the cldap server!\n"));
                return -1;
        }
 
        if (!ads->config.realm) {
-               ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
+               ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
                ads->ldap.port = 389;
        }
 
        print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
-       if ( !ads_cldap_netlogon(addr, ads->server.realm, &reply ) ) {
-               d_fprintf(stderr, "CLDAP query failed!\n");
+       if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
+               d_fprintf(stderr, _("CLDAP query failed!\n"));
+               ads_destroy(&ads);
                return -1;
        }
 
-       d_printf("Workgroup: %s\n", reply.domain);
+       d_printf(_("Workgroup: %s\n"), reply.domain);
 
        ads_destroy(&ads);
 
@@ -419,24 +426,24 @@ static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *d
                }
                SAFE_FREE(disp_fields[0]);
                SAFE_FREE(disp_fields[1]);
-               return True;
+               return true;
        }
        if (!values) /* must be new field, indicate string field */
-               return True;
+               return true;
        if (StrCaseCmp(field, "sAMAccountName") == 0) {
                disp_fields[0] = SMB_STRDUP((char *) values[0]);
        }
        if (StrCaseCmp(field, "description") == 0)
                disp_fields[1] = SMB_STRDUP((char *) values[0]);
-       return True;
+       return true;
 }
 
-static int net_ads_user_usage(int argc, const char **argv)
+static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
 {
-       return net_help_user(argc, argv);
+       return net_user_usage(c, argc, argv);
 }
 
-static int ads_user_add(int argc, const char **argv)
+static int ads_user_add(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS status;
@@ -445,65 +452,70 @@ static int ads_user_add(int argc, const char **argv)
        int rc = -1;
        char *ou_str = NULL;
 
-       if (argc < 1) return net_ads_user_usage(argc, argv);
+       if (argc < 1 || c->display_usage)
+               return net_ads_user_usage(c, argc, argv);
 
-       if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                return -1;
        }
 
        status = ads_find_user_acct(ads, &res, argv[0]);
 
        if (!ADS_ERR_OK(status)) {
-               d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
+               d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
                goto done;
        }
 
        if (ads_count_replies(ads, res)) {
-               d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
+               d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
+                         argv[0]);
                goto done;
        }
 
-       if (opt_container) {
-               ou_str = SMB_STRDUP(opt_container);
+       if (c->opt_container) {
+               ou_str = SMB_STRDUP(c->opt_container);
        } else {
                ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
        }
 
-       status = ads_add_user_acct(ads, argv[0], ou_str, opt_comment);
+       status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
 
        if (!ADS_ERR_OK(status)) {
-               d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
+               d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
                         ads_errstr(status));
                goto done;
        }
 
        /* if no password is to be set, we're done */
        if (argc == 1) {
-               d_printf("User %s added\n", argv[0]);
+               d_printf(_("User %s added\n"), argv[0]);
                rc = 0;
                goto done;
        }
 
        /* try setting the password */
-       asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
+       if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
+               goto done;
+       }
        status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
                                       ads->auth.time_offset);
-       safe_free(upn);
+       SAFE_FREE(upn);
        if (ADS_ERR_OK(status)) {
-               d_printf("User %s added\n", argv[0]);
+               d_printf(_("User %s added\n"), argv[0]);
                rc = 0;
                goto done;
        }
 
        /* password didn't set, delete account */
-       d_fprintf(stderr, "Could not add user %s.  Error setting password %s\n",
+       d_fprintf(stderr, _("Could not add user %s. "
+                           "Error setting password %s\n"),
                 argv[0], ads_errstr(status));
        ads_msgfree(ads, res);
        status=ads_find_user_acct(ads, &res, argv[0]);
        if (ADS_ERR_OK(status)) {
-               userdn = ads_get_dn(ads, res);
+               userdn = ads_get_dn(ads, talloc_tos(), res);
                ads_del_dn(ads, userdn);
-               ads_memfree(ads, userdn);
+               TALLOC_FREE(userdn);
        }
 
  done:
@@ -514,43 +526,88 @@ static int ads_user_add(int argc, const char **argv)
        return rc;
 }
 
-static int ads_user_info(int argc, const char **argv)
+static int ads_user_info(struct net_context *c, int argc, const char **argv)
 {
-       ADS_STRUCT *ads;
+       ADS_STRUCT *ads = NULL;
        ADS_STATUS rc;
-       LDAPMessage *res;
-       const char *attrs[] = {"memberOf", NULL};
+       LDAPMessage *res = NULL;
+       TALLOC_CTX *frame;
+       int ret = 0;
+       wbcErr wbc_status;
+       const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
        char *searchstring=NULL;
        char **grouplist;
+       char *primary_group;
        char *escaped_user;
+       DOM_SID primary_group_sid;
+       uint32_t group_rid;
+       enum SID_NAME_USE type;
 
-       if (argc < 1) {
-               return net_ads_user_usage(argc, argv);
+       if (argc < 1 || c->display_usage) {
+               return net_ads_user_usage(c, argc, argv);
        }
 
-       escaped_user = escape_ldap_string_alloc(argv[0]);
+       frame = talloc_new(talloc_tos());
+       if (frame == NULL) {
+               return -1;
+       }
 
+       escaped_user = escape_ldap_string(frame, argv[0]);
        if (!escaped_user) {
-               d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
+               d_fprintf(stderr,
+                         _("ads_user_info: failed to escape user %s\n"),
+                         argv[0]);
                return -1;
        }
 
-       if (!ADS_ERR_OK(ads_startup(False, &ads))) {
-               SAFE_FREE(escaped_user);
-               return -1;
+       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
+               ret = -1;
+               goto error;
        }
 
-       asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
+       if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
+               ret =-1;
+               goto error;
+       }
        rc = ads_search(ads, &res, searchstring, attrs);
-       safe_free(searchstring);
+       SAFE_FREE(searchstring);
 
        if (!ADS_ERR_OK(rc)) {
-               d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
-               ads_destroy(&ads);
-               SAFE_FREE(escaped_user);
-               return -1;
+               d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
+               ret = -1;
+               goto error;
+       }
+
+       if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
+               d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
+               ret = -1;
+               goto error;
+       }
+
+       rc = ads_domain_sid(ads, &primary_group_sid);
+       if (!ADS_ERR_OK(rc)) {
+               d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
+               ret = -1;
+               goto error;
        }
 
+       sid_append_rid(&primary_group_sid, group_rid);
+
+       wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
+                                 NULL, /* don't look up domain */
+                                 &primary_group,
+                                 (enum wbcSidType *) &type);
+       if (!WBC_ERROR_IS_OK(wbc_status)) {
+               d_fprintf(stderr, "wbcLookupSid: %s\n",
+                         wbcErrorString(wbc_status));
+               ret = -1;
+               goto error;
+       }
+
+       d_printf("%s\n", primary_group);
+
+       wbcFreeMemory(primary_group);
+
        grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
                                    (LDAPMessage *)res, "memberOf");
 
@@ -565,13 +622,14 @@ static int ads_user_info(int argc, const char **argv)
                ldap_value_free(grouplist);
        }
 
-       ads_msgfree(ads, res);
-       ads_destroy(&ads);
-       SAFE_FREE(escaped_user);
-       return 0;
+error:
+       if (res) ads_msgfree(ads, res);
+       if (ads) ads_destroy(&ads);
+       TALLOC_FREE(frame);
+       return ret;
 }
 
-static int ads_user_delete(int argc, const char **argv)
+static int ads_user_delete(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS rc;
@@ -579,42 +637,63 @@ static int ads_user_delete(int argc, const char **argv)
        char *userdn;
 
        if (argc < 1) {
-               return net_ads_user_usage(argc, argv);
+               return net_ads_user_usage(c, argc, argv);
        }
 
-       if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                return -1;
        }
 
        rc = ads_find_user_acct(ads, &res, argv[0]);
        if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
-               d_printf("User %s does not exist.\n", argv[0]);
+               d_printf(_("User %s does not exist.\n"), argv[0]);
                ads_msgfree(ads, res);
                ads_destroy(&ads);
                return -1;
        }
-       userdn = ads_get_dn(ads, res);
+       userdn = ads_get_dn(ads, talloc_tos(), res);
        ads_msgfree(ads, res);
        rc = ads_del_dn(ads, userdn);
-       ads_memfree(ads, userdn);
+       TALLOC_FREE(userdn);
        if (ADS_ERR_OK(rc)) {
-               d_printf("User %s deleted\n", argv[0]);
+               d_printf(_("User %s deleted\n"), argv[0]);
                ads_destroy(&ads);
                return 0;
        }
-       d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
+       d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
                 ads_errstr(rc));
        ads_destroy(&ads);
        return -1;
 }
 
-int net_ads_user(int argc, const char **argv)
+int net_ads_user(struct net_context *c, int argc, const char **argv)
 {
        struct functable func[] = {
-               {"ADD", ads_user_add},
-               {"INFO", ads_user_info},
-               {"DELETE", ads_user_delete},
-               {NULL, NULL}
+               {
+                       "add",
+                       ads_user_add,
+                       NET_TRANSPORT_ADS,
+                       N_("Add an AD user"),
+                       N_("net ads user add\n"
+                          "    Add an AD user")
+               },
+               {
+                       "info",
+                       ads_user_info,
+                       NET_TRANSPORT_ADS,
+                       N_("Display information about an AD user"),
+                       N_("net ads user info\n"
+                          "    Display information about an AD user")
+               },
+               {
+                       "delete",
+                       ads_user_delete,
+                       NET_TRANSPORT_ADS,
+                       N_("Delete an AD user"),
+                       N_("net ads user delete\n"
+                          "    Delete an AD user")
+               },
+               {NULL, NULL, 0, NULL, NULL}
        };
        ADS_STRUCT *ads;
        ADS_STATUS rc;
@@ -623,33 +702,43 @@ int net_ads_user(int argc, const char **argv)
        char *disp_fields[2] = {NULL, NULL};
 
        if (argc == 0) {
-               if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+               if (c->display_usage) {
+                       d_printf(  "%s\n"
+                                  "net ads user\n"
+                                  "    %s\n",
+                                _("Usage:"),
+                                _("List AD users"));
+                       net_display_usage_from_functable(func);
+                       return 0;
+               }
+
+               if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                        return -1;
                }
 
-               if (opt_long_list_entries)
-                       d_printf("\nUser name             Comment"\
-                                "\n-----------------------------\n");
+               if (c->opt_long_list_entries)
+                       d_printf(_("\nUser name             Comment"
+                                  "\n-----------------------------\n"));
 
                rc = ads_do_search_all_fn(ads, ads->config.bind_path,
                                          LDAP_SCOPE_SUBTREE,
                                          "(objectCategory=user)",
-                                         opt_long_list_entries ? longattrs :
+                                         c->opt_long_list_entries ? longattrs :
                                          shortattrs, usergrp_display,
                                          disp_fields);
                ads_destroy(&ads);
                return ADS_ERR_OK(rc) ? 0 : -1;
        }
 
-       return net_run_function(argc, argv, func, net_ads_user_usage);
+       return net_run_function(c, argc, argv, "net ads user", func);
 }
 
-static int net_ads_group_usage(int argc, const char **argv)
+static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
 {
-       return net_help_group(argc, argv);
+       return net_group_usage(c, argc, argv);
 }
 
-static int ads_group_add(int argc, const char **argv)
+static int ads_group_add(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS status;
@@ -657,39 +746,39 @@ static int ads_group_add(int argc, const char **argv)
        int rc = -1;
        char *ou_str = NULL;
 
-       if (argc < 1) {
-               return net_ads_group_usage(argc, argv);
+       if (argc < 1 || c->display_usage) {
+               return net_ads_group_usage(c, argc, argv);
        }
 
-       if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                return -1;
        }
 
        status = ads_find_user_acct(ads, &res, argv[0]);
 
        if (!ADS_ERR_OK(status)) {
-               d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
+               d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
                goto done;
        }
 
        if (ads_count_replies(ads, res)) {
-               d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
+               d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
                goto done;
        }
 
-       if (opt_container) {
-               ou_str = SMB_STRDUP(opt_container);
+       if (c->opt_container) {
+               ou_str = SMB_STRDUP(c->opt_container);
        } else {
                ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
        }
 
-       status = ads_add_group_acct(ads, argv[0], ou_str, opt_comment);
+       status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
 
        if (ADS_ERR_OK(status)) {
-               d_printf("Group %s added\n", argv[0]);
+               d_printf(_("Group %s added\n"), argv[0]);
                rc = 0;
        } else {
-               d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
+               d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
                         ads_errstr(status));
        }
 
@@ -701,49 +790,63 @@ static int ads_group_add(int argc, const char **argv)
        return rc;
 }
 
-static int ads_group_delete(int argc, const char **argv)
+static int ads_group_delete(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS rc;
        LDAPMessage *res = NULL;
        char *groupdn;
 
-       if (argc < 1) {
-               return net_ads_group_usage(argc, argv);
+       if (argc < 1 || c->display_usage) {
+               return net_ads_group_usage(c, argc, argv);
        }
 
-       if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                return -1;
        }
 
        rc = ads_find_user_acct(ads, &res, argv[0]);
        if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
-               d_printf("Group %s does not exist.\n", argv[0]);
+               d_printf(_("Group %s does not exist.\n"), argv[0]);
                ads_msgfree(ads, res);
                ads_destroy(&ads);
                return -1;
        }
-       groupdn = ads_get_dn(ads, res);
+       groupdn = ads_get_dn(ads, talloc_tos(), res);
        ads_msgfree(ads, res);
        rc = ads_del_dn(ads, groupdn);
-       ads_memfree(ads, groupdn);
+       TALLOC_FREE(groupdn);
        if (ADS_ERR_OK(rc)) {
-               d_printf("Group %s deleted\n", argv[0]);
+               d_printf(_("Group %s deleted\n"), argv[0]);
                ads_destroy(&ads);
                return 0;
        }
-       d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
+       d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
                 ads_errstr(rc));
        ads_destroy(&ads);
        return -1;
 }
 
-int net_ads_group(int argc, const char **argv)
+int net_ads_group(struct net_context *c, int argc, const char **argv)
 {
        struct functable func[] = {
-               {"ADD", ads_group_add},
-               {"DELETE", ads_group_delete},
-               {NULL, NULL}
+               {
+                       "add",
+                       ads_group_add,
+                       NET_TRANSPORT_ADS,
+                       N_("Add an AD group"),
+                       N_("net ads group add\n"
+                          "    Add an AD group")
+               },
+               {
+                       "delete",
+                       ads_group_delete,
+                       NET_TRANSPORT_ADS,
+                       N_("Delete an AD group"),
+                       N_("net ads group delete\n"
+                          "    Delete an AD group")
+               },
+               {NULL, NULL, 0, NULL, NULL}
        };
        ADS_STRUCT *ads;
        ADS_STATUS rc;
@@ -752,45 +855,64 @@ int net_ads_group(int argc, const char **argv)
        char *disp_fields[2] = {NULL, NULL};
 
        if (argc == 0) {
-               if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+               if (c->display_usage) {
+                       d_printf(  "%s\n"
+                                  "net ads group\n"
+                                  "    %s\n",
+                                _("Usage:"),
+                                _("List AD groups"));
+                       net_display_usage_from_functable(func);
+                       return 0;
+               }
+
+               if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                        return -1;
                }
 
-               if (opt_long_list_entries)
-                       d_printf("\nGroup name            Comment"\
-                                "\n-----------------------------\n");
+               if (c->opt_long_list_entries)
+                       d_printf(_("\nGroup name            Comment"
+                                  "\n-----------------------------\n"));
                rc = ads_do_search_all_fn(ads, ads->config.bind_path,
                                          LDAP_SCOPE_SUBTREE,
                                          "(objectCategory=group)",
-                                         opt_long_list_entries ? longattrs :
+                                         c->opt_long_list_entries ? longattrs :
                                          shortattrs, usergrp_display,
                                          disp_fields);
 
                ads_destroy(&ads);
                return ADS_ERR_OK(rc) ? 0 : -1;
        }
-       return net_run_function(argc, argv, func, net_ads_group_usage);
+       return net_run_function(c, argc, argv, "net ads group", func);
 }
 
-static int net_ads_status(int argc, const char **argv)
+static int net_ads_status(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS rc;
        LDAPMessage *res;
 
-       if (!ADS_ERR_OK(ads_startup(True, &ads))) {
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads status\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Display machine account details"));
+               return 0;
+       }
+
+       if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
                return -1;
        }
 
        rc = ads_find_machine_acct(ads, &res, global_myname());
        if (!ADS_ERR_OK(rc)) {
-               d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
+               d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
                ads_destroy(&ads);
                return -1;
        }
 
        if (ads_count_replies(ads, res) == 0) {
-               d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
+               d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
                ads_destroy(&ads);
                return -1;
        }
@@ -807,62 +929,81 @@ static int net_ads_status(int argc, const char **argv)
  with full control to the computer object's ACL.
 *******************************************************************/
 
-static int net_ads_leave(int argc, const char **argv)
+static int net_ads_leave(struct net_context *c, int argc, const char **argv)
 {
        TALLOC_CTX *ctx;
        struct libnet_UnjoinCtx *r = NULL;
        WERROR werr;
 
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads leave\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Leave an AD domain"));
+               return 0;
+       }
+
        if (!*lp_realm()) {
-               d_fprintf(stderr, "No realm set, are we joined ?\n");
+               d_fprintf(stderr, _("No realm set, are we joined ?\n"));
                return -1;
        }
 
        if (!(ctx = talloc_init("net_ads_leave"))) {
-               d_fprintf(stderr, "Could not initialise talloc context.\n");
+               d_fprintf(stderr, _("Could not initialise talloc context.\n"));
                return -1;
        }
 
-       use_in_memory_ccache();
+       if (!c->opt_kerberos) {
+               use_in_memory_ccache();
+       }
 
        werr = libnet_init_UnjoinCtx(ctx, &r);
        if (!W_ERROR_IS_OK(werr)) {
-               d_fprintf(stderr, "Could not initialise unjoin context.\n");
+               d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
                return -1;
        }
 
        r->in.debug             = true;
-       r->in.dc_name           = opt_host;
+       r->in.use_kerberos      = c->opt_kerberos;
+       r->in.dc_name           = c->opt_host;
        r->in.domain_name       = lp_realm();
-       r->in.admin_account     = opt_user_name;
-       r->in.admin_password    = net_prompt_pass(opt_user_name);
+       r->in.admin_account     = c->opt_user_name;
+       r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
        r->in.modify_config     = lp_config_backend_is_registry();
+
+       /* Try to delete it, but if that fails, disable it.  The
+          WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
        r->in.unjoin_flags      = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
                                  WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
+       r->in.delete_machine_account = true;
 
        werr = libnet_Unjoin(ctx, r);
        if (!W_ERROR_IS_OK(werr)) {
-               d_printf("Failed to leave domain: %s\n",
+               d_printf(_("Failed to leave domain: %s\n"),
                         r->out.error_string ? r->out.error_string :
                         get_friendly_werror_msg(werr));
                goto done;
        }
 
-       if (W_ERROR_IS_OK(werr)) {
-               d_printf("Deleted account for '%s' in realm '%s'\n",
+       if (r->out.deleted_machine_account) {
+               d_printf(_("Deleted account for '%s' in realm '%s'\n"),
                        r->in.machine_name, r->out.dns_domain_name);
                goto done;
        }
 
        /* We couldn't delete it - see if the disable succeeded. */
        if (r->out.disabled_machine_account) {
-               d_printf("Disabled account for '%s' in realm '%s'\n",
+               d_printf(_("Disabled account for '%s' in realm '%s'\n"),
                        r->in.machine_name, r->out.dns_domain_name);
                werr = WERR_OK;
                goto done;
        }
 
-       d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
+       /* Based on what we requseted, we shouldn't get here, but if
+          we did, it means the secrets were removed, and therefore
+          we have left the domain */
+       d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
                  r->in.machine_name, r->out.dns_domain_name);
 
  done:
@@ -876,19 +1017,23 @@ static int net_ads_leave(int argc, const char **argv)
        return -1;
 }
 
-static NTSTATUS net_ads_join_ok(void)
+static NTSTATUS net_ads_join_ok(struct net_context *c)
 {
        ADS_STRUCT *ads = NULL;
        ADS_STATUS status;
+       fstring dc_name;
+       struct sockaddr_storage dcip;
 
        if (!secrets_init()) {
                DEBUG(1,("Failed to initialise secrets database\n"));
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       net_use_krb_machine_account();
+       net_use_krb_machine_account(c);
+
+       get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
 
-       status = ads_startup(True, &ads);
+       status = ads_startup(c, true, &ads);
        if (!ADS_ERR_OK(status)) {
                return ads_ntstatus(status);
        }
@@ -900,20 +1045,29 @@ static NTSTATUS net_ads_join_ok(void)
 /*
   check that an existing join is OK
  */
-int net_ads_testjoin(int argc, const char **argv)
+int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
 {
        NTSTATUS status;
        use_in_memory_ccache();
 
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads testjoin\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Test if the existing join is ok"));
+               return 0;
+       }
+
        /* Display success or failure */
-       status = net_ads_join_ok();
+       status = net_ads_join_ok(c);
        if (!NT_STATUS_IS_OK(status)) {
-               fprintf(stderr,"Join to domain is not valid: %s\n",
+               fprintf(stderr, _("Join to domain is not valid: %s\n"),
                        get_friendly_nt_error_msg(status));
                return -1;
        }
 
-       printf("Join is OK\n");
+       printf(_("Join is OK\n"));
        return 0;
 }
 
@@ -924,20 +1078,20 @@ int net_ads_testjoin(int argc, const char **argv)
 static WERROR check_ads_config( void )
 {
        if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
-               d_printf("Host is not configured as a member server.\n");
+               d_printf(_("Host is not configured as a member server.\n"));
                return WERR_INVALID_DOMAIN_ROLE;
        }
 
        if (strlen(global_myname()) > 15) {
-               d_printf("Our netbios name can be at most 15 chars long, "
-                        "\"%s\" is %u chars long\n", global_myname(),
+               d_printf(_("Our netbios name can be at most 15 chars long, "
+                          "\"%s\" is %u chars long\n"), global_myname(),
                         (unsigned int)strlen(global_myname()));
-               return WERR_INVALID_COMPUTER_NAME;
+               return WERR_INVALID_COMPUTERNAME;
        }
 
        if ( lp_security() == SEC_ADS && !*lp_realm()) {
-               d_fprintf(stderr, "realm must be set in in %s for ADS "
-                       "join to succeed.\n", get_dyn_CONFIGFILE());
+               d_fprintf(stderr, _("realm must be set in in %s for ADS "
+                         "join to succeed.\n"), get_dyn_CONFIGFILE());
                return WERR_INVALID_PARAM;
        }
 
@@ -969,8 +1123,8 @@ static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
        char *root_domain = NULL;
 
        if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
-               d_printf("No DNS domain configured for %s. "
-                        "Unable to perform DNS Update.\n", machine_name);
+               d_printf(_("No DNS domain configured for %s. "
+                          "Unable to perform DNS Update.\n"), machine_name);
                status = NT_STATUS_INVALID_PARAMETER;
                goto done;
        }
@@ -1074,22 +1228,22 @@ static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
 /*******************************************************************
  ********************************************************************/
 
-static int net_ads_join_usage(int argc, const char **argv)
-{
-       d_printf("net ads join [options]\n");
-       d_printf("Valid options:\n");
-       d_printf("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n");
-       d_printf("                      The deault UPN is in the form host/netbiosname@REALM.\n");
-       d_printf("   createcomputer=OU  Precreate the computer account in a specific OU.\n");
-       d_printf("                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
-       d_printf("                      E.g. \"createcomputer=Computers/Servers/Unix\"\n");
-       d_printf("                      NB: A backslash '\\' is used as escape at multiple levels and may\n");
-       d_printf("                          need to be doubled or even quadrupled.  It is not used as a separator.\n");
-       d_printf("   osName=string      Set the operatingSystem attribute during the join.\n");
-       d_printf("   osVer=string       Set the operatingSystemVersion attribute during the join.\n");
-       d_printf("                      NB: osName and osVer must be specified together for either to take effect.\n");
-       d_printf("                          Also, the operatingSystemService attribute is also set when along with\n");
-       d_printf("                          the two other attributes.\n");
+static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
+{
+       d_printf(_("net ads join [options]\n"
+                  "Valid options:\n"));
+       d_printf(_("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n"
+                  "                      The deault UPN is in the form host/netbiosname@REALM.\n"));
+       d_printf(_("   createcomputer=OU  Precreate the computer account in a specific OU.\n"
+                  "                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
+                  "                      E.g. \"createcomputer=Computers/Servers/Unix\"\n"
+                  "                      NB: A backslash '\\' is used as escape at multiple levels and may\n"
+                  "                          need to be doubled or even quadrupled.  It is not used as a separator.\n"));
+       d_printf(_("   osName=string      Set the operatingSystem attribute during the join.\n"));
+       d_printf(_("   osVer=string       Set the operatingSystemVersion attribute during the join.\n"
+                  "                      NB: osName and osVer must be specified together for either to take effect.\n"
+                  "                          Also, the operatingSystemService attribute is also set when along with\n"
+                  "                          the two other attributes.\n"));
 
        return -1;
 }
@@ -1097,13 +1251,13 @@ static int net_ads_join_usage(int argc, const char **argv)
 /*******************************************************************
  ********************************************************************/
 
-int net_ads_join(int argc, const char **argv)
+int net_ads_join(struct net_context *c, int argc, const char **argv)
 {
        TALLOC_CTX *ctx = NULL;
        struct libnet_JoinCtx *r = NULL;
        const char *domain = lp_realm();
        WERROR werr = WERR_SETUP_NOT_JOINED;
-       bool createupn = False;
+       bool createupn = false;
        const char *machineupn = NULL;
        const char *create_in_ou = NULL;
        int i;
@@ -1111,22 +1265,27 @@ int net_ads_join(int argc, const char **argv)
        const char *os_version = NULL;
        bool modify_config = lp_config_backend_is_registry();
 
+       if (c->display_usage)
+               return net_ads_join_usage(c, argc, argv);
+
        if (!modify_config) {
 
                werr = check_ads_config();
                if (!W_ERROR_IS_OK(werr)) {
-                       d_fprintf(stderr, "Invalid configuration.  Exiting....\n");
+                       d_fprintf(stderr, _("Invalid configuration.  Exiting....\n"));
                        goto fail;
                }
        }
 
        if (!(ctx = talloc_init("net_ads_join"))) {
-               d_fprintf(stderr, "Could not initialise talloc context.\n");
+               d_fprintf(stderr, _("Could not initialise talloc context.\n"));
                werr = WERR_NOMEM;
                goto fail;
        }
 
-       use_in_memory_ccache();
+       if (!c->opt_kerberos) {
+               use_in_memory_ccache();
+       }
 
        werr = libnet_init_JoinCtx(ctx, &r);
        if (!W_ERROR_IS_OK(werr)) {
@@ -1137,26 +1296,26 @@ int net_ads_join(int argc, const char **argv)
 
        for ( i=0; i<argc; i++ ) {
                if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
-                       createupn = True;
+                       createupn = true;
                        machineupn = get_string_param(argv[i]);
                }
                else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
                        if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
-                               d_fprintf(stderr, "Please supply a valid OU path.\n");
+                               d_fprintf(stderr, _("Please supply a valid OU path.\n"));
                                werr = WERR_INVALID_PARAM;
                                goto fail;
                        }
                }
                else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
                        if ( (os_name = get_string_param(argv[i])) == NULL ) {
-                               d_fprintf(stderr, "Please supply a operating system name.\n");
+                               d_fprintf(stderr, _("Please supply a operating system name.\n"));
                                werr = WERR_INVALID_PARAM;
                                goto fail;
                        }
                }
                else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
                        if ( (os_version = get_string_param(argv[i])) == NULL ) {
-                               d_fprintf(stderr, "Please supply a valid operating system version.\n");
+                               d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
                                werr = WERR_INVALID_PARAM;
                                goto fail;
                        }
@@ -1167,7 +1326,7 @@ int net_ads_join(int argc, const char **argv)
        }
 
        if (!*domain) {
-               d_fprintf(stderr, "Please supply a valid domain name\n");
+               d_fprintf(stderr, _("Please supply a valid domain name\n"));
                werr = WERR_INVALID_PARAM;
                goto fail;
        }
@@ -1180,10 +1339,11 @@ int net_ads_join(int argc, const char **argv)
        r->in.account_ou        = create_in_ou;
        r->in.os_name           = os_name;
        r->in.os_version        = os_version;
-       r->in.dc_name           = opt_host;
-       r->in.admin_account     = opt_user_name;
-       r->in.admin_password    = net_prompt_pass(opt_user_name);
+       r->in.dc_name           = c->opt_host;
+       r->in.admin_account     = c->opt_user_name;
+       r->in.admin_password    = net_prompt_pass(c, c->opt_user_name);
        r->in.debug             = true;
+       r->in.use_kerberos      = c->opt_kerberos;
        r->in.modify_config     = modify_config;
        r->in.join_flags        = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
                                  WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
@@ -1197,20 +1357,21 @@ int net_ads_join(int argc, const char **argv)
        /* Check the short name of the domain */
 
        if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
-               d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
-               d_printf("domain name obtained from the server.\n");
-               d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
-               d_printf("You should set \"workgroup = %s\" in %s.\n",
+               d_printf(_("The workgroup in %s does not match the short\n"
+                          "domain name obtained from the server.\n"
+                          "Using the name [%s] from the server.\n"
+                          "You should set \"workgroup = %s\" in %s.\n"),
+                        get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
                         r->out.netbios_domain_name, get_dyn_CONFIGFILE());
        }
 
-       d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
+       d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
 
        if (r->out.dns_domain_name) {
-               d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
+               d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
                        r->out.dns_domain_name);
        } else {
-               d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
+               d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
                        r->out.netbios_domain_name);
        }
 
@@ -1223,15 +1384,18 @@ int net_ads_join(int argc, const char **argv)
                        /* kinit with the machine password */
 
                        use_in_memory_ccache();
-                       asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
+                       if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
+                               goto fail;
+                       }
                        ads_dns->auth.password = secrets_fetch_machine_password(
                                r->out.netbios_domain_name, NULL, NULL );
                        ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
+                       strupper_m(ads_dns->auth.realm );
                        ads_kinit_password( ads_dns );
                }
 
                if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
-                       d_fprintf( stderr, "DNS update failed!\n" );
+                       d_fprintf( stderr, _("DNS update failed!\n") );
                }
 
                /* exit from this block using machine creds */
@@ -1245,7 +1409,7 @@ int net_ads_join(int argc, const char **argv)
 
 fail:
        /* issue an overall failure message at the end. */
-       d_printf("Failed to join domain: %s\n",
+       d_printf(_("Failed to join domain: %s\n"),
                r && r->out.error_string ? r->out.error_string :
                get_friendly_werror_msg(werr));
        TALLOC_FREE( ctx );
@@ -1256,24 +1420,7 @@ fail:
 /*******************************************************************
  ********************************************************************/
 
-static int net_ads_dns_usage(int argc, const char **argv)
-{
-#if defined(WITH_DNS_UPDATES)
-       d_printf("net ads dns <command>\n");
-       d_printf("Valid commands:\n");
-       d_printf("   register         Issue a dynamic DNS update request for our hostname\n");
-
-       return 0;
-#else
-       d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
-       return -1;
-#endif
-}
-
-/*******************************************************************
- ********************************************************************/
-
-static int net_ads_dns_register(int argc, const char **argv)
+static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
 {
 #if defined(WITH_DNS_UPDATES)
        ADS_STRUCT *ads;
@@ -1284,17 +1431,21 @@ static int net_ads_dns_register(int argc, const char **argv)
        talloc_enable_leak_report();
 #endif
 
-       if (argc > 0) {
-               d_fprintf(stderr, "net ads dns register\n");
+       if (argc > 0 || c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads dns register\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Register hostname with DNS\n"));
                return -1;
        }
 
        if (!(ctx = talloc_init("net_ads_dns"))) {
-               d_fprintf(stderr, "Could not initialise talloc context\n");
+               d_fprintf(stderr, _("Could not initialise talloc context\n"));
                return -1;
        }
 
-       status = ads_startup(True, &ads);
+       status = ads_startup(c, true, &ads);
        if ( !ADS_ERR_OK(status) ) {
                DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
                TALLOC_FREE(ctx);
@@ -1302,20 +1453,21 @@ static int net_ads_dns_register(int argc, const char **argv)
        }
 
        if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
-               d_fprintf( stderr, "DNS update failed!\n" );
+               d_fprintf( stderr, _("DNS update failed!\n") );
                ads_destroy( &ads );
                TALLOC_FREE( ctx );
                return -1;
        }
 
-       d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
+       d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
 
        ads_destroy(&ads);
        TALLOC_FREE( ctx );
 
        return 0;
 #else
-       d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
+       d_fprintf(stderr,
+                 _("DNS update support not enabled at compile time!\n"));
        return -1;
 #endif
 }
@@ -1324,7 +1476,7 @@ static int net_ads_dns_register(int argc, const char **argv)
 DNS_ERROR do_gethostbyname(const char *server, const char *host);
 #endif
 
-static int net_ads_dns_gethostbyname(int argc, const char **argv)
+static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
 {
 #if defined(WITH_DNS_UPDATES)
        DNS_ERROR err;
@@ -1333,36 +1485,56 @@ static int net_ads_dns_gethostbyname(int argc, const char **argv)
        talloc_enable_leak_report();
 #endif
 
-       if (argc != 2) {
-               d_fprintf(stderr, "net ads dns gethostbyname <server> "
-                         "<name>\n");
+       if (argc != 2 || c->display_usage) {
+               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"
+                          "    name\tName to look up\n"));
                return -1;
        }
 
        err = do_gethostbyname(argv[0], argv[1]);
 
-       d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
+       d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
 #endif
        return 0;
 }
 
-static int net_ads_dns(int argc, const char *argv[])
+static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
 {
        struct functable func[] = {
-               {"REGISTER", net_ads_dns_register},
-               {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
-               {NULL, NULL}
+               {
+                       "register",
+                       net_ads_dns_register,
+                       NET_TRANSPORT_ADS,
+                       N_("Add host dns entry to AD"),
+                       N_("net ads dns register\n"
+                          "    Add host dns entry to AD")
+               },
+               {
+                       "gethostbyname",
+                       net_ads_dns_gethostbyname,
+                       NET_TRANSPORT_ADS,
+                       N_("Look up host"),
+                       N_("net ads dns gethostbyname\n"
+                          "    Look up host")
+               },
+               {NULL, NULL, 0, NULL, NULL}
        };
 
-       return net_run_function(argc, argv, func, net_ads_dns_usage);
+       return net_run_function(c, argc, argv, "net ads dns", func);
 }
 
 /*******************************************************************
  ********************************************************************/
 
-int net_ads_printer_usage(int argc, const char **argv)
+int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
 {
-       d_printf(
+       d_printf(_(
 "\nnet ads printer search <printer>"
 "\n\tsearch for a printer in the directory\n"
 "\nnet ads printer info <printer> <server>"
@@ -1373,34 +1545,43 @@ int net_ads_printer_usage(int argc, const char **argv)
 "\n\t(note: printer name is required)\n"
 "\nnet ads printer remove <printername>"
 "\n\tremove printer from directory"
-"\n\t(note: printer name is required)\n");
+"\n\t(note: printer name is required)\n"));
        return -1;
 }
 
 /*******************************************************************
  ********************************************************************/
 
-static int net_ads_printer_search(int argc, const char **argv)
+static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS rc;
        LDAPMessage *res = NULL;
 
-       if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads printer search\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("List printers in the AD"));
+               return 0;
+       }
+
+       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                return -1;
        }
 
        rc = ads_find_printers(ads, &res);
 
        if (!ADS_ERR_OK(rc)) {
-               d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
+               d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
                ads_msgfree(ads, res);
                ads_destroy(&ads);
                return -1;
        }
 
        if (ads_count_replies(ads, res) == 0) {
-               d_fprintf(stderr, "No results found\n");
+               d_fprintf(stderr, _("No results found\n"));
                ads_msgfree(ads, res);
                ads_destroy(&ads);
                return -1;
@@ -1412,14 +1593,24 @@ static int net_ads_printer_search(int argc, const char **argv)
        return 0;
 }
 
-static int net_ads_printer_info(int argc, const char **argv)
+static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS rc;
        const char *servername, *printername;
        LDAPMessage *res = NULL;
 
-       if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+       if (c->display_usage) {
+               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"));
+               return 0;
+       }
+
+       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                return -1;
        }
 
@@ -1438,7 +1629,7 @@ static int net_ads_printer_info(int argc, const char **argv)
        rc = ads_find_printer_on_server(ads, &res, printername, servername);
 
        if (!ADS_ERR_OK(rc)) {
-               d_fprintf(stderr, "Server '%s' not found: %s\n",
+               d_fprintf(stderr, _("Server '%s' not found: %s\n"),
                        servername, ads_errstr(rc));
                ads_msgfree(ads, res);
                ads_destroy(&ads);
@@ -1446,7 +1637,7 @@ static int net_ads_printer_info(int argc, const char **argv)
        }
 
        if (ads_count_replies(ads, res) == 0) {
-               d_fprintf(stderr, "Printer '%s' not found\n", printername);
+               d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
                ads_msgfree(ads, res);
                ads_destroy(&ads);
                return -1;
@@ -1459,13 +1650,13 @@ static int net_ads_printer_info(int argc, const char **argv)
        return 0;
 }
 
-static int net_ads_printer_publish(int argc, const char **argv)
+static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
 {
         ADS_STRUCT *ads;
         ADS_STATUS rc;
        const char *servername, *printername;
-       struct cli_state *cli;
-       struct rpc_pipe_client *pipe_hnd;
+       struct cli_state *cli = NULL;
+       struct rpc_pipe_client *pipe_hnd = NULL;
        struct sockaddr_storage server_ss;
        NTSTATUS nt_status;
        TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
@@ -1474,14 +1665,20 @@ static int net_ads_printer_publish(int argc, const char **argv)
        char *srv_cn_escaped = NULL, *printername_escaped = NULL;
        LDAPMessage *res = NULL;
 
-       if (!ADS_ERR_OK(ads_startup(True, &ads))) {
+       if (argc < 1 || c->display_usage) {
+               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"));
                talloc_destroy(mem_ctx);
                return -1;
        }
 
-       if (argc < 1) {
+       if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
                talloc_destroy(mem_ctx);
-               return net_ads_printer_usage(argc, argv);
+               return -1;
        }
 
        printername = argv[0];
@@ -1494,19 +1691,20 @@ static int net_ads_printer_publish(int argc, const char **argv)
 
        /* Get printer data from SPOOLSS */
 
-       resolve_name(servername, &server_ss, 0x20);
+       resolve_name(servername, &server_ss, 0x20, false);
 
        nt_status = cli_full_connection(&cli, global_myname(), servername,
                                        &server_ss, 0,
                                        "IPC$", "IPC",
-                                       opt_user_name, opt_workgroup,
-                                       opt_password ? opt_password : "",
+                                       c->opt_user_name, c->opt_workgroup,
+                                       c->opt_password ? c->opt_password : "",
                                        CLI_FULL_CONNECTION_USE_KERBEROS,
                                        Undefined, NULL);
 
        if (NT_STATUS_IS_ERR(nt_status)) {
-               d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
-                        "for %s\n", servername, printername);
+               d_fprintf(stderr, _("Unable to open a connnection to %s to "
+                                   "obtain data for %s\n"),
+                         servername, printername);
                ads_destroy(&ads);
                talloc_destroy(mem_ctx);
                return -1;
@@ -1517,7 +1715,8 @@ static int net_ads_printer_publish(int argc, const char **argv)
        ads_find_machine_acct(ads, &res, servername);
 
        if (ads_count_replies(ads, res) == 0) {
-               d_fprintf(stderr, "Could not find machine account for server %s\n", 
+               d_fprintf(stderr, _("Could not find machine account for server "
+                                   "%s\n"),
                         servername);
                ads_destroy(&ads);
                talloc_destroy(mem_ctx);
@@ -1532,20 +1731,27 @@ static int net_ads_printer_publish(int argc, const char **argv)
        if (!srv_cn_escaped || !printername_escaped) {
                SAFE_FREE(srv_cn_escaped);
                SAFE_FREE(printername_escaped);
-               d_fprintf(stderr, "Internal error, out of memory!");
+               d_fprintf(stderr, _("Internal error, out of memory!"));
                ads_destroy(&ads);
                talloc_destroy(mem_ctx);
                return -1;
        }
 
-       asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
+       if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
+               SAFE_FREE(srv_cn_escaped);
+               SAFE_FREE(printername_escaped);
+               d_fprintf(stderr, _("Internal error, out of memory!"));
+               ads_destroy(&ads);
+               talloc_destroy(mem_ctx);
+               return -1;
+       }
 
        SAFE_FREE(srv_cn_escaped);
        SAFE_FREE(printername_escaped);
 
-       pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
-       if (!pipe_hnd) {
-               d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
+       nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
                         servername);
                SAFE_FREE(prt_dn);
                ads_destroy(&ads);
@@ -1578,7 +1784,7 @@ static int net_ads_printer_publish(int argc, const char **argv)
        return 0;
 }
 
-static int net_ads_printer_remove(int argc, const char **argv)
+static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS rc;
@@ -1586,12 +1792,18 @@ static int net_ads_printer_remove(int argc, const char **argv)
        char *prt_dn;
        LDAPMessage *res = NULL;
 
-       if (!ADS_ERR_OK(ads_startup(True, &ads))) {
+       if (argc < 1 || c->display_usage) {
+               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"));
                return -1;
        }
 
-       if (argc < 1) {
-               return net_ads_printer_usage(argc, argv);
+       if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
+               return -1;
        }
 
        if (argc > 1) {
@@ -1603,26 +1815,26 @@ static int net_ads_printer_remove(int argc, const char **argv)
        rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
 
        if (!ADS_ERR_OK(rc)) {
-               d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
+               d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
                ads_msgfree(ads, res);
                ads_destroy(&ads);
                return -1;
        }
 
        if (ads_count_replies(ads, res) == 0) {
-               d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
+               d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
                ads_msgfree(ads, res);
                ads_destroy(&ads);
                return -1;
        }
 
-       prt_dn = ads_get_dn(ads, res);
+       prt_dn = ads_get_dn(ads, talloc_tos(), res);
        ads_msgfree(ads, res);
        rc = ads_del_dn(ads, prt_dn);
-       ads_memfree(ads, prt_dn);
+       TALLOC_FREE(prt_dn);
 
        if (!ADS_ERR_OK(rc)) {
-               d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
+               d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
                ads_destroy(&ads);
                return -1;
        }
@@ -1631,58 +1843,99 @@ static int net_ads_printer_remove(int argc, const char **argv)
        return 0;
 }
 
-static int net_ads_printer(int argc, const char **argv)
+static int net_ads_printer(struct net_context *c, int argc, const char **argv)
 {
        struct functable func[] = {
-               {"SEARCH", net_ads_printer_search},
-               {"INFO", net_ads_printer_info},
-               {"PUBLISH", net_ads_printer_publish},
-               {"REMOVE", net_ads_printer_remove},
-               {NULL, NULL}
+               {
+                       "search",
+                       net_ads_printer_search,
+                       NET_TRANSPORT_ADS,
+                       N_("Search for a printer"),
+                       N_("net ads printer search\n"
+                          "    Search for a printer")
+               },
+               {
+                       "info",
+                       net_ads_printer_info,
+                       NET_TRANSPORT_ADS,
+                       N_("Display printer information"),
+                       N_("net ads printer info\n"
+                          "    Display printer information")
+               },
+               {
+                       "publish",
+                       net_ads_printer_publish,
+                       NET_TRANSPORT_ADS,
+                       N_("Publish a printer"),
+                       N_("net ads printer publish\n"
+                          "    Publish a printer")
+               },
+               {
+                       "remove",
+                       net_ads_printer_remove,
+                       NET_TRANSPORT_ADS,
+                       N_("Delete a printer"),
+                       N_("net ads printer remove\n"
+                          "    Delete a printer")
+               },
+               {NULL, NULL, 0, NULL, NULL}
        };
 
-       return net_run_function(argc, argv, func, net_ads_printer_usage);
+       return net_run_function(c, argc, argv, "net ads printer", func);
 }
 
 
-static int net_ads_password(int argc, const char **argv)
+static int net_ads_password(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
-       const char *auth_principal = opt_user_name;
-       const char *auth_password = opt_password;
+       const char *auth_principal = c->opt_user_name;
+       const char *auth_password = c->opt_password;
        char *realm = NULL;
        char *new_password = NULL;
-       char *c, *prompt;
+       char *chr, *prompt;
        const char *user;
        ADS_STATUS ret;
 
-       if (opt_user_name == NULL || opt_password == NULL) {
-               d_fprintf(stderr, "You must supply an administrator username/password\n");
+       if (c->display_usage) {
+               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;
+       }
+
+       if (c->opt_user_name == NULL || c->opt_password == NULL) {
+               d_fprintf(stderr, _("You must supply an administrator "
+                                   "username/password\n"));
                return -1;
        }
 
        if (argc < 1) {
-               d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
+               d_fprintf(stderr, _("ERROR: You must say which username to "
+                                   "change password for\n"));
                return -1;
        }
 
        user = argv[0];
        if (!strchr_m(user, '@')) {
-               asprintf(&c, "%s@%s", argv[0], lp_realm());
-               user = c;
+               if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
+                       return -1;
+               }
+               user = chr;
        }
 
        use_in_memory_ccache();
-       c = strchr_m(auth_principal, '@');
-       if (c) {
-               realm = ++c;
+       chr = strchr_m(auth_principal, '@');
+       if (chr) {
+               realm = ++chr;
        } else {
                realm = lp_realm();
        }
 
        /* use the realm so we can eventually change passwords for users
        in realms other than default */
-       if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
+       if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
                return -1;
        }
 
@@ -1691,14 +1944,17 @@ static int net_ads_password(int argc, const char **argv)
        ads_connect(ads);
 
        if (!ads->config.realm) {
-               d_fprintf(stderr, "Didn't find the kerberos server!\n");
+               d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
+               ads_destroy(&ads);
                return -1;
        }
 
        if (argv[1]) {
                new_password = (char *)argv[1];
        } else {
-               asprintf(&prompt, "Enter new password for %s:", user);
+               if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
+                       return -1;
+               }
                new_password = getpass(prompt);
                free(prompt);
        }
@@ -1706,57 +1962,69 @@ static int net_ads_password(int argc, const char **argv)
        ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
                                auth_password, user, new_password, ads->auth.time_offset);
        if (!ADS_ERR_OK(ret)) {
-               d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
+               d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
                ads_destroy(&ads);
                return -1;
        }
 
-       d_printf("Password change for %s completed.\n", user);
+       d_printf(_("Password change for %s completed.\n"), user);
        ads_destroy(&ads);
 
        return 0;
 }
 
-int net_ads_changetrustpw(int argc, const char **argv)
+int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        char *host_principal;
        fstring my_name;
        ADS_STATUS ret;
 
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads changetrustpw\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Change the machine account's trust password"));
+               return 0;
+       }
+
        if (!secrets_init()) {
                DEBUG(1,("Failed to initialise secrets database\n"));
                return -1;
        }
 
-       net_use_krb_machine_account();
+       net_use_krb_machine_account(c);
 
        use_in_memory_ccache();
 
-       if (!ADS_ERR_OK(ads_startup(True, &ads))) {
+       if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
                return -1;
        }
 
        fstrcpy(my_name, global_myname());
        strlower_m(my_name);
-       asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
-       d_printf("Changing password for principal: %s\n", host_principal);
+       if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
+               ads_destroy(&ads);
+               return -1;
+       }
+       d_printf(_("Changing password for principal: %s\n"), host_principal);
 
        ret = ads_change_trust_account_password(ads, host_principal);
 
        if (!ADS_ERR_OK(ret)) {
-               d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
+               d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
                ads_destroy(&ads);
                SAFE_FREE(host_principal);
                return -1;
        }
 
-       d_printf("Password change for principal %s succeeded.\n", host_principal);
+       d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
 
-       if (lp_use_kerberos_keytab()) {
-               d_printf("Attempting to update system keytab with new password.\n");
+       if (USE_SYSTEM_KEYTAB) {
+               d_printf(_("Attempting to update system keytab with new password.\n"));
                if (ads_keytab_create_default(ads)) {
-                       d_printf("Failed to update system keytab.\n");
+                       d_printf(_("Failed to update system keytab.\n"));
                }
        }
 
@@ -1769,16 +2037,16 @@ int net_ads_changetrustpw(int argc, const char **argv)
 /*
   help for net ads search
 */
-static int net_ads_search_usage(int argc, const char **argv)
+static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
 {
-       d_printf(
-               "\nnet ads search <expression> <attributes...>\n"\
-               "\nperform a raw LDAP search on a ADS server and dump the results\n"\
-               "The expression is a standard LDAP search expression, and the\n"\
-               "attributes are a list of LDAP fields to show in the results\n\n"\
+       d_printf(_(
+               "\nnet ads search <expression> <attributes...>\n"
+               "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
+               "The expression is a standard LDAP search expression, and the\n"
+               "attributes are a list of LDAP fields to show in the results.\n\n"
                "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
-               );
-       net_common_flags_usage(argc, argv);
+               ));
+       net_common_flags_usage(c, argc, argv);
        return -1;
 }
 
@@ -1786,7 +2054,7 @@ static int net_ads_search_usage(int argc, const char **argv)
 /*
   general ADS search function. Useful in diagnosing problems in ADS
 */
-static int net_ads_search(int argc, const char **argv)
+static int net_ads_search(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS rc;
@@ -1794,11 +2062,11 @@ static int net_ads_search(int argc, const char **argv)
        const char **attrs;
        LDAPMessage *res = NULL;
 
-       if (argc < 1) {
-               return net_ads_search_usage(argc, argv);
+       if (argc < 1 || c->display_usage) {
+               return net_ads_search_usage(c, argc, argv);
        }
 
-       if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                return -1;
        }
 
@@ -1809,12 +2077,12 @@ static int net_ads_search(int argc, const char **argv)
                               LDAP_SCOPE_SUBTREE,
                               ldap_exp, attrs, &res);
        if (!ADS_ERR_OK(rc)) {
-               d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
+               d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
                ads_destroy(&ads);
                return -1;
        }
 
-       d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
+       d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
 
        /* dump the results */
        ads_dump(ads, res);
@@ -1829,17 +2097,17 @@ static int net_ads_search(int argc, const char **argv)
 /*
   help for net ads search
 */
-static int net_ads_dn_usage(int argc, const char **argv)
+static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
 {
-       d_printf(
-               "\nnet ads dn <dn> <attributes...>\n"\
-               "\nperform a raw LDAP search on a ADS server and dump the results\n"\
-               "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
-               "to show in the results\n\n"\
+       d_printf(_(
+               "\nnet ads dn <dn> <attributes...>\n"
+               "\nperform a raw LDAP search on a ADS server and dump the results\n"
+               "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
+               "to show in the results\n\n"
                "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
                "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
-               );
-       net_common_flags_usage(argc, argv);
+               ));
+       net_common_flags_usage(c, argc, argv);
        return -1;
 }
 
@@ -1847,7 +2115,7 @@ static int net_ads_dn_usage(int argc, const char **argv)
 /*
   general ADS search function. Useful in diagnosing problems in ADS
 */
-static int net_ads_dn(int argc, const char **argv)
+static int net_ads_dn(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS rc;
@@ -1855,11 +2123,11 @@ static int net_ads_dn(int argc, const char **argv)
        const char **attrs;
        LDAPMessage *res = NULL;
 
-       if (argc < 1) {
-               return net_ads_dn_usage(argc, argv);
+       if (argc < 1 || c->display_usage) {
+               return net_ads_dn_usage(c, argc, argv);
        }
 
-       if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                return -1;
        }
 
@@ -1870,7 +2138,7 @@ static int net_ads_dn(int argc, const char **argv)
                               LDAP_SCOPE_BASE,
                               "(objectclass=*)", attrs, &res);
        if (!ADS_ERR_OK(rc)) {
-               d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
+               d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
                ads_destroy(&ads);
                return -1;
        }
@@ -1889,16 +2157,16 @@ static int net_ads_dn(int argc, const char **argv)
 /*
   help for net ads sid search
 */
-static int net_ads_sid_usage(int argc, const char **argv)
+static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
 {
-       d_printf(
-               "\nnet ads sid <sid> <attributes...>\n"\
-               "\nperform a raw LDAP search on a ADS server and dump the results\n"\
-               "The SID is in string format, and the attributes are a list of LDAP fields \n"\
-               "to show in the results\n\n"\
+       d_printf(_(
+               "\nnet ads sid <sid> <attributes...>\n"
+               "\nperform a raw LDAP search on a ADS server and dump the results\n"
+               "The SID is in string format, and the attributes are a list of LDAP fields \n"
+               "to show in the results\n\n"
                "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
-               );
-       net_common_flags_usage(argc, argv);
+               ));
+       net_common_flags_usage(c, argc, argv);
        return -1;
 }
 
@@ -1906,7 +2174,7 @@ static int net_ads_sid_usage(int argc, const char **argv)
 /*
   general ADS search function. Useful in diagnosing problems in ADS
 */
-static int net_ads_sid(int argc, const char **argv)
+static int net_ads_sid(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        ADS_STATUS rc;
@@ -1915,11 +2183,11 @@ static int net_ads_sid(int argc, const char **argv)
        LDAPMessage *res = NULL;
        DOM_SID sid;
 
-       if (argc < 1) {
-               return net_ads_sid_usage(argc, argv);
+       if (argc < 1 || c->display_usage) {
+               return net_ads_sid_usage(c, argc, argv);
        }
 
-       if (!ADS_ERR_OK(ads_startup(False, &ads))) {
+       if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
                return -1;
        }
 
@@ -1927,19 +2195,19 @@ static int net_ads_sid(int argc, const char **argv)
        attrs = (argv + 1);
 
        if (!string_to_sid(&sid, sid_string)) {
-               d_fprintf(stderr, "could not convert sid\n");
+               d_fprintf(stderr, _("could not convert sid\n"));
                ads_destroy(&ads);
                return -1;
        }
 
        rc = ads_search_retry_sid(ads, &res, &sid, attrs);
        if (!ADS_ERR_OK(rc)) {
-               d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
+               d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
                ads_destroy(&ads);
                return -1;
        }
 
-       d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
+       d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
 
        /* dump the results */
        ads_dump(ads, res);
@@ -1950,35 +2218,21 @@ static int net_ads_sid(int argc, const char **argv)
        return 0;
 }
 
-
-static int net_ads_keytab_usage(int argc, const char **argv)
-{
-       d_printf(
-               "net ads keytab <COMMAND>\n"\
-"<COMMAND> can be either:\n"\
-"  ADD       Adds new service principal\n"\
-"  CREATE    Creates a fresh keytab\n"\
-"  FLUSH     Flushes out all keytab entries\n"\
-"  HELP      Prints this help message\n"\
-"  LIST      List the keytab\n"\
-"The ADD and LIST command will take arguments, the other commands\n"\
-"will not take any arguments.   The arguments given to ADD\n"\
-"should be a list of principals to add.  For example, \n"\
-"   net ads keytab add srv1 srv2\n"\
-"will add principals for the services srv1 and srv2 to the\n"\
-"system's keytab.\n"\
-"The LIST command takes a keytabname.\n"\
-"\n"
-               );
-       return -1;
-}
-
-static int net_ads_keytab_flush(int argc, const char **argv)
+static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
 {
        int ret;
        ADS_STRUCT *ads;
 
-       if (!ADS_ERR_OK(ads_startup(True, &ads))) {
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads keytab flush\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Delete the whole keytab"));
+               return 0;
+       }
+
+       if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
                return -1;
        }
        ret = ads_keytab_flush(ads);
@@ -1986,14 +2240,24 @@ static int net_ads_keytab_flush(int argc, const char **argv)
        return ret;
 }
 
-static int net_ads_keytab_add(int argc, const char **argv)
+static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
 {
        int i;
        int ret = 0;
        ADS_STRUCT *ads;
 
-       d_printf("Processing principals to add...\n");
-       if (!ADS_ERR_OK(ads_startup(True, &ads))) {
+       if (c->display_usage) {
+               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"));
+               return 0;
+       }
+
+       d_printf(_("Processing principals to add...\n"));
+       if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
                return -1;
        }
        for (i = 0; i < argc; i++) {
@@ -2003,12 +2267,21 @@ static int net_ads_keytab_add(int argc, const char **argv)
        return ret;
 }
 
-static int net_ads_keytab_create(int argc, const char **argv)
+static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
 {
        ADS_STRUCT *ads;
        int ret;
 
-       if (!ADS_ERR_OK(ads_startup(True, &ads))) {
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads keytab create\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Create new default keytab"));
+               return 0;
+       }
+
+       if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
                return -1;
        }
        ret = ads_keytab_create_default(ads);
@@ -2016,10 +2289,19 @@ static int net_ads_keytab_create(int argc, const char **argv)
        return ret;
 }
 
-static int net_ads_keytab_list(int argc, const char **argv)
+static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
 {
        const char *keytab = NULL;
 
+       if (c->display_usage) {
+               d_printf("%s\n%s",
+                        _("Usage:"),
+                        _("net ads keytab list [keytab]\n"
+                          "  List a local keytab\n"
+                          "    keytab\tKeytab to list\n"));
+               return 0;
+       }
+
        if (argc >= 1) {
                keytab = argv[0];
        }
@@ -2028,77 +2310,116 @@ static int net_ads_keytab_list(int argc, const char **argv)
 }
 
 
-int net_ads_keytab(int argc, const char **argv)
+int net_ads_keytab(struct net_context *c, int argc, const char **argv)
 {
        struct functable func[] = {
-               {"ADD", net_ads_keytab_add},
-               {"CREATE", net_ads_keytab_create},
-               {"FLUSH", net_ads_keytab_flush},
-               {"HELP", net_ads_keytab_usage},
-               {"LIST", net_ads_keytab_list},
-               {NULL, NULL}
+               {
+                       "add",
+                       net_ads_keytab_add,
+                       NET_TRANSPORT_ADS,
+                       N_("Add a service principal"),
+                       N_("net ads keytab add\n"
+                          "    Add a service principal")
+               },
+               {
+                       "create",
+                       net_ads_keytab_create,
+                       NET_TRANSPORT_ADS,
+                       N_("Create a fresh keytab"),
+                       N_("net ads keytab create\n"
+                          "    Create a fresh keytab")
+               },
+               {
+                       "flush",
+                       net_ads_keytab_flush,
+                       NET_TRANSPORT_ADS,
+                       N_("Remove all keytab entries"),
+                       N_("net ads keytab flush\n"
+                          "    Remove all keytab entries")
+               },
+               {
+                       "list",
+                       net_ads_keytab_list,
+                       NET_TRANSPORT_ADS,
+                       N_("List a keytab"),
+                       N_("net ads keytab list\n"
+                          "    List a keytab")
+               },
+               {NULL, NULL, 0, NULL, NULL}
        };
 
-       if (!lp_use_kerberos_keytab()) {
-               d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
-use keytab functions.\n");
+       if (!USE_KERBEROS_KEYTAB) {
+               d_printf(_("\nWarning: \"kerberos method\" must be set to a "
+                   "keytab method to use keytab functions.\n"));
        }
 
-       return net_run_function(argc, argv, func, net_ads_keytab_usage);
+       return net_run_function(c, argc, argv, "net ads keytab", func);
 }
 
-static int net_ads_kerberos_usage(int argc, const char **argv)
+static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
 {
-       d_printf(
-               "net ads kerberos <COMMAND>\n"\
-               "<COMMAND> can be either:\n"\
-               "  RENEW     Renew TGT from existing credential cache\n"\
-               "  PAC       Dumps the Kerberos PAC\n"\
-               "  KINIT     Retrieve Ticket Granting Ticket (TGT)\n"\
-               "\n"
-       );
+       int ret = -1;
 
-       return -1;
-}
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads kerberos renew\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Renew TGT from existing credential cache"));
+               return 0;
+       }
 
-static int net_ads_kerberos_renew(int argc, const char **argv)
-{
-       int ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
+       ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
        if (ret) {
-               d_printf("failed to renew kerberos ticket: %s\n",
+               d_printf(_("failed to renew kerberos ticket: %s\n"),
                        error_message(ret));
        }
        return ret;
 }
 
-static int net_ads_kerberos_pac(int argc, const char **argv)
+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;
        int ret = -1;
+       const char *impersonate_princ_s = NULL;
+
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads kerberos pac\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Dump the Kerberos PAC"));
+               return 0;
+       }
 
        mem_ctx = talloc_init("net_ads_kerberos_pac");
        if (!mem_ctx) {
                goto out;
        }
 
-       opt_password = net_prompt_pass(opt_user_name);
+       if (argc > 0) {
+               impersonate_princ_s = argv[0];
+       }
+
+       c->opt_password = net_prompt_pass(c, c->opt_user_name);
 
        status = kerberos_return_pac(mem_ctx,
-                                    opt_user_name,
-                                    opt_password,
+                                    c->opt_user_name,
+                                    c->opt_password,
                                     0,
                                     NULL,
                                     NULL,
                                     NULL,
-                                    True,
-                                    True,
+                                    true,
+                                    true,
                                     2592000, /* one month */
+                                    impersonate_princ_s,
                                     &pac);
        if (!NT_STATUS_IS_OK(status)) {
-               d_printf("failed to query kerberos PAC: %s\n",
+               d_printf(_("failed to query kerberos PAC: %s\n"),
                        nt_errstr(status));
                goto out;
        }
@@ -2107,7 +2428,7 @@ static int net_ads_kerberos_pac(int argc, const char **argv)
        if (info) {
                const char *s;
                s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
-               d_printf("The Pac: %s\n", s);
+               d_printf(_("The Pac: %s\n"), s);
        }
 
        ret = 0;
@@ -2116,162 +2437,293 @@ static int net_ads_kerberos_pac(int argc, const char **argv)
        return ret;
 }
 
-static int net_ads_kerberos_kinit(int argc, const char **argv)
+static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
 {
        TALLOC_CTX *mem_ctx = NULL;
        int ret = -1;
        NTSTATUS status;
 
+       if (c->display_usage) {
+               d_printf(  "%s\n"
+                          "net ads kerberos kinit\n"
+                          "    %s\n",
+                        _("Usage:"),
+                        _("Get Ticket Granting Ticket (TGT) for the user"));
+               return 0;
+       }
+
        mem_ctx = talloc_init("net_ads_kerberos_kinit");
        if (!mem_ctx) {
                goto out;
        }
 
-       opt_password = net_prompt_pass(opt_user_name);
+       c->opt_password = net_prompt_pass(c, c->opt_user_name);
 
-       ret = kerberos_kinit_password_ext(opt_user_name,
-                                         opt_password,
+       ret = kerberos_kinit_password_ext(c->opt_user_name,
+                                         c->opt_password,
                                          0,
                                          NULL,
                                          NULL,
                                          NULL,
-                                         True,
-                                         True,
+                                         true,
+                                         true,
                                          2592000, /* one month */
                                          &status);
        if (ret) {
-               d_printf("failed to kinit password: %s\n",
+               d_printf(_("failed to kinit password: %s\n"),
                        nt_errstr(status));
        }
  out:
        return ret;
 }
 
-int net_ads_kerberos(int argc, const char **argv)
+int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
 {
        struct functable func[] = {
-               {"KINIT", net_ads_kerberos_kinit},
-               {"RENEW", net_ads_kerberos_renew},
-               {"PAC", net_ads_kerberos_pac},
-               {"HELP", net_ads_kerberos_usage},
-               {NULL, NULL}
+               {
+                       "kinit",
+                       net_ads_kerberos_kinit,
+                       NET_TRANSPORT_ADS,
+                       N_("Retrieve Ticket Granting Ticket (TGT)"),
+                       N_("net ads kerberos kinit\n"
+                          "    Receive Ticket Granting Ticket (TGT)")
+               },
+               {
+                       "renew",
+                       net_ads_kerberos_renew,
+                       NET_TRANSPORT_ADS,
+                       N_("Renew Ticket Granting Ticket from credential cache"),
+                       N_("net ads kerberos renew\n"
+                          "    Renew Ticket Granting Ticket (TGT) from "
+                          "credential cache")
+               },
+               {
+                       "pac",
+                       net_ads_kerberos_pac,
+                       NET_TRANSPORT_ADS,
+                       N_("Dump Kerberos PAC"),
+                       N_("net ads kerberos pac\n"
+                          "    Dump Kerberos PAC")
+               },
+               {NULL, NULL, 0, NULL, NULL}
        };
 
-       return net_run_function(argc, argv, func, net_ads_kerberos_usage);
+       return net_run_function(c, argc, argv, "net ads kerberos", func);
 }
 
-
-int net_ads_help(int argc, const char **argv)
+int net_ads(struct net_context *c, int argc, const char **argv)
 {
        struct functable func[] = {
-               {"USER", net_ads_user_usage},
-               {"GROUP", net_ads_group_usage},
-               {"PRINTER", net_ads_printer_usage},
-               {"SEARCH", net_ads_search_usage},
-               {"INFO", net_ads_info},
-               {"JOIN", net_ads_join_usage},
-               {"DNS", net_ads_dns_usage},
-               {"LEAVE", net_ads_leave},
-               {"STATUS", net_ads_status},
-               {"PASSWORD", net_ads_password},
-               {"CHANGETRUSTPW", net_ads_changetrustpw},
-               {NULL, NULL}
+               {
+                       "info",
+                       net_ads_info,
+                       NET_TRANSPORT_ADS,
+                       N_("Display details on remote ADS server"),
+                       N_("net ads info\n"
+                          "    Display details on remote ADS server")
+               },
+               {
+                       "join",
+                       net_ads_join,
+                       NET_TRANSPORT_ADS,
+                       N_("Join the local machine to ADS realm"),
+                       N_("net ads join\n"
+                          "    Join the local machine to ADS realm")
+               },
+               {
+                       "testjoin",
+                       net_ads_testjoin,
+                       NET_TRANSPORT_ADS,
+                       N_("Validate machine account"),
+                       N_("net ads testjoin\n"
+                          "    Validate machine account")
+               },
+               {
+                       "leave",
+                       net_ads_leave,
+                       NET_TRANSPORT_ADS,
+                       N_("Remove the local machine from ADS"),
+                       N_("net ads leave\n"
+                          "    Remove the local machine from ADS")
+               },
+               {
+                       "status",
+                       net_ads_status,
+                       NET_TRANSPORT_ADS,
+                       N_("Display machine account details"),
+                       N_("net ads status\n"
+                          "    Display machine account details")
+               },
+               {
+                       "user",
+                       net_ads_user,
+                       NET_TRANSPORT_ADS,
+                       N_("List/modify users"),
+                       N_("net ads user\n"
+                          "    List/modify users")
+               },
+               {
+                       "group",
+                       net_ads_group,
+                       NET_TRANSPORT_ADS,
+                       N_("List/modify groups"),
+                       N_("net ads group\n"
+                          "    List/modify groups")
+               },
+               {
+                       "dns",
+                       net_ads_dns,
+                       NET_TRANSPORT_ADS,
+                       N_("Issue dynamic DNS update"),
+                       N_("net ads dns\n"
+                          "    Issue dynamic DNS update")
+               },
+               {
+                       "password",
+                       net_ads_password,
+                       NET_TRANSPORT_ADS,
+                       N_("Change user passwords"),
+                       N_("net ads password\n"
+                          "    Change user passwords")
+               },
+               {
+                       "changetrustpw",
+                       net_ads_changetrustpw,
+                       NET_TRANSPORT_ADS,
+                       N_("Change trust account password"),
+                       N_("net ads changetrustpw\n"
+                          "    Change trust account password")
+               },
+               {
+                       "printer",
+                       net_ads_printer,
+                       NET_TRANSPORT_ADS,
+                       N_("List/modify printer entries"),
+                       N_("net ads printer\n"
+                          "    List/modify printer entries")
+               },
+               {
+                       "search",
+                       net_ads_search,
+                       NET_TRANSPORT_ADS,
+                       N_("Issue LDAP search using filter"),
+                       N_("net ads search\n"
+                          "    Issue LDAP search using filter")
+               },
+               {
+                       "dn",
+                       net_ads_dn,
+                       NET_TRANSPORT_ADS,
+                       N_("Issue LDAP search by DN"),
+                       N_("net ads dn\n"
+                          "    Issue LDAP search by DN")
+               },
+               {
+                       "sid",
+                       net_ads_sid,
+                       NET_TRANSPORT_ADS,
+                       N_("Issue LDAP search by SID"),
+                       N_("net ads sid\n"
+                          "    Issue LDAP search by SID")
+               },
+               {
+                       "workgroup",
+                       net_ads_workgroup,
+                       NET_TRANSPORT_ADS,
+                       N_("Display workgroup name"),
+                       N_("net ads workgroup\n"
+                          "    Display the workgroup name")
+               },
+               {
+                       "lookup",
+                       net_ads_lookup,
+                       NET_TRANSPORT_ADS,
+                       N_("Perfom CLDAP query on DC"),
+                       N_("net ads lookup\n"
+                          "    Find the ADS DC using CLDAP lookups")
+               },
+               {
+                       "keytab",
+                       net_ads_keytab,
+                       NET_TRANSPORT_ADS,
+                       N_("Manage local keytab file"),
+                       N_("net ads keytab\n"
+                          "    Manage local keytab file")
+               },
+               {
+                       "gpo",
+                       net_ads_gpo,
+                       NET_TRANSPORT_ADS,
+                       N_("Manage group policy objects"),
+                       N_("net ads gpo\n"
+                          "    Manage group policy objects")
+               },
+               {
+                       "kerberos",
+                       net_ads_kerberos,
+                       NET_TRANSPORT_ADS,
+                       N_("Manage kerberos keytab"),
+                       N_("net ads kerberos\n"
+                          "    Manage kerberos keytab")
+               },
+               {NULL, NULL, 0, NULL, NULL}
        };
 
-       return net_run_function(argc, argv, func, net_ads_usage);
-}
-
-int net_ads(int argc, const char **argv)
-{
-       struct functable func[] = {
-               {"INFO", net_ads_info},
-               {"JOIN", net_ads_join},
-               {"TESTJOIN", net_ads_testjoin},
-               {"LEAVE", net_ads_leave},
-               {"STATUS", net_ads_status},
-               {"USER", net_ads_user},
-               {"GROUP", net_ads_group},
-               {"DNS", net_ads_dns},
-               {"PASSWORD", net_ads_password},
-               {"CHANGETRUSTPW", net_ads_changetrustpw},
-               {"PRINTER", net_ads_printer},
-               {"SEARCH", net_ads_search},
-               {"DN", net_ads_dn},
-               {"SID", net_ads_sid},
-               {"WORKGROUP", net_ads_workgroup},
-               {"LOOKUP", net_ads_lookup},
-               {"KEYTAB", net_ads_keytab},
-               {"GPO", net_ads_gpo},
-               {"KERBEROS", net_ads_kerberos},
-               {"HELP", net_ads_help},
-               {NULL, NULL}
-       };
-
-       return net_run_function(argc, argv, func, net_ads_usage);
+       return net_run_function(c, argc, argv, "net ads", func);
 }
 
 #else
 
 static int net_ads_noads(void)
 {
-       d_fprintf(stderr, "ADS support not compiled in\n");
+       d_fprintf(stderr, _("ADS support not compiled in\n"));
        return -1;
 }
 
-int net_ads_keytab(int argc, const char **argv)
-{
-       return net_ads_noads();
-}
-
-int net_ads_kerberos(int argc, const char **argv)
+int net_ads_keytab(struct net_context *c, int argc, const char **argv)
 {
        return net_ads_noads();
 }
 
-int net_ads_usage(int argc, const char **argv)
+int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
 {
        return net_ads_noads();
 }
 
-int net_ads_help(int argc, const char **argv)
+int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
 {
        return net_ads_noads();
 }
 
-int net_ads_changetrustpw(int argc, const char **argv)
+int net_ads_join(struct net_context *c, int argc, const char **argv)
 {
        return net_ads_noads();
 }
 
-int net_ads_join(int argc, const char **argv)
+int net_ads_user(struct net_context *c, int argc, const char **argv)
 {
        return net_ads_noads();
 }
 
-int net_ads_user(int argc, const char **argv)
-{
-       return net_ads_noads();
-}
-
-int net_ads_group(int argc, const char **argv)
+int net_ads_group(struct net_context *c, int argc, const char **argv)
 {
        return net_ads_noads();
 }
 
 /* this one shouldn't display a message */
-int net_ads_check(void)
+int net_ads_check(struct net_context *c)
 {
        return -1;
 }
 
-int net_ads_check_our_domain(void)
+int net_ads_check_our_domain(struct net_context *c)
 {
        return -1;
 }
 
-int net_ads(int argc, const char **argv)
+int net_ads(struct net_context *c, int argc, const char **argv)
 {
-       return net_ads_usage(argc, argv);
+       return net_ads_noads();
 }
 
 #endif /* WITH_ADS */