Lots more net consistency work:
authorJim McDonough <jmcd@samba.org>
Fri, 5 Apr 2002 01:36:28 +0000 (01:36 +0000)
committerJim McDonough <jmcd@samba.org>
Fri, 5 Apr 2002 01:36:28 +0000 (01:36 +0000)
- Added net_help.c for unified help when possible
- Added net rpc user listing, delete, info commands
- Unified net user command to autodetect ads/rpc/rap (try in that order)
- Added generic routine for detecting rpc (protocol > PROTOCOL_NT1)
- I'm sure I forgot something.

source/utils/net.c
source/utils/net_ads.c
source/utils/net_help.c [new file with mode: 0644]
source/utils/net_rap.c
source/utils/net_rpc.c

index e33691ea5eda5cfc8b4dbd95c527bb1e0c024f29..b81e37c0af4885461d1605f4deb0edd8b6aa913d 100644 (file)
@@ -78,27 +78,6 @@ struct in_addr opt_dest_ip;
 
 extern pstring global_myname;
 
-int net_common_flags_usage(int argc, const char **argv)
-{
-
-       d_printf("Valid targets: choose one (none defaults to localhost)\n");
-       d_printf("\t-S or --server=<server>\t\tserver name\n");
-       d_printf("\t-I or --ipaddress=<ipaddr>\taddress of target server\n");
-       d_printf("\t-w or --workgroup=<wg>\t\ttarget workgroup or domain\n");
-
-       d_printf("\n");
-       d_printf("Valid miscellaneous options are:\n"); /* misc options */
-       d_printf("\t-p or --port=<port>\tconnection port on target server\n");
-       d_printf("\t-W or --myworkgroup=<wg>\tclient workgroup\n");
-       d_printf("\t-d or --debug=<level>\t\tdebug level (0-10)\n");
-       d_printf("\t-n or --myname=<name>\t\tclient name\n");
-       d_printf("\t-U or --user=<name>\t\tuser name\n");
-       d_printf("\t-s or --conf=<path>\t\tpathname of smb.conf file\n");
-       d_printf("\t-l or --long\t\t\tDisplay full information\n");
-       return -1;
-}
-
-
 /*
   run a function from a function table. If not found then
   call the specified usage function 
@@ -180,7 +159,7 @@ NTSTATUS connect_to_ipc_anonymous(struct cli_state **c,
        }
 }
 
-static BOOL net_find_server(unsigned flags, struct in_addr *server_ip, char **server_name)
+BOOL net_find_server(unsigned flags, struct in_addr *server_ip, char **server_name)
 {
 
        if (opt_host) {
@@ -300,11 +279,17 @@ struct cli_state *net_make_ipc_connection(unsigned flags)
        return cli;
 }
 
+
+
 static int net_user(int argc, const char **argv)
 {
        if (net_ads_check() == 0)
                return net_ads_user(argc, argv);
 
+       /* if server is not specified, default to PDC? */
+       if (net_rpc_check(NET_FLAGS_PDC))
+               return net_rpc_user(argc, argv);
+
        return net_rap_user(argc, argv);
 }
 
@@ -320,63 +305,6 @@ static int net_join(int argc, const char **argv)
        return net_rpc_join(argc, argv);
 }
 
