From e90b65284812aaa5ff9e9935ce9bbad7791cbbcd Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 15 Jul 2002 10:35:28 +0000 Subject: updated the 3.0 branch from the head branch - ready for alpha18 (This used to be commit 03ac082dcb375b6f3ca3d810a6a6367542bc23ce) --- source3/utils/net.c | 70 ++++- source3/utils/net.h | 5 + source3/utils/net_ads.c | 269 ++++++++++++++--- source3/utils/net_help.c | 71 ++++- source3/utils/net_lookup.c | 173 ++++++++++- source3/utils/net_rap.c | 53 +--- source3/utils/net_rpc.c | 671 +++++++++++++++++++++++++++++++++++++++++-- source3/utils/net_rpc_join.c | 10 +- source3/utils/net_time.c | 6 +- source3/utils/nmblookup.c | 34 ++- source3/utils/pdbedit.c | 538 ++++++++++++---------------------- source3/utils/smbcacls.c | 126 ++++---- source3/utils/smbcontrol.c | 157 ++++++++-- source3/utils/smbgroupedit.c | 18 +- source3/utils/smbpasswd.c | 105 +++---- source3/utils/smbtree.c | 85 +----- source3/utils/status.c | 18 +- source3/utils/testparm.c | 277 ++++++++---------- 18 files changed, 1786 insertions(+), 900 deletions(-) (limited to 'source3/utils') diff --git a/source3/utils/net.c b/source3/utils/net.c index b81e37c0af..d34ac21f39 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -72,11 +72,13 @@ int opt_flags = -1; int opt_jobid = 0; int opt_timeout = 0; char *opt_target_workgroup = NULL; +static int opt_machine_pass = 0; BOOL opt_have_ip = False; struct in_addr opt_dest_ip; extern pstring global_myname; +extern BOOL AllowDebugChange; /* run a function from a function table. If not found then @@ -119,7 +121,7 @@ NTSTATUS connect_to_ipc(struct cli_state **c, struct in_addr *server_ip, server_ip, opt_port, "IPC$", "IPC", opt_user_name, opt_workgroup, - opt_password, strlen(opt_password)); + opt_password, 0); if (NT_STATUS_IS_OK(nt_status)) { return nt_status; @@ -279,8 +281,6 @@ 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) @@ -293,6 +293,16 @@ static int net_user(int argc, const char **argv) return net_rap_user(argc, argv); } +static int net_group(int argc, const char **argv) +{ + if (net_ads_check() == 0) + return net_ads_group(argc, argv); + + if (argc == 0 && net_rpc_check(NET_FLAGS_PDC)) + return net_rpc_group(argc, argv); + + return net_rap_group(argc, argv); +} static int net_join(int argc, const char **argv) { @@ -305,6 +315,20 @@ static int net_join(int argc, const char **argv) return net_rpc_join(argc, argv); } +static int net_share(int argc, const char **argv) +{ + if (net_rpc_check(0)) + return net_rpc_share(argc, argv); + return net_rap_share(argc, argv); +} + +static int net_file(int argc, const char **argv) +{ + if (net_rpc_check(0)) + return net_rpc_file(argc, argv); + return net_rap_file(argc, argv); +} + /* main function table */ static struct functable net_func[] = { {"RPC", net_rpc}, @@ -312,14 +336,14 @@ static struct functable net_func[] = { {"ADS", net_ads}, /* eventually these should auto-choose the transport ... */ - {"FILE", net_rap_file}, - {"SHARE", net_rap_share}, + {"FILE", net_file}, + {"SHARE", net_share}, {"SESSION", net_rap_session}, {"SERVER", net_rap_server}, {"DOMAIN", net_rap_domain}, {"PRINTQ", net_rap_printq}, {"USER", net_user}, - {"GROUP", net_rap_group}, + {"GROUP", net_group}, {"VALIDATE", net_rap_validate}, {"GROUPMEMBER", net_rap_groupmember}, {"ADMIN", net_rap_admin}, @@ -346,7 +370,7 @@ static struct functable net_func[] = { const char ** argv_new; poptContext pc; static char *servicesf = dyn_CONFIGFILE; - static int debuglevel = 0; + static char *debuglevel = NULL; struct poptOption long_options[] = { {"help", 'h', POPT_ARG_NONE, 0, 'h'}, @@ -357,8 +381,8 @@ static struct functable net_func[] = { {"port", 'p', POPT_ARG_INT, &opt_port}, {"myname", 'n', POPT_ARG_STRING, &opt_requester_name}, {"conf", 's', POPT_ARG_STRING, &servicesf}, - {"debug", 'd', POPT_ARG_INT, &debuglevel}, - {"debuglevel", 'd', POPT_ARG_INT, &debuglevel}, + {"debug", 'd', POPT_ARG_STRING, &debuglevel}, + {"debuglevel", 'd', POPT_ARG_STRING, &debuglevel}, {"server", 'S', POPT_ARG_STRING, &opt_host}, {"comment", 'C', POPT_ARG_STRING, &opt_comment}, {"maxusers", 'M', POPT_ARG_INT, &opt_maxusers}, @@ -368,6 +392,7 @@ static struct functable net_func[] = { {"reboot", 'r', POPT_ARG_NONE, &opt_reboot}, {"force", 'f', POPT_ARG_NONE, &opt_force}, {"timeout", 't', POPT_ARG_INT, &opt_timeout}, + {"machine-pass",'P', POPT_ARG_NONE, &opt_machine_pass}, { 0, 0, 0, 0} }; @@ -403,12 +428,16 @@ static struct functable net_func[] = { default: d_printf("\nInvalid option %c (%d)\n", (char)opt, opt); net_help(argc, argv); + exit(1); } } - lp_load(servicesf,True,False,False); + if (debuglevel) { + debug_parse_levels(debuglevel); + AllowDebugChange = False; + } - DEBUGLEVEL = debuglevel; + lp_load(servicesf,True,False,False); argv_new = (const char **)poptGetArgs(pc); @@ -419,7 +448,7 @@ static struct functable net_func[] = { break; } } - + if (!opt_requester_name) { static fstring myname; get_myname(myname); @@ -451,6 +480,23 @@ static struct functable net_func[] = { load_interfaces(); + if (opt_machine_pass) { + /* it is very useful to be able to make ads queries as the + machine account for testing purposes and for domain leave */ + + if (!secrets_init()) { + d_printf("ERROR: Unable to open secrets database\n"); + exit(1); + } + + asprintf(&opt_user_name,"%s$", global_myname); + opt_password = secrets_fetch_machine_password(); + if (!opt_password) { + d_printf("ERROR: Unable to fetch machine password\n"); + exit(1); + } + } + rc = net_run_function(argc_new-1, argv_new+1, net_func, net_help); DEBUG(2,("return code = %d\n", rc)); diff --git a/source3/utils/net.h b/source3/utils/net.h index af6f153f7b..86bdf2082e 100644 --- a/source3/utils/net.h +++ b/source3/utils/net.h @@ -16,6 +16,8 @@ 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 "../utils/net_proto.h" #define NET_FLAGS_MASTER 1 #define NET_FLAGS_DMB 2 @@ -49,3 +51,6 @@ extern char *opt_host; extern char *opt_user_name; extern char *opt_password; extern BOOL opt_user_specified; + +extern const char *share_type[]; + diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 68fa89ea35..fa3eac6bd3 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -33,20 +33,22 @@ int net_ads_usage(int argc, const char **argv) "\nnet ads leave"\ "\n\tremoves the local machine from a ADS realm\n"\ "\nnet ads user"\ -"\n\tlist users in the realm\n"\ +"\n\tlist, add, or delete users in the realm\n"\ "\nnet ads group"\ -"\n\tlist groups in the realm\n"\ +"\n\tlist, add, or delete groups in the realm\n"\ "\nnet ads info"\ "\n\tshows some info on the server\n"\ "\nnet ads status"\ "\n\tdump the machine account details to stdout\n" "\nnet ads password -Uadmin_username@realm%%admin_pass"\ -"\n\tchange a user's password using an admin account" -"\n\t(note: use realm in UPPERCASE)\n" -"\nnet ads chostpass" -"\n\tchange the trust account password of this machine in the AD tree\n" -"\nnet ads printer [info | publish | remove] " -"\n\t lookup, add, or remove directory entry for a printer\n" +"\n\tchange a user's password using an admin account"\ +"\n\t(note: use realm in UPPERCASE)\n"\ +"\nnet ads chostpass"\ +"\n\tchange the trust account password of this machine in the AD tree\n"\ +"\nnet ads printer [info | publish | remove] "\ +"\n\t lookup, add, or remove directory entry for a printer\n"\ +"\nnet ads search"\ +"\n\tperform a raw LDAP search and dump the results\n" ); return -1; } @@ -56,7 +58,7 @@ static int net_ads_info(int argc, const char **argv) { ADS_STRUCT *ads; - ads = ads_init(NULL, opt_host, NULL, NULL); + ads = ads_init(NULL, NULL, opt_host, NULL, NULL); ads_connect(ads); if (!ads) { @@ -81,7 +83,7 @@ static ADS_STRUCT *ads_startup(void) BOOL need_password = False; BOOL second_time = False; - ads = ads_init(NULL, opt_host, NULL, NULL); + ads = ads_init(NULL, NULL, opt_host, NULL, NULL); if (!opt_user_name) { opt_user_name = "administrator"; @@ -135,27 +137,30 @@ int net_ads_check(void) } -static void usergrp_display(char *field, void **values, void *data_area) +static BOOL usergrp_display(char *field, void **values, void *data_area) { char **disp_fields = (char **) data_area; if (!field) { /* must be end of record */ if (!strchr_m(disp_fields[0], '$')) { if (disp_fields[1]) - printf("%-21.21s %-50.50s\n", + d_printf("%-21.21s %-50.50s\n", disp_fields[0], disp_fields[1]); else - printf("%-21.21s\n", disp_fields[0]); + d_printf("%s\n", disp_fields[0]); } SAFE_FREE(disp_fields[0]); SAFE_FREE(disp_fields[1]); - return; + return True; } + if (!values) /* must be new field, indicate string field */ + return True; if (StrCaseCmp(field, "sAMAccountName") == 0) { - disp_fields[0] = strdup(((struct berval *) values[0])->bv_val); + disp_fields[0] = strdup((char *) values[0]); } if (StrCaseCmp(field, "description") == 0) - disp_fields[1] = strdup(((struct berval *) values[0])->bv_val); + disp_fields[1] = strdup((char *) values[0]); + return True; /* always strings here */ } static int net_ads_user_usage(int argc, const char **argv) @@ -167,6 +172,7 @@ static int ads_user_add(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS status; + char *upn, *userdn; void *res=NULL; int rc = -1; @@ -183,18 +189,43 @@ static int ads_user_add(int argc, const char **argv) if (ads_count_replies(ads, res)) { d_printf("ads_user_add: User %s already exists\n", argv[0]); - ads_msgfree(ads, res); goto done; } status = ads_add_user_acct(ads, argv[0], opt_comment); + if (!ADS_ERR_OK(status)) { + d_printf("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]); + rc = 0; + goto done; + } + + /* try setting the password */ + asprintf(&upn, "%s@%s", argv[0], ads->realm); + status = krb5_set_password(ads->kdc_server, upn, argv[1]); + safe_free(upn); if (ADS_ERR_OK(status)) { d_printf("User %s added\n", argv[0]); rc = 0; - } else { - d_printf("Could not add user %s: %s\n", argv[0], - ads_errstr(status)); + goto done; + } + + /* password didn't set, delete account */ + d_printf("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); + ads_del_dn(ads, userdn); + ads_memfree(ads, userdn); } done: @@ -233,7 +264,7 @@ static int ads_user_info(int argc, const char **argv) char **groupname; for (i=0;grouplist[i];i++) { groupname = ldap_explode_dn(grouplist[i], 1); - printf("%s\n", groupname[0]); + d_printf("%s\n", groupname[0]); ldap_value_free(groupname); } ldap_value_free(grouplist); @@ -308,26 +339,111 @@ int net_ads_user(int argc, const char **argv) return net_run_function(argc, argv, func, net_ads_user_usage); } -static int net_ads_group(int argc, const char **argv) +static int net_ads_group_usage(int argc, const char **argv) +{ + return net_help_group(argc, argv); +} + +static int ads_group_add(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + void *res=NULL; + int rc = -1; + + if (argc < 1) return net_ads_group_usage(argc, argv); + + if (!(ads = ads_startup())) return -1; + + status = ads_find_user_acct(ads, &res, argv[0]); + + if (!ADS_ERR_OK(status)) { + d_printf("ads_group_add: %s\n", ads_errstr(status)); + goto done; + } + + if (ads_count_replies(ads, res)) { + d_printf("ads_group_add: Group %s already exists\n", argv[0]); + ads_msgfree(ads, res); + goto done; + } + + status = ads_add_group_acct(ads, argv[0], opt_comment); + + if (ADS_ERR_OK(status)) { + d_printf("Group %s added\n", argv[0]); + rc = 0; + } else { + d_printf("Could not add group %s: %s\n", argv[0], + ads_errstr(status)); + } + + done: + if (res) + ads_msgfree(ads, res); + ads_destroy(&ads); + return rc; +} + +static int ads_group_delete(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS rc; + void *res; + char *groupdn; + + if (argc < 1) return net_ads_group_usage(argc, argv); + + if (!(ads = ads_startup())) return -1; + + rc = ads_find_user_acct(ads, &res, argv[0]); + if (!ADS_ERR_OK(rc)) { + DEBUG(0, ("Group %s does not exist\n", argv[0])); + return -1; + } + groupdn = ads_get_dn(ads, res); + ads_msgfree(ads, res); + rc = ads_del_dn(ads, groupdn); + ads_memfree(ads, groupdn); + if (!ADS_ERR_OK(rc)) { + d_printf("Group %s deleted\n", argv[0]); + return 0; + } + d_printf("Error deleting group %s: %s\n", argv[0], + ads_errstr(rc)); + return -1; +} + +int net_ads_group(int argc, const char **argv) { + struct functable func[] = { + {"ADD", ads_group_add}, + {"DELETE", ads_group_delete}, + {NULL, NULL} + }; ADS_STRUCT *ads; ADS_STATUS rc; const char *shortattrs[] = {"sAMAccountName", NULL}; const char *longattrs[] = {"sAMAccountName", "description", NULL}; char *disp_fields[2] = {NULL, NULL}; - if (!(ads = ads_startup())) return -1; + if (argc == 0) { + if (!(ads = ads_startup())) return -1; - if (opt_long_list_entries) - d_printf("\nGroup name Comment"\ - "\n-----------------------------\n"); - rc = ads_do_search_all_fn(ads, ads->bind_path, LDAP_SCOPE_SUBTREE, - "(objectclass=group)", opt_long_list_entries - ? longattrs : shortattrs, usergrp_display, - disp_fields); + if (opt_long_list_entries) + d_printf("\nGroup name Comment"\ + "\n-----------------------------\n"); + rc = ads_do_search_all_fn(ads, ads->bind_path, + LDAP_SCOPE_SUBTREE, + "(objectclass=group)", + opt_long_list_entries ? longattrs : + shortattrs, usergrp_display, + disp_fields); - ads_destroy(&ads); - return 0; + ads_destroy(&ads); + return 0; + } + return net_run_function(argc, argv, func, net_ads_group_usage); } static int net_ads_status(int argc, const char **argv) @@ -485,7 +601,7 @@ static int net_ads_printer_info(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; - char *servername, *printername; + const char *servername, *printername; extern pstring global_myname; void *res = NULL; @@ -521,6 +637,11 @@ static int net_ads_printer_info(int argc, const char **argv) return 0; } +void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len) +{ + return; +} + static int net_ads_printer_publish(int argc, const char **argv) { ADS_STRUCT *ads; @@ -528,6 +649,7 @@ static int net_ads_printer_publish(int argc, const char **argv) char *uncname, *servername; ADS_PRINTER_ENTRY prt; extern pstring global_myname; + char *ports[2] = {"Samba", NULL}; /* these const strings are only here as an example. The attributes @@ -536,7 +658,6 @@ static int net_ads_printer_publish(int argc, const char **argv) const char *bins[] = {"Tray 21", NULL}; const char *media[] = {"Letter", NULL}; const char *orients[] = {"PORTRAIT", NULL}; - const char *ports[] = {"Samba", NULL}; if (!(ads = ads_startup())) return -1; @@ -545,6 +666,9 @@ static int net_ads_printer_publish(int argc, const char **argv) memset(&prt, 0, sizeof(ADS_PRINTER_ENTRY)); + /* we don't sue the servername or unc name provided by + get_a_printer, because the server name might be + localhost or an ip address */ prt.printerName = argv[0]; asprintf(&servername, "%s.%s", global_myname, ads->realm); prt.serverName = servername; @@ -557,7 +681,7 @@ static int net_ads_printer_publish(int argc, const char **argv) prt.printOrientationsSupported = (char **) orients; prt.portName = (char **) ports; prt.printSpooling = "PrintAfterSpooled"; - + rc = ads_add_printer(ads, &prt); if (!ADS_ERR_OK(rc)) { d_printf("ads_publish_printer: %s\n", ads_errstr(rc)); @@ -650,7 +774,7 @@ static int net_ads_password(int argc, const char **argv) /* use the realm so we can eventually change passwords for users in realms other than default */ - if (!(ads = ads_init(realm, NULL, NULL, NULL))) return -1; + if (!(ads = ads_init(realm, NULL, NULL, NULL, NULL))) return -1; asprintf(&prompt, "Enter new password for %s:", argv[0]); @@ -681,8 +805,7 @@ static int net_ads_change_localhost_pass(int argc, const char **argv) char *hostname; ADS_STATUS ret; - - if (!(ads = ads_init(NULL, NULL, NULL, NULL))) return -1; + if (!(ads = ads_init_simple())) return -1; hostname = strdup(global_myname); strlower(hostname); @@ -706,19 +829,79 @@ static int net_ads_change_localhost_pass(int argc, const char **argv) return 0; } +/* + help for net ads search +*/ +static int net_ads_search_usage(int argc, const char **argv) +{ + d_printf( + "\nnet ads search \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); + return -1; +} + + +/* + general ADS search function. Useful in diagnosing problems in ADS +*/ +static int net_ads_search(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS rc; + const char *exp; + const char **attrs; + void *res = NULL; + + if (argc < 1) { + return net_ads_search_usage(argc, argv); + } + + if (!(ads = ads_startup())) { + return -1; + } + + exp = argv[0]; + attrs = (argv + 1); + + rc = ads_do_search_all(ads, ads->bind_path, + LDAP_SCOPE_SUBTREE, + exp, attrs, &res); + if (!ADS_ERR_OK(rc)) { + d_printf("search failed: %s\n", ads_errstr(rc)); + return -1; + } + + d_printf("Got %d replies\n\n", ads_count_replies(ads, res)); + + /* dump the results */ + ads_dump(ads, res); + + ads_msgfree(ads, res); + ads_destroy(&ads); + + return 0; +} + + int net_ads_help(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}, #if 0 {"INFO", net_ads_info}, {"JOIN", net_ads_join}, {"LEAVE", net_ads_leave}, {"STATUS", net_ads_status}, - {"GROUP", net_ads_group}, {"PASSWORD", net_ads_password}, {"CHOSTPASS", net_ads_change_localhost_pass}, - {"PRINTER", net_ads_printer}, #endif {NULL, NULL} }; @@ -738,6 +921,7 @@ int net_ads(int argc, const char **argv) {"PASSWORD", net_ads_password}, {"CHOSTPASS", net_ads_change_localhost_pass}, {"PRINTER", net_ads_printer}, + {"SEARCH", net_ads_search}, {"HELP", net_ads_help}, {NULL, NULL} }; @@ -773,6 +957,11 @@ int net_ads_user(int argc, const char **argv) return net_ads_noads(); } +int net_ads_group(int argc, const char **argv) +{ + return net_ads_noads(); +} + /* this one shouldn't display a message */ int net_ads_check(void) { diff --git a/source3/utils/net_help.c b/source3/utils/net_help.c index 21af8a4fd9..ab3eac4b43 100644 --- a/source3/utils/net_help.c +++ b/source3/utils/net_help.c @@ -19,6 +19,7 @@ */ #include "includes.h" +#include "../utils/net.h" int net_common_methods_usage(int argc, const char**argv) { @@ -63,12 +64,12 @@ static int help_usage(int argc, const char **argv) 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 [misc. options] [targets]"\ + d_printf("\nnet user [misc. options] [targets]\n\tList users\n"); + d_printf("\nnet user DELETE [misc. options] [targets]"\ "\n\tDelete specified user\n"); - d_printf("\nnet [method] user INFO [misc. options] [targets]"\ + d_printf("\nnet user INFO [misc. options] [targets]"\ "\n\tList the domain groups of the specified user\n"); - d_printf("\nnet [method] user ADD [-F user flags] [misc. options]"\ + d_printf("\nnet user ADD [password] [-F user flags] [misc. options]"\ " [targets]\n\tAdd specified user\n"); net_common_methods_usage(argc, argv); @@ -78,16 +79,66 @@ int net_help_user(int argc, const char **argv) return -1; } +int net_help_group(int argc, const char **argv) +{ + d_printf("net group [misc. options] [targets]"\ + "\n\tList user groups\n\n"); + d_printf("net group DELETE [misc. options] [targets]"\ + "\n\tDelete specified group\n"); + d_printf("\nnet group ADD [-C comment]"\ + " [misc. options] [targets]\n\tCreate specified group\n"); + net_common_methods_usage(argc, argv); + net_common_flags_usage(argc, argv); + d_printf( + "\t-C or --comment=\tdescriptive comment (for add only)\n"); + return -1; +} + +int net_help_share(int argc, const char **argv) +{ + d_printf( + "\nnet share [misc. options] [targets] \n" + "\tenumerates all exported resources (network shares) " + "on target server\n" + "\nnet share ADD [misc. options] [targets]" + "\n\tAdds a share from a server (makes the export active)\n" + "\nnet share DELETE [misc. options] [targets]\n" + "\n\tDeletes a share from a server (makes the export inactive)\n"); + net_common_methods_usage(argc, argv); + net_common_flags_usage(argc, argv); + d_printf( + "\t-C or --comment=\tdescriptive comment (for add only)\n" + "\t-M or --maxusers=\t\tmax users allowed for share\n"); + return -1; +} + +int net_help_file(int argc, const char **argv) +{ + d_printf("net file [misc. options] [targets]\n"\ + "\tlists all open files on file server\n\n"); + d_printf("net file USER [misc. options] [targets]"\ + "\n\tlists all files opened by username on file server\n\n"); + d_printf("net file CLOSE [misc. options] [targets]\n"\ + "\tcloses specified file on target server\n\n"); + d_printf("net [rap] file INFO [misc. options] [targets]\n"\ + "\tdisplays information about the specified open file\n"); + + net_common_methods_usage(argc, argv); + net_common_flags_usage(argc, argv); + 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 group\t\tto manage groups\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"\ + " net ads \tto run ADS commands\n"\ + " net rap \tto run RAP (pre-RPC) commands\n"\ + " net rpc \tto run RPC commands\n"\ "\n"\ "Type \"net help