-static int net_usage(int argc, const char **argv)
-{
-       d_printf("  net time\t\t to view or set time information\n"\
-                "  net lookup\t\t to lookup host name or ip address\n"\
-                "\n"\
-                "  net ads [command]\tto run ADS commands\n"\
-                "  net rap [command]\tto run RAP (pre-RPC) commands\n"\
-                "  net rpc [command]\tto run RPC commands\n"\
-                "\n"\
-                "Type \"net help <option>\" to get more information on that option\n");
-       return -1;
-}
-
-static int help_usage(int argc, const char **argv)
-{
-       d_printf(
-"\n"\
-"Usage: net help <function>\n"\
-"\n"\
-"Valid functions are:\n"\
-"  RPC RAP ADS FILE SHARE SESSION SERVER DOMAIN PRINTQ USER GROUP VALIDATE\n"\
-"  GROUPMEMBER ADMIN SERVICE PASSWORD TIME LOOKUP\n");
-       return -1;
-}
-
-/*
-  handle "net help *" subcommands
-*/
-static int net_help(int argc, const char **argv)
-{
-       struct functable func[] = {
-               {"ADS", net_ads_help},  
-               {"RAP", net_rap_help},
-               {"RPC", net_rpc_help},
-
-               {"FILE", net_rap_file_usage},
-               {"SHARE", net_rap_share_usage},
-               {"SESSION", net_rap_session_usage},
-               {"SERVER", net_rap_server_usage},
-               {"DOMAIN", net_rap_domain_usage},
-               {"PRINTQ", net_rap_printq_usage},
-               {"USER", net_rap_user_usage},
-               {"GROUP", net_rap_group_usage},
-               {"VALIDATE", net_rap_validate_usage},
-               {"GROUPMEMBER", net_rap_groupmember_usage},
-               {"ADMIN", net_rap_admin_usage},
-               {"SERVICE", net_rap_service_usage},
-               {"PASSWORD", net_rap_password_usage},
-               {"TIME", net_time_usage},
-               {"LOOKUP", net_lookup_usage},
-
-               {"HELP", help_usage},
-               {NULL, NULL}};
-
-       return net_run_function(argc, argv, func, net_usage);
-}
-
 /* main function table */
 static struct functable net_func[] = {
        {"RPC", net_rpc},
@@ -453,7 +381,7 @@ static struct functable net_func[] = {
        while((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt) {
                case 'h':
-                       net_usage(argc, argv);
+                       net_help(argc, argv);
                        exit(0);
                        break;
                case 'I':
@@ -474,7 +402,7 @@ static struct functable net_func[] = {
                        break;
                default:
                        d_printf("\nInvalid option %c (%d)\n", (char)opt, opt);
-                       net_usage(argc, argv);
+                       net_help(argc, argv);
                }
        }
 
@@ -523,7 +451,7 @@ static struct functable net_func[] = {
 
        load_interfaces();
 
-       rc = net_run_function(argc_new-1, argv_new+1, net_func, net_usage);
+       rc = net_run_function(argc_new-1, argv_new+1, net_func, net_help);
        
        DEBUG(2,("return code = %d\n", rc));
        return rc;
index 2696152b12fbb9092d64ec63b22dad0013506e34..260f49ee7619326e105fd07da6e53132eb6fe5cb 100644 (file)
@@ -162,16 +162,7 @@ static void usergrp_display(char *field, void **values, void *data_area)
 
 static int net_ads_user_usage(int argc, const char **argv)
 {
-       d_printf("\nnet ads user \n\tList users\n");
-       d_printf("\nnet ads user DELETE <name>"\
-                "\n\tDelete specified user\n");
-       d_printf("\nnet ads user INFO <name>"\
-                "\n\tList the domain groups of the specified user\n");
-       d_printf("\nnet ads user ADD <name> [-F user flags]"\
-                "\n\tAdd specified user\n");
-       net_common_flags_usage(argc, argv);
-
-       return -1;
+       return net_help_user(argc, argv);
 } 
 
 static int ads_user_add(int argc, const char **argv)
diff --git a/source/utils/net_help.c b/source/utils/net_help.c
new file mode 100644 (file)
index 0000000..38b1aa2
--- /dev/null
@@ -0,0 +1,125 @@
+/* 
+   Samba Unix/Linux SMB client library 
+   net help commands
+   Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+*/
+
+#include "includes.h"
+
+int net_common_methods_usage(int argc, const char**argv)
+{
+       d_printf("Valid methods: (auto-detected if not specified)\n");
+       d_printf("\tads\t\t\t\tActive Directory (LDAP/Kerberos)\n");
+       d_printf("\trpc\t\t\t\tDCE-RPC\n");
+       d_printf("\trap\t\t\t\tRAP (older systems)\n");
+       d_printf("\n");
+}
+
+int net_common_flags_usage(int argc, const char **argv)
+{
+       d_printf("Valid targets: choose one (none defaults to localhost)\n");
+       d_printf("\t-S or --server=<server>\t\tserver name\n");
+       d_printf("\t-I or --ipaddress=<ipaddr>\taddress of target server\n");
+       d_printf("\t-w or --workgroup=<wg>\t\ttarget workgroup or domain\n");
+
+       d_printf("\n");
+       d_printf("Valid miscellaneous options are:\n"); /* misc options */
+       d_printf("\t-p or --port=<port>\t\tconnection port on target\n");
+       d_printf("\t-W or --myworkgroup=<wg>\tclient workgroup\n");
+       d_printf("\t-d or --debug=<level>\t\tdebug level (0-10)\n");
+       d_printf("\t-n or --myname=<name>\t\tclient name\n");
+       d_printf("\t-U or --user=<name>\t\tuser name\n");
+       d_printf("\t-s or --conf=<path>\t\tpathname of smb.conf file\n");
+       d_printf("\t-l or --long\t\t\tDisplay full information\n");
+       return -1;
+}
+
+static int help_usage(int argc, const char **argv)
+{
+       d_printf(
+"\n"\
+"Usage: net help <function>\n"\
+"\n"\
+"Valid functions are:\n"\
+"  RPC RAP ADS FILE SHARE SESSION SERVER DOMAIN PRINTQ USER GROUP VALIDATE\n"\
+"  GROUPMEMBER ADMIN SERVICE PASSWORD TIME LOOKUP\n");
+       return -1;
+}
+
+int net_help_user(int argc, const char **argv)
+{
+       d_printf("\nnet [method] user [misc. options] [targets]\n\tList users\n");
+       d_printf("\nnet [method] user DELETE <name> [misc. options] [targets]"\
+                "\n\tDelete specified user\n");
+       d_printf("\nnet [method] user INFO <name> [misc. options] [targets]"\
+                "\n\tList the domain groups of the specified user\n");
+       d_printf("\nnet [method] user ADD <name> [-F user flags] [misc. options]"\
+                " [targets]\n\tAdd specified user\n");
+
+       net_common_methods_usage(argc, argv);
+       net_common_flags_usage(argc, argv);
+       d_printf(
+        "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n");
+       return -1;
+}
+
+static int net_usage(int argc, const char **argv)
+{
+       d_printf("  net time\t\tto view or set time information\n"\
+                "  net lookup\t\tto lookup host name or ip address\n"\
+                "  net user\t\tto manage users\n"\
+                "  net join\t\tto join a domain\n"\
+                "\n"\
+                "  net ads [command]\tto run ADS commands\n"\
+                "  net rap [command]\tto run RAP (pre-RPC) commands\n"\
+                "  net rpc [command]\tto run RPC commands\n"\
+                "\n"\
+                "Type \"net help <option>\" to get more information on that option\n");
+       return -1;
+}
+
+/*
+  handle "net help *" subcommands
+*/
+int net_help(int argc, const char **argv)
+{
+       struct functable func[] = {
+               {"ADS", net_ads_help},  
+               {"RAP", net_rap_help},
+               {"RPC", net_rpc_help},
+
+               {"FILE", net_rap_file_usage},
+               {"SHARE", net_rap_share_usage},
+               {"SESSION", net_rap_session_usage},
+               {"SERVER", net_rap_server_usage},
+               {"DOMAIN", net_rap_domain_usage},
+               {"PRINTQ", net_rap_printq_usage},
+               {"USER", net_help_user},
+               {"GROUP", net_rap_group_usage},
+               {"VALIDATE", net_rap_validate_usage},
+               {"GROUPMEMBER", net_rap_groupmember_usage},
+               {"ADMIN", net_rap_admin_usage},
+               {"SERVICE", net_rap_service_usage},
+               {"PASSWORD", net_rap_password_usage},
+               {"TIME", net_time_usage},
+               {"LOOKUP", net_lookup_usage},
+
+               {"HELP", help_usage},
+               {NULL, NULL}};
+
+       return net_run_function(argc, argv, func, net_usage);
+}
index 13180c47c52da582401f2c6da7544327766313bf..a6b199fd88be58f14399d83e1f97a713119d856a 100644 (file)
@@ -605,20 +605,9 @@ int net_rap_printq(int argc, const char **argv)
 }
 
        
-int net_rap_user_usage(int argc, const char **argv)
+static int net_rap_user_usage(int argc, const char **argv)
 {
-       d_printf("\nnet rap user [misc. options] [targets]\n\tList users\n");
-       d_printf("\nnet rap user DELETE <name> [misc. options] [targets]"\
-                "\n\tDelete specified user\n");
-       d_printf("\nnet rap user INFO <name> [misc. options] [targets]"\
-                "\n\tList the domain groups of the specified user\n");
-       d_printf("\nnet rap user ADD <name> [-F user flags] [misc. options]"\
-                " [targets]\n\tAdd specified user\n");
-
-       net_common_flags_usage(argc, argv);
-       d_printf(
-        "\t-C or --comment=<comment>\tdescriptive comment (for add only)\n");
-       return -1;
+       return net_help_user(argc, argv);
 } 
        
 static void user_fn(const char *user_name, const char *comment,
index 6200d6f91467c54c0e2eab846a64c14f13088633..19e2c63eccfe23e132290aeee51544ac78bc1c59 100644 (file)
@@ -20,6 +20,8 @@
 #include "includes.h"
 #include "../utils/net.h"
 
+extern pstring global_myname;
+
 /**
  * @file net_rpc.c
  *
@@ -296,6 +298,17 @@ int net_rpc_join(int argc, const char **argv)
 
 /****************************************************************************/
 
+/**
+ * Basic usage function for 'net rpc user'
+ * @param argc Standard main() style argc.
+ * @param argv Standard main() style argv.  Initial components are already
+ *             stripped.
+ **/
+
+static int rpc_user_usage(int argc, const char **argv)
+{
+       return net_help_user(argc, argv);
+}
 
 /** 
  * Add a new user to a remote RPC server
@@ -307,7 +320,7 @@ int net_rpc_join(int argc, const char **argv)
  * @param cli A cli_state connected to the server.
  * @param mem_ctx Talloc context, destoyed on completion of the function.
  * @param argc  Standard main() style argc
- * @param argc  Standard main() style argv.  Initial components are already
+ * @param argv  Standard main() style argv.  Initial components are already
  *              stripped
  *
  * @return Normal NTSTATUS return.
@@ -323,7 +336,8 @@ static NTSTATUS rpc_user_add_internals(const DOM_SID *domain_sid, struct cli_sta
        uint32 unknown, user_rid;
 
        if (argc != 1) {
-               d_printf("Usage: net rpc user add username\n");
+               d_printf("User must be specified\n");
+               rpc_user_usage(argc, argv);
                return NT_STATUS_OK;
        }
 
@@ -372,7 +386,7 @@ static NTSTATUS rpc_user_add_internals(const DOM_SID *domain_sid, struct cli_sta
  * Add a new user to a remote RPC server
  *
  * @param argc  Standard main() style argc
- * @param argc  Standard main() style argv.  Initial components are already
+ * @param argv  Standard main() style argv.  Initial components are already
  *              stripped
  *
  * @return A shell status integer (0 for success)
@@ -385,16 +399,277 @@ static int rpc_user_add(int argc, const char **argv)
 }
 
 /** 
- * Basic usage function for 'net rpc user'
+ * Delete a user from a remote RPC server
+ *
+ * All paramaters are provided by the run_rpc_command funcion, except for
+ * argc, argv which are passes through. 
+ *
+ * @param domain_sid The domain sid acquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on completion of the function.
  * @param argc  Standard main() style argc
- * @param argc  Standard main() style argv.  Initial components are already
+ * @param argv  Standard main() style argv.  Initial components are already
  *              stripped
+ *
+ * @return Normal NTSTATUS return.
  **/
 
-static int rpc_user_usage(int argc, const char **argv) 
+static NTSTATUS rpc_user_del_internals(const DOM_SID *domain_sid, 
+                                      struct cli_state *cli, 
+                                      TALLOC_CTX *mem_ctx, 
+                                      int argc, const char **argv)
 {
-       d_printf("  net rpc user add \t to add a user\n");
-       return -1;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       POLICY_HND connect_pol, domain_pol, user_pol;
+
+       if (argc < 1) {
+               d_printf("User must be specified\n");
+               rpc_user_usage(argc, argv);
+               return NT_STATUS_OK;
+       }
+       /* Get sam policy and domain handles */
+
+       result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                 &connect_pol);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               goto done;
+       }
+
+       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                     MAXIMUM_ALLOWED_ACCESS,
+                                     domain_sid, &domain_pol);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               goto done;
+       }
+
+       /* Get handle on user */
+
+       {
+               uint32 *user_rids, num_rids, *name_types;
+               uint32 flags = 0x000003e8; /* Unknown */
+
+               result = cli_samr_lookup_names(cli, mem_ctx, &domain_pol,
+                                              flags, 1, (char **) &argv[0],
+                                              &num_rids, &user_rids,
+                                              &name_types);
+
+               if (!NT_STATUS_IS_OK(result)) {
+                       goto done;
+               }
+
+               result = cli_samr_open_user(cli, mem_ctx, &domain_pol,
+                                           MAXIMUM_ALLOWED_ACCESS,
+                                           user_rids[0], &user_pol);
+
+               if (!NT_STATUS_IS_OK(result)) {
+                       goto done;
+               }
+       }
+
+       /* Delete user */
+
+       result = cli_samr_delete_dom_user(cli, mem_ctx, &user_pol);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               goto done;
+       }
+
+       /* Display results */
+
+ done:
+       return result;
+
+}      
+
+/** 
+ * Delete a user from a remote RPC server
+ *
+ * @param argc  Standard main() style argc
+ * @param argv  Standard main() style argv.  Initial components are already
+ *              stripped
+ *
+ * @return A shell status integer (0 for success)
+ **/
+
+static int rpc_user_delete(int argc, const char **argv) 
+{
+       return run_rpc_command(PIPE_SAMR, 0, rpc_user_del_internals,
+                              argc, argv);
+}
+
+/** 
+ * List user's groups on a remote RPC server
+ *
+ * All paramaters are provided by the run_rpc_command funcion, except for
+ * argc, argv which are passes through. 
+ *
+ * @param domain_sid The domain sid acquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on completion of the function.
+ * @param argc  Standard main() style argc
+ * @param argv  Standard main() style argv.  Initial components are already
+ *              stripped
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS 
+rpc_user_info_internals(const DOM_SID *domain_sid, struct cli_state *cli,
+                       TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+       POLICY_HND connect_pol, domain_pol, user_pol;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       uint32 *rids, num_rids, *name_types, num_names;
+       uint32 flags = 0x000003e8; /* Unknown */
+       int i;
+       char **names;
+       DOM_GID *user_gids;
+
+       if (argc < 1) {
+               d_printf("User must be specified\n");
+               rpc_user_usage(argc, argv);
+               return NT_STATUS_OK;
+       }
+       /* Get sam policy handle */
+       
+       result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                 &connect_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+       
+       /* Get domain policy handle */
+       
+       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                     MAXIMUM_ALLOWED_ACCESS,
+                                     domain_sid, &domain_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       /* Get handle on user */
+
+       result = cli_samr_lookup_names(cli, mem_ctx, &domain_pol,
+                                      flags, 1, (char **) &argv[0],
+                                      &num_rids, &rids, &name_types);
+
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       result = cli_samr_open_user(cli, mem_ctx, &domain_pol,
+                                   MAXIMUM_ALLOWED_ACCESS,
+                                   rids[0], &user_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       result = cli_samr_query_usergroups(cli, mem_ctx, &user_pol,
+                                          &num_rids, &user_gids);
+
+       /* Look up rids */
+
+       rids = (uint32 *)talloc(mem_ctx, sizeof(uint32) * num_rids);
+
+       for (i = 0; i < num_rids; i++)
+                rids[i] = user_gids[i].g_rid;
+
+       result = cli_samr_lookup_rids(cli, mem_ctx, &domain_pol,
+                                     flags, num_rids, rids,
+                                     &num_names, &names, &name_types);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               goto done;
+       }
+
+       /* Display results */
+
+       for (i = 0; i < num_names; i++)
+               printf("%s\n", names[i]);
+
+ done:
+       return result;
+}
+
+/** 
+ * List a user's groups from a remote RPC server
+ *
+ * @param argc  Standard main() style argc
+ * @param argv  Standard main() style argv.  Initial components are already
+ *              stripped
+ *
+ * @return A shell status integer (0 for success)
+ **/
+
+static int rpc_user_info(int argc, const char **argv) 
+{
+       return run_rpc_command(PIPE_SAMR, 0, rpc_user_info_internals,
+                              argc, argv);
+}
+
+/** 
+ * List users on a remote RPC server
+ *
+ * All paramaters are provided by the run_rpc_command funcion, except for
+ * argc, argv which are passes through. 
+ *
+ * @param domain_sid The domain sid acquired from the remote server
+ * @param cli A cli_state connected to the server.
+ * @param mem_ctx Talloc context, destoyed on completion of the function.
+ * @param argc  Standard main() style argc
+ * @param argv  Standard main() style argv.  Initial components are already
+ *              stripped
+ *
+ * @return Normal NTSTATUS return.
+ **/
+
+static NTSTATUS 
+rpc_user_list_internals(const DOM_SID *domain_sid, struct cli_state *cli,
+                       TALLOC_CTX *mem_ctx, int argc, const char **argv)
+{
+       POLICY_HND connect_pol, domain_pol;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       uint32 start_idx=0, max_entries=250, num_entries, i;
+       SAM_DISPINFO_CTR ctr;
+       SAM_DISPINFO_1 info1;
+
+       /* Get sam policy handle */
+       
+       result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                 &connect_pol);
+       if (!NT_STATUS_IS_OK(result)) {
+               goto done;
+       }
+       
+       /* Get domain policy handle */
+       
+       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                     MAXIMUM_ALLOWED_ACCESS,
+                                     domain_sid, &domain_pol);
+       if (!NT_STATUS_IS_OK(result)) {
+               goto done;
+       }
+
+       /* Query domain users */
+       ZERO_STRUCT(ctr);
+       ZERO_STRUCT(info1);
+       ctr.sam.info1 = &info1;
+       if (opt_long_list_entries)
+               d_printf("\nUser name             Comment"\
+                        "\n-----------------------------\n");
+       do {
+               fstring user, desc;
+               result = cli_samr_query_dispinfo(cli, mem_ctx, &domain_pol,
+                                                &start_idx, 1, &num_entries,
+                                                max_entries, &ctr);
+               for (i = 0; i < num_entries; i++) {
+                       unistr2_to_ascii(user, &(&ctr.sam.info1->str[i])->uni_acct_name, sizeof(user)-1);
+                       if (opt_long_list_entries) 
+                               unistr2_to_ascii(desc, &(&ctr.sam.info1->str[i])->uni_acct_desc, sizeof(desc)-1);
+                       
+                       if (opt_long_list_entries)
+                               printf("%-21.21s %-50.50s\n", user, desc);
+                       else
+                               printf("%-21.21s\n", user);
+               }
+       } while (!NT_STATUS_IS_OK(result));
+
+ done:
+       return result;
 }
 
 /** 
@@ -404,15 +679,22 @@ static int rpc_user_usage(int argc, const char **argv)
  *              stripped
  **/
 
-static int rpc_user(int argc, const char **argv) 
+int net_rpc_user(int argc, const char **argv) 
 {
        struct functable func[] = {
                {"add", rpc_user_add},
+               {"info", rpc_user_info},
+               {"delete", rpc_user_delete},
                {NULL, NULL}
        };
        
        if (argc == 0) {
-               return rpc_user_usage(argc, argv);
+               if (opt_long_list_entries) {
+               } else {
+               }
+                       return run_rpc_command(PIPE_SAMR, 0, 
+                                              rpc_user_list_internals,
+                                              argc, argv);
        }
 
        return net_run_function(argc, argv, func, rpc_user_usage);
@@ -928,6 +1210,44 @@ static int rpc_trustdom(int argc, const char **argv)
        return (net_run_function(argc, argv, func, rpc_user_usage));
 }
 
+/**
+ * Check if a server will take rpc commands
+ * @param flags        Type of server to connect to (PDC, DMB, localhost)
+ *             if the host is not explicitly specified
+ * @return  BOOL (true means rpc supported)
+ */
+BOOL net_rpc_check(unsigned flags)
+{
+       struct cli_state cli;
+       BOOL ret = False;
+       struct in_addr server_ip;
+       char *server_name = NULL;
+
+       /* flags (i.e. server type) may depend on command */
+       if (!net_find_server(flags, &server_ip, &server_name))
+               goto done;
+
+       ZERO_STRUCT(cli);
+       if (cli_initialise(&cli) == False)
+               return False;
+
+       if (!cli_connect(&cli, server_name, &server_ip))
+               goto done;
+       if (!attempt_netbios_session_request(&cli, global_myname, 
+                                            server_name, &server_ip))
+               goto done;
+       if (!cli_negprot(&cli))
+               goto done;
+       if (cli.protocol < PROTOCOL_NT1)
+               goto done;
+
+       ret = True;
+ done:
+       cli_shutdown(&cli);
+       return ret;
+}
+
+
 /****************************************************************************/
 
 
@@ -968,7 +1288,7 @@ int net_rpc_help(int argc, const char **argv)
 {
        struct functable func[] = {
                {"join", rpc_join_usage},
-               {"user", rpc_user_usage},
+               {"user", net_help_user},
                /*{"changetrustpw", rpc_changetrustpw_usage}, */
                {"trustdom", rpc_trustdom_usage},
                /*{"abortshutdown", rpc_shutdown_abort_usage},*/
@@ -996,7 +1316,7 @@ int net_rpc(int argc, const char **argv)
 {
        struct functable func[] = {
                {"join", net_rpc_join},
-               {"user", rpc_user},
+               {"user", net_rpc_user},
                {"changetrustpw", rpc_changetrustpw},
                {"trustdom", rpc_trustdom},
                {"abortshutdown", rpc_shutdown_abort},