From 0af1500fc0bafe61019f1b2ab1d9e1d369221240 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 3 Feb 2006 22:19:41 +0000 Subject: r13316: Let the carnage begin.... Sync with trunk as off r13315 (This used to be commit 17e63ac4ed8325c0d44fe62b2442449f3298559f) --- source3/utils/net.c | 27 ++ source3/utils/net.h | 23 ++ source3/utils/net_ads_gpo.c | 436 +++++++++++++++++++++ source3/utils/net_groupmap.c | 38 +- source3/utils/net_help.c | 9 +- source3/utils/net_lookup.c | 52 +++ source3/utils/net_rpc.c | 557 ++++++++++++++++++++++++--- source3/utils/net_rpc_rights.c | 55 ++- source3/utils/net_rpc_samsync.c | 141 +------ source3/utils/net_rpc_shell.c | 270 +++++++++++++ source3/utils/net_sam.c | 784 +++++++++++++++++++++++++++++++++++++ source3/utils/net_usershare.c | 829 ++++++++++++++++++++++++++++++++++++++++ source3/utils/net_util.c | 89 +++++ source3/utils/netlookup.c | 209 ++++++++++ source3/utils/ntlm_auth.c | 6 +- source3/utils/pdbedit.c | 10 +- source3/utils/smbcacls.c | 2 +- source3/utils/smbcontrol.c | 114 +++++- source3/utils/smbcquotas.c | 2 +- source3/utils/smbpasswd.c | 24 +- 20 files changed, 3453 insertions(+), 224 deletions(-) create mode 100644 source3/utils/net_ads_gpo.c create mode 100644 source3/utils/net_rpc_shell.c create mode 100644 source3/utils/net_sam.c create mode 100644 source3/utils/net_usershare.c create mode 100644 source3/utils/net_util.c create mode 100644 source3/utils/netlookup.c (limited to 'source3/utils') diff --git a/source3/utils/net.c b/source3/utils/net.c index 25e10c6a316..069047c9ec8 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -132,6 +132,29 @@ int net_run_function(int argc, const char **argv, struct functable *table, return usage_fn(argc, argv); } +/* + * run a function from a function table. + */ +int net_run_function2(int argc, const char **argv, const char *whoami, + struct functable2 *table) +{ + int i; + + if (argc != 0) { + for (i=0; table[i].funcname; i++) { + if (StrCaseCmp(argv[0], table[i].funcname) == 0) + return table[i].fn(argc-1, argv+1); + } + } + + for (i=0; table[i].funcname != NULL; i++) { + d_printf("%s %-15s %s\n", whoami, table[i].funcname, + table[i].helptext); + } + + return -1; +} + /**************************************************************************** connect to \\server\service ****************************************************************************/ @@ -376,6 +399,8 @@ struct cli_state *net_make_ipc_connection(unsigned flags) if (NT_STATUS_IS_OK(nt_status)) { return cli; } else { + d_fprintf(stderr, "Connection failed: %s\n", + nt_errstr(nt_status)); return NULL; } } @@ -705,6 +730,7 @@ static struct functable net_func[] = { {"USER", net_user}, {"GROUP", net_group}, {"GROUPMAP", net_groupmap}, + {"SAM", net_sam}, {"VALIDATE", net_rap_validate}, {"GROUPMEMBER", net_rap_groupmember}, {"ADMIN", net_rap_admin}, @@ -722,6 +748,7 @@ static struct functable net_func[] = { {"MAXRID", net_maxrid}, {"IDMAP", net_idmap}, {"STATUS", net_status}, + {"USERSHARE", net_usershare}, {"USERSIDLIST", net_usersidlist}, #ifdef WITH_FAKE_KASERVER {"AFS", net_afs}, diff --git a/source3/utils/net.h b/source3/utils/net.h index 2df13cfb8f1..fc3167012d6 100644 --- a/source3/utils/net.h +++ b/source3/utils/net.h @@ -39,6 +39,29 @@ typedef struct copy_clistate { uint16 attribute; }copy_clistate; +struct rpc_sh_ctx { + struct cli_state *cli; + + DOM_SID *domain_sid; + char *domain_name; + + const char *whoami; + const char *thiscmd; + struct rpc_sh_cmd *cmds; + struct rpc_sh_ctx *parent; +}; + +struct rpc_sh_cmd { + const char *name; + struct rpc_sh_cmd *(*sub)(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx); + int pipe_idx; + NTSTATUS (*fn)(TALLOC_CTX *mem_ctx, struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv); + const char *help; +}; + /* INCLUDE FILES */ #include "utils/net_proto.h" diff --git a/source3/utils/net_ads_gpo.c b/source3/utils/net_ads_gpo.c new file mode 100644 index 00000000000..fec6fb88fa2 --- /dev/null +++ b/source3/utils/net_ads_gpo.c @@ -0,0 +1,436 @@ +/* + Samba Unix/Linux SMB client library + net ads commands for Group Policy + Copyright (C) 2005 Guenther Deschner (gd@samba.org) + + 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" +#include "utils/net.h" + +#ifdef HAVE_ADS + +static int net_ads_gpo_usage(int argc, const char **argv) +{ + d_printf( + "net ads gpo \n"\ +" can be either:\n"\ +" ADDLINK Link a container to a GPO\n"\ +" APPLY Apply all GPOs\n"\ +" DELETELINK Delete a gPLink from a container\n"\ +" EFFECTIVE Lists all GPOs assigned to a machine\n"\ +" GETGPO Lists specified GPO\n"\ +" GETLINK Lists gPLink of a containter\n"\ +" HELP Prints this help message\n"\ +" LIST Lists all GPOs\n"\ +"\n" + ); + return -1; +} + +static int net_ads_gpo_effective(int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx; + ADS_STRUCT *ads; + ADS_STATUS status; + const char *attrs[] = {"distinguishedName", "userAccountControl", NULL}; + void *res = NULL; + const char *filter; + char *dn = NULL; + struct GROUP_POLICY_OBJECT *gpo_list; + uint32 uac = 0; + uint32 flags = 0; + + if (argc < 1) { + return -1; + } + + mem_ctx = talloc_init("net_ads_gpo_effective"); + if (mem_ctx == NULL) { + return -1; + } + + filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))", argv[0]); + if (filter == NULL) { + goto out; + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_do_search_all(ads, ads->config.bind_path, + LDAP_SCOPE_SUBTREE, + filter, attrs, &res); + + if (!ADS_ERR_OK(status)) { + goto out; + } + + if (ads_count_replies(ads, res) != 1) { + printf("no result\n"); + goto out; + } + + dn = ads_get_dn(ads, res); + if (dn == NULL) { + goto out; + } + + if (!ads_pull_uint32(ads, res, "userAccountControl", &uac)) { + goto out; + } + + if (uac & UF_WORKSTATION_TRUST_ACCOUNT) { + flags |= GPO_LIST_FLAG_MACHINE; + } + + printf("%s: '%s' has dn: '%s'\n", + (uac & UF_WORKSTATION_TRUST_ACCOUNT) ? "machine" : "user", + argv[0], dn); + + status = ads_get_gpo_list(ads, mem_ctx, dn, flags, &gpo_list); + if (!ADS_ERR_OK(status)) { + goto out; + } + + printf("unsorted full dump of all GPOs for this machine:\n"); + + { + struct GROUP_POLICY_OBJECT *gpo = gpo_list; + + for (gpo = gpo_list; gpo; gpo = gpo->next) { + dump_gpo(mem_ctx, gpo); + } + } + + printf("sorted full dump of all GPOs valid for this machine:\n"); + +out: + ads_memfree(ads, dn); + ads_msgfree(ads, res); + + ads_destroy(&ads); + talloc_destroy(mem_ctx); + return 0; +} + +static int net_ads_gpo_list(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + void *res = NULL; + int num_reply = 0; + void *msg = NULL; + struct GROUP_POLICY_OBJECT gpo; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_init("net_ads_gpo_list"); + if (mem_ctx == NULL) { + return -1; + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_do_search_all(ads, ads->config.bind_path, + LDAP_SCOPE_SUBTREE, + "(objectclass=groupPolicyContainer)", NULL, &res); + if (!ADS_ERR_OK(status)) { + d_printf("search failed: %s\n", ads_errstr(status)); + goto out; + } + + num_reply = ads_count_replies(ads, res); + + d_printf("Got %d replies\n\n", num_reply); + + /* dump the results */ + for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { + + status = ads_parse_gpo(ads, mem_ctx, msg, ads_get_dn(ads, msg), &gpo); + + if (!ADS_ERR_OK(status)) { + d_printf("parse failed: %s\n", ads_errstr(status)); + goto out; + } + + dump_gpo(mem_ctx, &gpo); + + } + +out: + ads_msgfree(ads, res); + + talloc_destroy(mem_ctx); + ads_destroy(&ads); + + return 0; +} + +static int net_ads_gpo_apply(int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx; + ADS_STRUCT *ads; + ADS_STATUS status; + const char *attrs[] = {"distinguishedName", "userAccountControl", NULL}; + void *res = NULL; + const char *filter; + char *dn = NULL; + struct GROUP_POLICY_OBJECT *gpo_list; + uint32 uac = 0; + uint32 flags = 0; + + if (argc < 1) { + return -1; + } + + mem_ctx = talloc_init("net_ads_gpo_apply"); + if (mem_ctx == NULL) { + goto out; + } + + filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))", argv[0]); + if (filter == NULL) { + goto out; + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_do_search_all(ads, ads->config.bind_path, + LDAP_SCOPE_SUBTREE, + filter, attrs, &res); + + if (!ADS_ERR_OK(status)) { + goto out; + } + + if (ads_count_replies(ads, res) != 1) { + printf("no result\n"); + goto out; + } + + dn = ads_get_dn(ads, res); + if (dn == NULL) { + goto out; + } + + if (!ads_pull_uint32(ads, res, "userAccountControl", &uac)) { + goto out; + } + + if (uac & UF_WORKSTATION_TRUST_ACCOUNT) { + flags |= GPO_LIST_FLAG_MACHINE; + } + + printf("%s: '%s' has dn: '%s'\n", + (uac & UF_WORKSTATION_TRUST_ACCOUNT) ? "machine" : "user", + argv[0], dn); + + status = ads_get_gpo_list(ads, mem_ctx, dn, flags, &gpo_list); + if (!ADS_ERR_OK(status)) { + goto out; + } + + /* FIXME: allow to process just a single extension */ + status = gpo_process_gpo_list(ads, mem_ctx, &gpo_list, NULL, flags); + if (!ADS_ERR_OK(status)) { + goto out; + } + +out: + ads_memfree(ads, dn); + ads_msgfree(ads, res); + + ads_destroy(&ads); + talloc_destroy(mem_ctx); + return 0; +} + + +static int net_ads_gpo_get_link(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + TALLOC_CTX *mem_ctx; + struct GP_LINK gp_link; + + if (argc < 1) { + return -1; + } + + mem_ctx = talloc_init("add_gpo_link"); + if (mem_ctx == NULL) { + return -1; + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_get_gpo_link(ads, mem_ctx, argv[0], &gp_link); + if (!ADS_ERR_OK(status)) { + d_printf("get link for %s failed: %s\n", argv[0], ads_errstr(status)); + goto out; + } + + dump_gplink(ads, mem_ctx, &gp_link); + +out: + talloc_destroy(mem_ctx); + ads_destroy(&ads); + + return 0; +} + +static int net_ads_gpo_add_link(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + uint32 gpo_opt = 0; + TALLOC_CTX *mem_ctx; + + if (argc < 2) { + return -1; + } + + mem_ctx = talloc_init("add_gpo_link"); + if (mem_ctx == NULL) { + return -1; + } + + if (argc == 3) { + gpo_opt = atoi(argv[2]); + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_add_gpo_link(ads, mem_ctx, argv[0], argv[1], gpo_opt); + if (!ADS_ERR_OK(status)) { + d_printf("add link failed: %s\n", ads_errstr(status)); + goto out; + } + +out: + talloc_destroy(mem_ctx); + ads_destroy(&ads); + + return 0; +} + +static int net_ads_gpo_delete_link(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + TALLOC_CTX *mem_ctx; + + if (argc < 2) { + return -1; + } + + mem_ctx = talloc_init("delete_gpo_link"); + if (mem_ctx == NULL) { + return -1; + } + + if (!(ads = ads_startup())) { + goto out; + } + + status = ads_delete_gpo_link(ads, mem_ctx, argv[0], argv[1]); + if (!ADS_ERR_OK(status)) { + d_printf("delete link failed: %s\n", ads_errstr(status)); + goto out; + } + +out: + talloc_destroy(mem_ctx); + ads_destroy(&ads); + + return 0; +} + +static int net_ads_gpo_get_gpo(int argc, const char **argv) +{ + ADS_STRUCT *ads; + ADS_STATUS status; + TALLOC_CTX *mem_ctx; + struct GROUP_POLICY_OBJECT gpo; + uint32 sysvol_gpt_version; + + if (argc < 1) { + return -1; + } + + mem_ctx = talloc_init("add_gpo_get_gpo"); + if (mem_ctx == NULL) { + return -1; + } + + if (!(ads = ads_startup())) { + goto out; + } + + if (strnequal(argv[0], "CN={", strlen("CN={"))) { + status = ads_get_gpo(ads, mem_ctx, argv[0], NULL, NULL, &gpo); + } else { + status = ads_get_gpo(ads, mem_ctx, NULL, argv[0], NULL, &gpo); + } + + if (!ADS_ERR_OK(status)) { + d_printf("get gpo for [%s] failed: %s\n", argv[0], ads_errstr(status)); + goto out; + } + + dump_gpo(mem_ctx, &gpo); + + status = ADS_ERROR_NT(ads_gpo_get_sysvol_gpt_version(ads, mem_ctx, gpo.file_sys_path, &sysvol_gpt_version)); + if (!ADS_ERR_OK(status)) { + goto out; + } + + printf("sysvol GPT version: %d\n", sysvol_gpt_version); + +out: + talloc_destroy(mem_ctx); + ads_destroy(&ads); + + return 0; +} + +int net_ads_gpo(int argc, const char **argv) +{ + struct functable func[] = { + {"LIST", net_ads_gpo_list}, + {"EFFECTIVE", net_ads_gpo_effective}, + {"ADDLINK", net_ads_gpo_add_link}, + {"DELETELINK", net_ads_gpo_delete_link}, + {"GETLINK", net_ads_gpo_get_link}, + {"GETGPO", net_ads_gpo_get_gpo}, + {"HELP", net_ads_gpo_usage}, + {"APPLY", net_ads_gpo_apply}, + {NULL, NULL} + }; + + return net_run_function(argc, argv, func, net_ads_gpo_usage); +} + +#endif diff --git a/source3/utils/net_groupmap.c b/source3/utils/net_groupmap.c index 1cff120c393..96a6aa531aa 100644 --- a/source3/utils/net_groupmap.c +++ b/source3/utils/net_groupmap.c @@ -93,6 +93,7 @@ static void print_map_entry ( GROUP_MAP map, BOOL long_list ) else { d_printf("%s\n", map.nt_name); d_printf("\tSID : %s\n", sid_string_static(&map.sid)); + d_printf("\tUnix gid : %d\n", map.gid); d_printf("\tUnix group: %s\n", gidtoname(map.gid)); d_printf("\tGroup type: %s\n", sid_type_lookup(map.sid_name_use)); @@ -261,10 +262,26 @@ static int net_groupmap_add(int argc, const char **argv) d_fprintf(stderr, "Can't lookup UNIX group %s\n", unixgrp); return -1; } + + { + GROUP_MAP map; + if (pdb_getgrgid(&map, gid)) { + d_printf("Unix group %s already mapped to SID %s\n", + unixgrp, sid_string_static(&map.sid)); + return -1; + } + } if ( (rid == 0) && (string_sid[0] == '\0') ) { - d_printf("No rid or sid specified, choosing algorithmic mapping\n"); - rid = pdb_gid_to_group_rid(gid); + d_printf("No rid or sid specified, choosing a RID\n"); + if (pdb_rid_algorithm()) { + rid = pdb_gid_to_group_rid(gid); + } else { + if (!pdb_new_rid(&rid)) { + d_printf("Could not get new RID\n"); + } + } + d_printf("Got RID %d\n", rid); } /* append the rid to our own domain/machine SID if we don't have a full SID */ @@ -423,7 +440,7 @@ static int net_groupmap_modify(int argc, const char **argv) map.gid = gid; } - if ( !pdb_update_group_mapping_entry(&map) ) { + if ( !NT_STATUS_IS_OK(pdb_update_group_mapping_entry(&map)) ) { d_fprintf(stderr, "Could not update group database\n"); return -1; } @@ -548,7 +565,7 @@ static int net_groupmap_set(int argc, const char **argv) fstrcpy(map.nt_name, ntgroup); fstrcpy(map.comment, ""); - if (!pdb_add_group_mapping_entry(&map)) { + if (!NT_STATUS_IS_OK(pdb_add_group_mapping_entry(&map))) { d_fprintf(stderr, "Could not add mapping entry for %s\n", ntgroup); return -1; @@ -582,7 +599,7 @@ static int net_groupmap_set(int argc, const char **argv) if (grp != NULL) map.gid = grp->gr_gid; - if (!pdb_update_group_mapping_entry(&map)) { + if (!NT_STATUS_IS_OK(pdb_update_group_mapping_entry(&map))) { d_fprintf(stderr, "Could not update group mapping for %s\n", ntgroup); return -1; } @@ -633,7 +650,7 @@ static int net_groupmap_addmem(int argc, const char **argv) return -1; } - if (!pdb_add_aliasmem(&alias, &member)) { + if (!NT_STATUS_IS_OK(pdb_add_aliasmem(&alias, &member))) { d_fprintf(stderr, "Could not add sid %s to alias %s\n", argv[1], argv[0]); return -1; @@ -653,7 +670,7 @@ static int net_groupmap_delmem(int argc, const char **argv) return -1; } - if (!pdb_del_aliasmem(&alias, &member)) { + if (!NT_STATUS_IS_OK(pdb_del_aliasmem(&alias, &member))) { d_fprintf(stderr, "Could not delete sid %s from alias %s\n", argv[1], argv[0]); return -1; @@ -677,7 +694,7 @@ static int net_groupmap_listmem(int argc, const char **argv) members = NULL; num = 0; - if (!pdb_enum_aliasmem(&alias, &members, &num)) { + if (!NT_STATUS_IS_OK(pdb_enum_aliasmem(&alias, &members, &num))) { d_fprintf(stderr, "Could not list members for sid %s\n", argv[0]); return -1; } @@ -701,8 +718,9 @@ static BOOL print_alias_memberships(TALLOC_CTX *mem_ctx, alias_rids = NULL; num_alias_rids = 0; - if (!pdb_enum_alias_memberships(mem_ctx, domain_sid, member, 1, - &alias_rids, &num_alias_rids)) { + if (!NT_STATUS_IS_OK(pdb_enum_alias_memberships( + mem_ctx, domain_sid, member, 1, + &alias_rids, &num_alias_rids))) { d_fprintf(stderr, "Could not list memberships for sid %s\n", sid_string_static(member)); return False; diff --git a/source3/utils/net_help.c b/source3/utils/net_help.c index c5188c3608e..79062345ab6 100644 --- a/source3/utils/net_help.c +++ b/source3/utils/net_help.c @@ -61,7 +61,7 @@ static int help_usage(int argc, const char **argv) "Valid functions are:\n"\ " RPC RAP ADS FILE SHARE SESSION SERVER DOMAIN PRINTQ USER GROUP VALIDATE\n"\ " GROUPMEMBER ADMIN SERVICE PASSWORD TIME LOOKUP GETLOCALSID SETLOCALSID\n"\ -" CHANGESCRETPW IDMAP\n"); +" CHANGESCRETPW LOOKUP SAM\n"); return -1; } @@ -223,8 +223,9 @@ static int net_usage(int argc, const char **argv) " 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 sam\t\tto edit the local user database directly\n"\ + " net lookup\t\tto look up various things\n"\ " net groupmap\t\tto manage group mappings\n"\ - " net idmap\t\tto manage the idmap id mappings\n"\ " net join\t\tto join a domain\n"\ " net cache\t\tto operate on cache tdb file\n"\ " net getlocalsid [NAME]\tto get the SID for local name\n"\ @@ -233,6 +234,7 @@ static int net_usage(int argc, const char **argv) " \tthis requires the -f flag as a safety barrier\n"\ " net status\t\tShow server status\n"\ " net usersidlist\tto get a list of all users with their SIDs\n" + " net usershare\t\tto add, delete and list locally user-modifiable shares\n" "\n"\ " net ads \tto run ADS commands\n"\ " net rap \tto run RAP (pre-RPC) commands\n"\ @@ -270,11 +272,12 @@ int net_help(int argc, const char **argv) {"PASSWORD", net_rap_password_usage}, {"TIME", net_time_usage}, {"LOOKUP", net_lookup_usage}, + {"USERSHARE", net_usershare_usage}, {"USERSIDLIST", net_usersidlist_usage}, #ifdef WITH_FAKE_KASERVER {"AFS", net_help_afs}, #endif - {"IDMAP", net_help_idmap}, + {"HELP", help_usage}, {NULL, NULL}}; diff --git a/source3/utils/net_lookup.c b/source3/utils/net_lookup.c index 8ee63515d45..dd2d666d5a0 100644 --- a/source3/utils/net_lookup.c +++ b/source3/utils/net_lookup.c @@ -28,6 +28,8 @@ int net_lookup_usage(int argc, const char **argv) " net lookup kdc [realm]\n\tgives IP of realm's kerberos KDC\n\n" " net lookup dc [domain]\n\tgives IP of domains Domain Controllers\n\n" " net lookup master [domain|wg]\n\tgive IP of master browser\n\n" +" net lookup name [name]\n\tLookup name's sid and type\n\n" +" net lookup sid [sid]\n\tGive sid's name and type\n\n" ); return -1; } @@ -227,6 +229,54 @@ static int net_lookup_kdc(int argc, const char **argv) return -1; } +static int net_lookup_name(int argc, const char **argv) +{ + const char *dom, *name; + DOM_SID sid; + enum SID_NAME_USE type; + + if (argc != 1) { + d_printf("usage: net lookup name \n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ALL, + &dom, &name, &sid, &type)) { + d_printf("Could not lookup name %s\n", argv[0]); + return -1; + } + + d_printf("%s %d (%s) %s\\%s\n", sid_string_static(&sid), + type, sid_type_lookup(type), dom, name); + return 0; +} + +static int net_lookup_sid(int argc, const char **argv) +{ + const char *dom, *name; + DOM_SID sid; + enum SID_NAME_USE type; + + if (argc != 1) { + d_printf("usage: net lookup sid \n"); + return -1; + } + + if (!string_to_sid(&sid, argv[0])) { + d_printf("Could not convert %s to SID\n", argv[0]); + return -1; + } + + if (!lookup_sid(tmp_talloc_ctx(), &sid, + &dom, &name, &type)) { + d_printf("Could not lookup name %s\n", argv[0]); + return -1; + } + + d_printf("%s %d (%s) %s\\%s\n", sid_string_static(&sid), + type, sid_type_lookup(type), dom, name); + return 0; +} /* lookup hosts or IP addresses using internal samba lookup fns */ int net_lookup(int argc, const char **argv) @@ -239,6 +289,8 @@ int net_lookup(int argc, const char **argv) {"DC", net_lookup_dc}, {"MASTER", net_lookup_master}, {"KDC", net_lookup_kdc}, + {"NAME", net_lookup_name}, + {"SID", net_lookup_sid}, {NULL, NULL} }; diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index 0495a7b92c2..a9dc3a1fc65 100644 --- a/source3/utils/net_rpc.c +++ b/source3/utils/net_rpc.c @@ -49,46 +49,42 @@ static int net_mode_share; * @return The Domain SID of the remote machine. **/ -static DOM_SID *net_get_remote_domain_sid(struct cli_state *cli, TALLOC_CTX *mem_ctx, char **domain_name) +NTSTATUS net_get_remote_domain_sid(struct cli_state *cli, TALLOC_CTX *mem_ctx, + DOM_SID **domain_sid, char **domain_name) { struct rpc_pipe_client *lsa_pipe; - DOM_SID *domain_sid; POLICY_HND pol; NTSTATUS result = NT_STATUS_OK; uint32 info_class = 5; lsa_pipe = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &result); if (!lsa_pipe) { - fprintf(stderr, "could not initialise lsa pipe\n"); - goto error; + d_fprintf(stderr, "Could not initialise lsa pipe\n"); + return result; } result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, False, SEC_RIGHTS_MAXIMUM_ALLOWED, &pol); if (!NT_STATUS_IS_OK(result)) { - goto error; + d_fprintf(stderr, "open_policy failed: %s\n", + nt_errstr(result)); + return result; } - result = rpccli_lsa_query_info_policy(lsa_pipe, mem_ctx, &pol, info_class, - domain_name, &domain_sid); + result = rpccli_lsa_query_info_policy(lsa_pipe, mem_ctx, &pol, + info_class, domain_name, + domain_sid); if (!NT_STATUS_IS_OK(result)) { - error: - fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain); - - if (!NT_STATUS_IS_OK(result)) { - fprintf(stderr, "error: %s\n", nt_errstr(result)); - } - - exit(1); + d_fprintf(stderr, "lsaquery failed: %s\n", + nt_errstr(result)); + return result; } - if (lsa_pipe) { - rpccli_lsa_close(lsa_pipe, mem_ctx, &pol); - cli_rpc_pipe_close(lsa_pipe); - } + rpccli_lsa_close(lsa_pipe, mem_ctx, &pol); + cli_rpc_pipe_close(lsa_pipe); - return domain_sid; + return NT_STATUS_OK; } /** @@ -136,7 +132,12 @@ int run_rpc_command(struct cli_state *cli_arg, return -1; } - domain_sid = net_get_remote_domain_sid(cli, mem_ctx, &domain_name); + nt_status = net_get_remote_domain_sid(cli, mem_ctx, &domain_sid, + &domain_name); + if (!NT_STATUS_IS_OK(nt_status)) { + cli_shutdown(cli); + return -1; + } if (!(conn_flags & NET_FLAGS_NO_PIPE)) { if (lp_client_schannel() && (pipe_idx == PI_NETLOGON)) { @@ -410,7 +411,7 @@ int net_rpc_join(int argc, const char **argv) * @return Normal NTSTATUS return. **/ -static NTSTATUS rpc_info_internals(const DOM_SID *domain_sid, +NTSTATUS rpc_info_internals(const DOM_SID *domain_sid, const char *domain_name, struct cli_state *cli, struct rpc_pipe_client *pipe_hnd, @@ -1219,6 +1220,380 @@ int net_rpc_user(int argc, const char **argv) return net_run_function(argc, argv, func, rpc_user_usage); } +static NTSTATUS rpc_sh_user_list(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_user_list_internals(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static NTSTATUS rpc_sh_user_info(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_user_info_internals(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static NTSTATUS rpc_sh_handle_user(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv, + NTSTATUS (*fn)( + TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + const POLICY_HND *user_hnd, + int argc, const char **argv)) + +{ + POLICY_HND connect_pol, domain_pol, user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + DOM_SID sid; + uint32 rid; + enum SID_NAME_USE type; + + if (argc == 0) { + d_fprintf(stderr, "usage: %s \n", ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + ZERO_STRUCT(connect_pol); + ZERO_STRUCT(domain_pol); + ZERO_STRUCT(user_pol); + + result = net_rpc_lookup_name(mem_ctx, pipe_hnd->cli, argv[0], + NULL, NULL, &sid, &type); + if (!NT_STATUS_IS_OK(result)) { + d_fprintf(stderr, "Could not lookup %s: %s\n", argv[0], + nt_errstr(result)); + goto done; + } + + if (type != SID_NAME_USER) { + d_fprintf(stderr, "%s is a %s, not a user\n", argv[0], + sid_type_lookup(type)); + result = NT_STATUS_NO_SUCH_USER; + goto done; + } + + if (!sid_peek_check_rid(ctx->domain_sid, &sid, &rid)) { + d_fprintf(stderr, "%s is not in our domain\n", argv[0]); + result = NT_STATUS_NO_SUCH_USER; + goto done; + } + + result = rpccli_samr_connect(pipe_hnd, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, &connect_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + ctx->domain_sid, &domain_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol, + MAXIMUM_ALLOWED_ACCESS, + rid, &user_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = fn(mem_ctx, ctx, pipe_hnd, &user_pol, argc-1, argv+1); + + done: + if (is_valid_policy_hnd(&user_pol)) { + rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol); + } + if (is_valid_policy_hnd(&domain_pol)) { + rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol); + } + if (is_valid_policy_hnd(&connect_pol)) { + rpccli_samr_close(pipe_hnd, mem_ctx, &connect_pol); + } + return result; +} + +static NTSTATUS rpc_sh_user_show_internals(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + const POLICY_HND *user_hnd, + int argc, const char **argv) +{ + NTSTATUS result; + SAM_USERINFO_CTR *ctr; + SAM_USER_INFO_21 *info; + + if (argc != 0) { + d_fprintf(stderr, "usage: %s show \n", ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + result = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, user_hnd, + 21, &ctr); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + info = ctr->info.id21; + + d_printf("user rid: %d, group rid: %d\n", info->user_rid, + info->group_rid); + + return result; +} + +static NTSTATUS rpc_sh_user_show(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_sh_handle_user(mem_ctx, ctx, pipe_hnd, argc, argv, + rpc_sh_user_show_internals); +} + +#define FETCHSTR(name, rec) \ +do { if (strequal(ctx->thiscmd, name)) { \ + oldval = rpcstr_pull_unistr2_talloc(mem_ctx, &usr->uni_##rec); } \ +} while (0); + +#define SETSTR(name, rec, flag) \ +do { if (strequal(ctx->thiscmd, name)) { \ + init_unistr2(&usr->uni_##rec, argv[0], STR_TERMINATE); \ + init_uni_hdr(&usr->hdr_##rec, &usr->uni_##rec); \ + usr->fields_present |= ACCT_##flag; } \ +} while (0); + +static NTSTATUS rpc_sh_user_str_edit_internals(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + const POLICY_HND *user_hnd, + int argc, const char **argv) +{ + NTSTATUS result; + SAM_USERINFO_CTR *ctr; + SAM_USER_INFO_21 *usr; + const char *username; + const char *oldval = ""; + + if (argc > 1) { + d_fprintf(stderr, "usage: %s [new value|NULL]\n", + ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + result = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, user_hnd, + 21, &ctr); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + usr = ctr->info.id21; + + username = rpcstr_pull_unistr2_talloc(mem_ctx, &usr->uni_user_name); + + FETCHSTR("fullname", full_name); + FETCHSTR("homedir", home_dir); + FETCHSTR("homedrive", dir_drive); + FETCHSTR("logonscript", logon_script); + FETCHSTR("profilepath", profile_path); + FETCHSTR("description", acct_desc); + + if (argc == 0) { + d_printf("%s's %s: [%s]\n", username, ctx->thiscmd, oldval); + goto done; + } + + ZERO_STRUCTP(usr); + + if (strcmp(argv[0], "NULL") == 0) { + argv[0] = ""; + } + + SETSTR("fullname", full_name, FULL_NAME); + SETSTR("homedir", home_dir, HOME_DIR); + SETSTR("homedrive", dir_drive, HOME_DRIVE); + SETSTR("logonscript", logon_script, LOGON_SCRIPT); + SETSTR("profilepath", profile_path, PROFILE); + SETSTR("description", acct_desc, DESCRIPTION); + + result = rpccli_samr_set_userinfo2( + pipe_hnd, mem_ctx, user_hnd, 21, + &pipe_hnd->cli->user_session_key, ctr); + + d_printf("Set %s's %s from [%s] to [%s]\n", username, + ctx->thiscmd, oldval, argv[0]); + + done: + + return result; +} + +#define HANDLEFLG(name, rec) \ +do { if (strequal(ctx->thiscmd, name)) { \ + oldval = (oldflags & ACB_##rec) ? "yes" : "no"; \ + if (newval) { \ + newflags = oldflags | ACB_##rec; \ + } else { \ + newflags = oldflags & ~ACB_##rec; \ + } } } while (0); + +static NTSTATUS rpc_sh_user_str_edit(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_sh_handle_user(mem_ctx, ctx, pipe_hnd, argc, argv, + rpc_sh_user_str_edit_internals); +} + +static NTSTATUS rpc_sh_user_flag_edit_internals(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + const POLICY_HND *user_hnd, + int argc, const char **argv) +{ + NTSTATUS result; + SAM_USERINFO_CTR *ctr; + SAM_USER_INFO_21 *usr; + const char *username; + const char *oldval = "unknown"; + uint32 oldflags, newflags; + BOOL newval; + + if ((argc > 1) || + ((argc == 1) && !strequal(argv[0], "yes") && + !strequal(argv[0], "no"))) { + d_fprintf(stderr, "usage: %s [yes|no]\n", + ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + newval = strequal(argv[0], "yes"); + + result = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, user_hnd, + 21, &ctr); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + usr = ctr->info.id21; + + username = rpcstr_pull_unistr2_talloc(mem_ctx, &usr->uni_user_name); + oldflags = usr->acb_info; + newflags = usr->acb_info; + + HANDLEFLG("disabled", DISABLED); + HANDLEFLG("pwnotreq", PWNOTREQ); + HANDLEFLG("autolock", AUTOLOCK); + HANDLEFLG("pwnoexp", PWNOEXP); + + if (argc == 0) { + d_printf("%s's %s flag: %s\n", username, ctx->thiscmd, oldval); + goto done; + } + + ZERO_STRUCTP(usr); + + usr->acb_info = newflags; + usr->fields_present = ACCT_FLAGS; + + result = rpccli_samr_set_userinfo2( + pipe_hnd, mem_ctx, user_hnd, 21, + &pipe_hnd->cli->user_session_key, ctr); + + if (NT_STATUS_IS_OK(result)) { + d_printf("Set %s's %s flag from [%s] to [%s]\n", username, + ctx->thiscmd, oldval, argv[0]); + } + + done: + + return result; +} + +static NTSTATUS rpc_sh_user_flag_edit(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_sh_handle_user(mem_ctx, ctx, pipe_hnd, argc, argv, + rpc_sh_user_flag_edit_internals); +} + +struct rpc_sh_cmd *net_rpc_user_edit_cmds(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx) +{ + static struct rpc_sh_cmd cmds[] = { + + { "fullname", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's full name" }, + + { "homedir", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's home directory" }, + + { "homedrive", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's home drive" }, + + { "logonscript", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's logon script" }, + + { "profilepath", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's profile path" }, + + { "description", NULL, PI_SAMR, rpc_sh_user_str_edit, + "Show/Set a user's description" }, + + { "disabled", NULL, PI_SAMR, rpc_sh_user_flag_edit, + "Show/Set whether a user is disabled" }, + + { "autolock", NULL, PI_SAMR, rpc_sh_user_flag_edit, + "Show/Set whether a user locked out" }, + + { "pwnotreq", NULL, PI_SAMR, rpc_sh_user_flag_edit, + "Show/Set whether a user does not need a password" }, + + { "pwnoexp", NULL, PI_SAMR, rpc_sh_user_flag_edit, + "Show/Set whether a user's password does not expire" }, + + { NULL, NULL, 0, NULL, NULL } + }; + + return cmds; +} + +struct rpc_sh_cmd *net_rpc_user_cmds(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx) +{ + static struct rpc_sh_cmd cmds[] = { + + { "list", NULL, PI_SAMR, rpc_sh_user_list, + "List available users" }, + + { "info", NULL, PI_SAMR, rpc_sh_user_info, + "List the domain groups a user is member of" }, + + { "show", NULL, PI_SAMR, rpc_sh_user_show, + "Show info about a user" }, + + { "edit", net_rpc_user_edit_cmds, 0, NULL, + "Show/Modify a user's fields" }, + + { NULL, NULL, 0, NULL, NULL } + }; + + return cmds; +}; + /****************************************************************************/ /** @@ -1580,7 +1955,7 @@ static NTSTATUS get_sid_from_name(struct cli_state *cli, } result = rpccli_lsa_lookup_names(pipe_hnd, mem_ctx, &lsa_pol, 1, - &name, &sids, &types); + &name, NULL, &sids, &types); if (NT_STATUS_IS_OK(result)) { sid_copy(sid, &sids[0]); @@ -2581,7 +2956,7 @@ static NTSTATUS rpc_share_add_internals(const DOM_SID *domain_sid, opt_comment, perms, opt_maxusers, num_users, path, password, level, NULL); - return W_ERROR_IS_OK(result) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + return werror_to_ntstatus(result); } static int rpc_share_add(int argc, const char **argv) @@ -4291,6 +4666,114 @@ int net_rpc_share(int argc, const char **argv) return net_run_function(argc, argv, func, rpc_share_usage); } +static NTSTATUS rpc_sh_share_list(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_share_list_internals(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static NTSTATUS rpc_sh_share_add(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + WERROR result; + + if ((argc < 2) || (argc > 3)) { + d_fprintf(stderr, "usage: %s [comment]\n", + ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + result = rpccli_srvsvc_net_share_add( + pipe_hnd, mem_ctx, argv[0], STYPE_DISKTREE, + (argc == 3) ? argv[2] : "", + 0, 0, 0, argv[1], NULL, 2, NULL); + + return werror_to_ntstatus(result); +} + +static NTSTATUS rpc_sh_share_delete(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + WERROR result; + + if (argc != 1) { + d_fprintf(stderr, "usage: %s \n", ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + result = rpccli_srvsvc_net_share_del(pipe_hnd, mem_ctx, argv[0]); + return werror_to_ntstatus(result); +} + +static NTSTATUS rpc_sh_share_info(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + SRV_SHARE_INFO info; + SRV_SHARE_INFO_2 *info2 = &info.share.info2; + WERROR result; + + if (argc != 1) { + d_fprintf(stderr, "usage: %s \n", ctx->whoami); + return NT_STATUS_INVALID_PARAMETER; + } + + result = rpccli_srvsvc_net_share_get_info( + pipe_hnd, mem_ctx, argv[0], 2, &info); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + d_printf("Name: %s\n", + rpcstr_pull_unistr2_talloc(mem_ctx, + &info2->info_2_str.uni_netname)); + d_printf("Comment: %s\n", + rpcstr_pull_unistr2_talloc(mem_ctx, + &info2->info_2_str.uni_remark)); + + d_printf("Path: %s\n", + rpcstr_pull_unistr2_talloc(mem_ctx, + &info2->info_2_str.uni_path)); + d_printf("Password: %s\n", + rpcstr_pull_unistr2_talloc(mem_ctx, + &info2->info_2_str.uni_passwd)); + + done: + return werror_to_ntstatus(result); +} + +struct rpc_sh_cmd *net_rpc_share_cmds(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx) +{ + static struct rpc_sh_cmd cmds[] = { + + { "list", NULL, PI_SRVSVC, rpc_sh_share_list, + "List available shares" }, + + { "add", NULL, PI_SRVSVC, rpc_sh_share_add, + "Add a share" }, + + { "delete", NULL, PI_SRVSVC, rpc_sh_share_delete, + "Delete a share" }, + + { "info", NULL, PI_SRVSVC, rpc_sh_share_info, + "Get information about a share" }, + + { NULL, NULL, 0, NULL, NULL } + }; + + return cmds; +}; + /****************************************************************************/ static int rpc_file_usage(int argc, const char **argv) @@ -5011,7 +5494,6 @@ static int rpc_trustdom_establish(int argc, const char **argv) TALLOC_CTX *mem_ctx; NTSTATUS nt_status; DOM_SID *domain_sid; - smb_ucs2_t *uni_domain_name; char* domain_name; char* domain_name_pol; @@ -5119,13 +5601,6 @@ static int rpc_trustdom_establish(int argc, const char **argv) return -1; } - if (push_ucs2_talloc(mem_ctx, &uni_domain_name, domain_name_pol) == (size_t)-1) { - DEBUG(0, ("Could not convert domain name %s to unicode\n", - domain_name_pol)); - cli_shutdown(cli); - return -1; - } - /* There should be actually query info level 3 (following nt serv behaviour), but I still don't know if it's _really_ necessary */ @@ -5134,10 +5609,8 @@ static int rpc_trustdom_establish(int argc, const char **argv) */ if (!secrets_store_trusted_domain_password(domain_name, - uni_domain_name, - strlen_w(uni_domain_name)+1, opt_password, - *domain_sid)) { + domain_sid)) { DEBUG(0, ("Storing password for trusted domain failed.\n")); cli_shutdown(cli); return -1; @@ -5253,7 +5726,6 @@ static NTSTATUS vampire_trusted_domain(struct rpc_pipe_client *pipe_hnd, LSA_TRUSTED_DOMAIN_INFO *info; char *cleartextpwd = NULL; DATA_BLOB data; - smb_ucs2_t *uni_dom_name; nt_status = rpccli_lsa_query_trusted_domain_info_by_sid(pipe_hnd, mem_ctx, pol, 4, &dom_sid, &info); @@ -5276,18 +5748,9 @@ static NTSTATUS vampire_trusted_domain(struct rpc_pipe_client *pipe_hnd, goto done; } - if (push_ucs2_talloc(mem_ctx, &uni_dom_name, trusted_dom_name) == (size_t)-1) { - DEBUG(0, ("Could not convert domain name %s to unicode\n", - trusted_dom_name)); - nt_status = NT_STATUS_UNSUCCESSFUL; - goto done; - } - if (!secrets_store_trusted_domain_password(trusted_dom_name, - uni_dom_name, - strlen_w(uni_dom_name)+1, cleartextpwd, - dom_sid)) { + &dom_sid)) { DEBUG(0, ("Storing password for trusted domain failed.\n")); nt_status = NT_STATUS_UNSUCCESSFUL; goto done; @@ -6163,7 +6626,6 @@ int net_rpc_help(int argc, const char **argv) return (net_run_function(argc, argv, func, rpc_user_usage)); } - /** * 'net rpc' entrypoint. * @param argc Standard main() style argc @@ -6194,6 +6656,7 @@ int net_rpc(int argc, const char **argv) {"rights", net_rpc_rights}, {"service", net_rpc_service}, {"registry", net_rpc_registry}, + {"shell", net_rpc_shell}, {"help", net_rpc_help}, {NULL, NULL} }; diff --git a/source3/utils/net_rpc_rights.c b/source3/utils/net_rpc_rights.c index 2c15fef5a09..2f02b409483 100644 --- a/source3/utils/net_rpc_rights.c +++ b/source3/utils/net_rpc_rights.c @@ -75,7 +75,8 @@ static NTSTATUS name_to_sid(struct rpc_pipe_client *pipe_hnd, if ( !NT_STATUS_IS_OK(result) ) return result; - result = rpccli_lsa_lookup_names(pipe_hnd, mem_ctx, &pol, 1, &name, &sids, &sid_types); + result = rpccli_lsa_lookup_names(pipe_hnd, mem_ctx, &pol, 1, &name, + NULL, &sids, &sid_types); if ( NT_STATUS_IS_OK(result) ) sid_copy( sid, &sids[0] ); @@ -488,7 +489,7 @@ static NTSTATUS rpc_rights_revoke_internal(const DOM_SID *domain_sid, done: if ( !NT_STATUS_IS_OK(result) ) { - d_fprintf(stderr, "Failed to revoke privileges for %s (%s)", + d_fprintf(stderr, "Failed to revoke privileges for %s (%s)\n", argv[0], nt_errstr(result)); } @@ -560,3 +561,53 @@ int net_rpc_rights(int argc, const char **argv) return net_help_rights( argc, argv ); } + +static NTSTATUS rpc_sh_rights_list(TALLOC_CTX *mem_ctx, struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_rights_list_internal(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static NTSTATUS rpc_sh_rights_grant(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_rights_grant_internal(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static NTSTATUS rpc_sh_rights_revoke(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_rights_revoke_internal(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +struct rpc_sh_cmd *net_rpc_rights_cmds(TALLOC_CTX *mem_ctx, + struct rpc_sh_ctx *ctx) +{ + static struct rpc_sh_cmd cmds[] = { + + { "list", NULL, PI_LSARPC, rpc_sh_rights_list, + "View available or assigned privileges" }, + + { "grant", NULL, PI_LSARPC, rpc_sh_rights_grant, + "Assign privilege[s]" }, + + { "revoke", NULL, PI_LSARPC, rpc_sh_rights_revoke, + "Revoke privilege[s]" }, + + { NULL, NULL, 0, NULL, NULL } + }; + + return cmds; +}; + diff --git a/source3/utils/net_rpc_samsync.c b/source3/utils/net_rpc_samsync.c index 09e62d9defa..45fdfbfad3e 100644 --- a/source3/utils/net_rpc_samsync.c +++ b/source3/utils/net_rpc_samsync.c @@ -559,7 +559,7 @@ static NTSTATUS fetch_account_info(uint32 rid, SAM_ACCOUNT_INFO *delta) sam_account_from_delta(sam_account, delta); DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n", sid_to_string(sid_string, &user_sid), pdb_get_username(sam_account))); - if (!pdb_update_sam_account(sam_account)) { + if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) { DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n", account)); pdb_free_sam(&sam_account); @@ -835,145 +835,6 @@ static NTSTATUS fetch_alias_info(uint32 rid, SAM_ALIAS_INFO *delta, static NTSTATUS fetch_alias_mem(uint32 rid, SAM_ALIAS_MEM_INFO *delta, DOM_SID dom_sid) { -#if 0 /* - * commented out right now after talking to Volker. Can't - * do much with the membership but seemed a shame to waste - * somewhat working code. Needs testing because the membership - * that shows up surprises me. Also can't do much with groups - * in groups (e.g. Domain Admins being a member of Adminsitrators). - * --jerry - */ - - int i; - TALLOC_CTX *t = NULL; - char **nt_members = NULL; - char **unix_members; - DOM_SID group_sid; - GROUP_MAP map; - struct group *grp; - enum SID_NAME_USE sid_type; - - if (delta->num_members == 0) { - return NT_STATUS_OK; - } - - sid_copy(&group_sid, &dom_sid); - sid_append_rid(&group_sid, rid); - - if (sid_equal(&dom_sid, &global_sid_Builtin)) { - sid_type = SID_NAME_WKN_GRP; - if (!get_builtin_group_from_sid(&group_sid, &map, False)) { - DEBUG(0, ("Could not find builtin group %s\n", sid_string_static(&group_sid))); - return NT_STATUS_NO_SUCH_GROUP; - } - } else { - sid_type = SID_NAME_ALIAS; - if (!get_local_group_from_sid(&group_sid, &map, False)) { - DEBUG(0, ("Could not find local group %s\n", sid_string_static(&group_sid))); - return NT_STATUS_NO_SUCH_GROUP; - } - } - - if (!(grp = getgrgid(map.gid))) { - DEBUG(0, ("Could not find unix group %d\n", map.gid)); - return NT_STATUS_NO_SUCH_GROUP; - } - - d_printf("Group members of %s: ", grp->gr_name); - - if (!(t = talloc_init("fetch_group_mem_info"))) { - DEBUG(0, ("could not talloc_init\n")); - return NT_STATUS_NO_MEMORY; - } - - nt_members = TALLOC_ZERO_ARRAY(t, char *, delta->num_members); - - for (i=0; inum_members; i++) { - NTSTATUS nt_status; - SAM_ACCOUNT *member = NULL; - DOM_SID member_sid; - - if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_talloc(t, &member))) { - talloc_destroy(t); - return nt_status; - } - - sid_copy(&member_sid, &delta->sids[i].sid); - - if (!pdb_getsampwsid(member, &member_sid)) { - DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n", - sid_string_static(&member_sid), grp->gr_name)); - pdb_free_sam(&member); - continue; - } - - if (pdb_get_group_rid(member) == rid) { - d_printf("%s(primary),", pdb_get_username(member)); - pdb_free_sam(&member); - continue; - } - - d_printf("%s,", pdb_get_username(member)); - nt_members[i] = talloc_strdup(t, pdb_get_username(member)); - pdb_free_sam(&member); - } - - d_printf("\n"); - - unix_members = grp->gr_mem; - - while (*unix_members) { - BOOL is_nt_member = False; - for (i=0; inum_members; i++) { - if (nt_members[i] == NULL) { - /* This was a primary group */ - continue; - } - - if (strcmp(*unix_members, nt_members[i]) == 0) { - is_nt_member = True; - break; - } - } - if (!is_nt_member) { - /* We look at a unix group member that is not - an nt group member. So, remove it. NT is - boss here. */ - smb_delete_user_group(grp->gr_name, *unix_members); - } - unix_members += 1; - } - - for (i=0; inum_members; i++) { - BOOL is_unix_member = False; - - if (nt_members[i] == NULL) { - /* This was the primary group */ - continue; - } - - unix_members = grp->gr_mem; - - while (*unix_members) { - if (strcmp(*unix_members, nt_members[i]) == 0) { - is_unix_member = True; - break; - } - unix_members += 1; - } - - if (!is_unix_member) { - /* We look at a nt group member that is not a - unix group member currently. So, add the nt - group member. */ - smb_add_user_group(grp->gr_name, nt_members[i]); - } - } - - talloc_destroy(t); - -#endif /* end of fetch_alias_mem() */ - return NT_STATUS_OK; } diff --git a/source3/utils/net_rpc_shell.c b/source3/utils/net_rpc_shell.c new file mode 100644 index 00000000000..f9675e430bc --- /dev/null +++ b/source3/utils/net_rpc_shell.c @@ -0,0 +1,270 @@ +/* + * Unix SMB/CIFS implementation. + * Shell around net rpc subcommands + * Copyright (C) Volker Lendecke 2006 + * + * 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" +#include "utils/net.h" + +static struct rpc_sh_cmd sh_cmds[]; + +static NTSTATUS rpc_sh_info(TALLOC_CTX *mem_ctx, struct rpc_sh_ctx *ctx, + struct rpc_pipe_client *pipe_hnd, + int argc, const char **argv) +{ + return rpc_info_internals(ctx->domain_sid, ctx->domain_name, + ctx->cli, pipe_hnd, mem_ctx, + argc, argv); +} + +static struct rpc_sh_ctx *this_ctx; + +static char **completion_fn(const char *text, int start, int end) +{ + char **cmds = NULL; + int n_cmds = 0; + struct rpc_sh_cmd *c; + + if (start != 0) { + return NULL; + } + + ADD_TO_ARRAY(NULL, char *, SMB_STRDUP(text), &cmds, &n_cmds); + + for (c = this_ctx->cmds; c->name != NULL; c++) { + BOOL match = (strncmp(text, c->name, strlen(text)) == 0); + + if (match) { + ADD_TO_ARRAY(NULL, char *, SMB_STRDUP(c->name), + &cmds, &n_cmds); + } + } + + if (n_cmds == 2) { + SAFE_FREE(cmds[0]); + cmds[0] = cmds[1]; + n_cmds -= 1; + } + + ADD_TO_ARRAY(NULL, char *, NULL, &cmds, &n_cmds); + return cmds; +} + +static NTSTATUS net_sh_run(struct rpc_sh_ctx *ctx, struct rpc_sh_cmd *cmd, + int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx; + struct rpc_pipe_client *pipe_hnd; + NTSTATUS status; + + mem_ctx = talloc_new(ctx); + if (mem_ctx == NULL) { + d_fprintf(stderr, "talloc_new failed\n"); + return NT_STATUS_NO_MEMORY; + } + + pipe_hnd = cli_rpc_pipe_open_noauth(ctx->cli, cmd->pipe_idx, &status); + if (pipe_hnd == NULL) { + d_fprintf(stderr, "Could not open pipe: %s\n", + nt_errstr(status)); + return status; + } + + status = cmd->fn(mem_ctx, ctx, pipe_hnd, argc, argv); + + cli_rpc_pipe_close(pipe_hnd); + + talloc_destroy(mem_ctx); + + return status; +} + +static BOOL net_sh_process(struct rpc_sh_ctx *ctx, + int argc, const char **argv) +{ + struct rpc_sh_cmd *c; + struct rpc_sh_ctx *new_ctx; + NTSTATUS status; + + if (argc == 0) { + return True; + } + + if (ctx == this_ctx) { + + /* We've been called from the cmd line */ + if (strequal(argv[0], "..") && + (this_ctx->parent != NULL)) { + new_ctx = this_ctx->parent; + talloc_free(this_ctx); + this_ctx = new_ctx; + return True; + } + } + + if (strequal(argv[0], "help") || strequal(argv[0], "?")) { + for (c = ctx->cmds; c->name != NULL; c++) { + if (ctx != this_ctx) { + d_printf("%s ", ctx->whoami); + } + d_printf("%-15s %s\n", c->name, c->help); + } + return True; + } + + for (c = ctx->cmds; c->name != NULL; c++) { + if (strequal(c->name, argv[0])) { + break; + } + } + + if (c->name == NULL) { + /* None found */ + d_fprintf(stderr, "%s: unknown cmd\n", argv[0]); + return True; + } + + new_ctx = TALLOC_P(ctx, struct rpc_sh_ctx); + if (new_ctx == NULL) { + d_fprintf(stderr, "talloc failed\n"); + return False; + } + new_ctx->cli = ctx->cli; + new_ctx->whoami = talloc_asprintf(new_ctx, "%s %s", + ctx->whoami, c->name); + new_ctx->thiscmd = talloc_strdup(new_ctx, c->name); + + if (c->sub != NULL) { + new_ctx->cmds = c->sub(new_ctx, ctx); + } else { + new_ctx->cmds = NULL; + } + + new_ctx->parent = ctx; + new_ctx->domain_name = ctx->domain_name; + new_ctx->domain_sid = ctx->domain_sid; + + argc -= 1; + argv += 1; + + if (c->sub != NULL) { + if (argc == 0) { + this_ctx = new_ctx; + return True; + } + return net_sh_process(new_ctx, argc, argv); + } + + status = net_sh_run(new_ctx, c, argc, argv); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "%s failed: %s\n", new_ctx->whoami, + nt_errstr(status)); + } + + return True; +} + +int net_rpc_shell(int argc, const char **argv) +{ + NTSTATUS status; + struct rpc_sh_ctx *ctx; + + if (argc != 0) { + d_fprintf(stderr, "usage: net rpc shell\n"); + return -1; + } + + ctx = TALLOC_P(NULL, struct rpc_sh_ctx); + if (ctx == NULL) { + d_fprintf(stderr, "talloc failed\n"); + return -1; + } + + ctx->cli = net_make_ipc_connection(0); + if (ctx->cli == NULL) { + d_fprintf(stderr, "Could not open connection\n"); + return -1; + } + + ctx->cmds = sh_cmds; + ctx->whoami = "net rpc"; + ctx->parent = NULL; + + status = net_get_remote_domain_sid(ctx->cli, ctx, &ctx->domain_sid, + &ctx->domain_name); + if (!NT_STATUS_IS_OK(status)) { + return -1; + } + + d_printf("Talking to domain %s (%s)\n", ctx->domain_name, + sid_string_static(ctx->domain_sid)); + + this_ctx = ctx; + + while(1) { + char *prompt; + char *line; + int ret; + + asprintf(&prompt, "%s> ", this_ctx->whoami); + + line = smb_readline(prompt, NULL, completion_fn); + SAFE_FREE(prompt); + + if (line == NULL) { + break; + } + + ret = poptParseArgvString(line, &argc, &argv); + if (ret != 0) { + d_fprintf(stderr, "cmdline invalid: %s\n", + poptStrerror(ret)); + return False; + } + + if ((line[0] != '\n') && + (!net_sh_process(this_ctx, argc, argv))) { + break; + } + } + + cli_shutdown(ctx->cli); + + talloc_free(ctx); + + return 0; +} + +static struct rpc_sh_cmd sh_cmds[] = { + + { "info", NULL, PI_SAMR, rpc_sh_info, + "Print information about the domain connected to" }, + + { "rights", net_rpc_rights_cmds, 0, NULL, + "List/Grant/Revoke user rights" }, + + { "share", net_rpc_share_cmds, 0, NULL, + "List/Add/Remove etc shares" }, + + { "user", net_rpc_user_cmds, 0, NULL, + "List/Add/Remove user info" }, + + { NULL, NULL, 0, NULL, NULL } +}; diff --git a/source3/utils/net_sam.c b/source3/utils/net_sam.c new file mode 100644 index 00000000000..ba3ec5c57f6 --- /dev/null +++ b/source3/utils/net_sam.c @@ -0,0 +1,784 @@ +/* + * Unix SMB/CIFS implementation. + * Local SAM access routines + * Copyright (C) Volker Lendecke 2006 + * + * 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" +#include "utils/net.h" + +/* + * Set a user's data + */ + +static int net_sam_userset(int argc, const char **argv, const char *field, + BOOL (*fn)(SAM_ACCOUNT *, const char *, + enum pdb_value_state)) +{ + SAM_ACCOUNT *sam_acct = NULL; + DOM_SID sid; + enum SID_NAME_USE type; + const char *dom, *name; + NTSTATUS status; + + if (argc != 2) { + d_fprintf(stderr, "usage: net sam set %s \n", + field); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &dom, &name, &sid, &type)) { + d_fprintf(stderr, "Could not find name %s\n", argv[0]); + return -1; + } + + if (type != SID_NAME_USER) { + d_fprintf(stderr, "%s is a %s, not a user\n", argv[0], + sid_type_lookup(type)); + return -1; + } + + if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_acct))) { + d_fprintf(stderr, "Internal error\n"); + return -1; + } + + if (!pdb_getsampwsid(sam_acct, &sid)) { + d_fprintf(stderr, "Loading user %s failed\n", argv[0]); + return -1; + } + + if (!fn(sam_acct, argv[1], PDB_CHANGED)) { + d_fprintf(stderr, "Internal error\n"); + return -1; + } + + status = pdb_update_sam_account(sam_acct); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Updating sam account %s failed with %s\n", + argv[0], nt_errstr(status)); + return -1; + } + + pdb_free_sam(&sam_acct); + + d_printf("Updated %s for %s\\%s to %s\n", field, dom, name, argv[1]); + return 0; +} + +static int net_sam_set_fullname(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "fullname", + pdb_set_fullname); +} + +static int net_sam_set_logonscript(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "logonscript", + pdb_set_logon_script); +} + +static int net_sam_set_profilepath(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "profilepath", + pdb_set_profile_path); +} + +static int net_sam_set_homedrive(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "homedrive", + pdb_set_dir_drive); +} + +static int net_sam_set_homedir(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "homedir", + pdb_set_homedir); +} + +static int net_sam_set_workstations(int argc, const char **argv) +{ + return net_sam_userset(argc, argv, "workstations", + pdb_set_workstations); +} + +/* + * Set account flags + */ + +static int net_sam_set_userflag(int argc, const char **argv, const char *field, + uint16 flag) +{ + SAM_ACCOUNT *sam_acct = NULL; + DOM_SID sid; + enum SID_NAME_USE type; + const char *dom, *name; + NTSTATUS status; + uint16 acct_flags; + + if ((argc != 2) || (!strequal(argv[1], "yes") && + !strequal(argv[1], "no"))) { + d_fprintf(stderr, "usage: net sam set %s [yes|no]\n", + field); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &dom, &name, &sid, &type)) { + d_fprintf(stderr, "Could not find name %s\n", argv[0]); + return -1; + } + + if (type != SID_NAME_USER) { + d_fprintf(stderr, "%s is a %s, not a user\n", argv[0], + sid_type_lookup(type)); + return -1; + } + + if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_acct))) { + d_fprintf(stderr, "Internal error\n"); + return -1; + } + + if (!pdb_getsampwsid(sam_acct, &sid)) { + d_fprintf(stderr, "Loading user %s failed\n", argv[0]); + return -1; + } + + acct_flags = pdb_get_acct_ctrl(sam_acct); + + if (strequal(argv[1], "yes")) { + acct_flags |= flag; + } else { + acct_flags &= ~flag; + } + + pdb_set_acct_ctrl(sam_acct, acct_flags, PDB_CHANGED); + + status = pdb_update_sam_account(sam_acct); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Updating sam account %s failed with %s\n", + argv[0], nt_errstr(status)); + return -1; + } + + pdb_free_sam(&sam_acct); + + d_fprintf(stderr, "Updated flag %s for %s\\%s to %s\n", field, dom, + name, argv[1]); + return 0; +} + +static int net_sam_set_disabled(int argc, const char **argv) +{ + return net_sam_set_userflag(argc, argv, "disabled", ACB_DISABLED); +} + +static int net_sam_set_pwnotreq(int argc, const char **argv) +{ + return net_sam_set_userflag(argc, argv, "pwnotreq", ACB_PWNOTREQ); +} + +static int net_sam_set_autolock(int argc, const char **argv) +{ + return net_sam_set_userflag(argc, argv, "autolock", ACB_AUTOLOCK); +} + +static int net_sam_set_pwnoexp(int argc, const char **argv) +{ + return net_sam_set_userflag(argc, argv, "pwnoexp", ACB_PWNOEXP); +} + +/* + * Set a user's time field + */ + +static int net_sam_set_time(int argc, const char **argv, const char *field, + BOOL (*fn)(SAM_ACCOUNT *, time_t, + enum pdb_value_state)) +{ + SAM_ACCOUNT *sam_acct = NULL; + DOM_SID sid; + enum SID_NAME_USE type; + const char *dom, *name; + NTSTATUS status; + time_t new_time; + + if (argc != 2) { + d_fprintf(stderr, "usage: net sam set %s " + "[now|YYYY-MM-DD HH:MM]\n", field); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &dom, &name, &sid, &type)) { + d_fprintf(stderr, "Could not find name %s\n", argv[0]); + return -1; + } + + if (type != SID_NAME_USER) { + d_fprintf(stderr, "%s is a %s, not a user\n", argv[0], + sid_type_lookup(type)); + return -1; + } + + if (strequal(argv[1], "now")) { + new_time = time(NULL); + } else { + struct tm tm; + char *end; + ZERO_STRUCT(tm); + end = strptime(argv[1], "%Y-%m-%d %H:%M", &tm); + new_time = mktime(&tm); + if ((end == NULL) || (*end != '\0') || (new_time == -1)) { + d_fprintf(stderr, "Could not parse time string %s\n", + argv[1]); + return -1; + } + } + + + if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_acct))) { + d_fprintf(stderr, "Internal error\n"); + return -1; + } + + if (!pdb_getsampwsid(sam_acct, &sid)) { + d_fprintf(stderr, "Loading user %s failed\n", argv[0]); + return -1; + } + + if (!fn(sam_acct, new_time, PDB_CHANGED)) { + d_fprintf(stderr, "Internal error\n"); + return -1; + } + + status = pdb_update_sam_account(sam_acct); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Updating sam account %s failed with %s\n", + argv[0], nt_errstr(status)); + return -1; + } + + pdb_free_sam(&sam_acct); + + d_printf("Updated %s for %s\\%s to %s\n", field, dom, name, argv[1]); + return 0; +} + +static int net_sam_set_pwdmustchange(int argc, const char **argv) +{ + return net_sam_set_time(argc, argv, "pwdmustchange", + pdb_set_pass_must_change_time); +} + +static int net_sam_set_pwdcanchange(int argc, const char **argv) +{ + return net_sam_set_time(argc, argv, "pwdcanchange", + pdb_set_pass_can_change_time); +} + +/* + * Set a user's or a group's comment + */ + +static int net_sam_set_comment(int argc, const char **argv) +{ + GROUP_MAP map; + DOM_SID sid; + enum SID_NAME_USE type; + const char *dom, *name; + NTSTATUS status; + + if (argc != 2) { + d_fprintf(stderr, "usage: net sam set comment " + "\n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &dom, &name, &sid, &type)) { + d_fprintf(stderr, "Could not find name %s\n", argv[0]); + return -1; + } + + if (type == SID_NAME_USER) { + return net_sam_userset(argc, argv, "comment", + pdb_set_acct_desc); + } + + if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) && + (type != SID_NAME_WKN_GRP)) { + d_fprintf(stderr, "%s is a %s, not a group\n", argv[0], + sid_type_lookup(type)); + return -1; + } + + if (!pdb_getgrsid(&map, sid)) { + d_fprintf(stderr, "Could not load group %s\n", argv[0]); + return -1; + } + + fstrcpy(map.comment, argv[1]); + + status = pdb_update_group_mapping_entry(&map); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Updating group mapping entry failed with " + "%s\n", nt_errstr(status)); + return -1; + } + + d_printf("Updated comment of group %s\\%s to %s\n", dom, name, + argv[1]); + + return 0; +} + +static int net_sam_set(int argc, const char **argv) +{ + struct functable2 func[] = { + { "homedir", net_sam_set_homedir, + "Change a user's home directory" }, + { "profilepath", net_sam_set_profilepath, + "Change a user's profile path" }, + { "comment", net_sam_set_comment, + "Change a users or groups description" }, + { "fullname", net_sam_set_fullname, + "Change a user's full name" }, + { "logonscript", net_sam_set_logonscript, + "Change a user's logon script" }, + { "homedrive", net_sam_set_homedrive, + "Change a user's home drive" }, + { "workstations", net_sam_set_workstations, + "Change a user's allowed workstations" }, + { "disabled", net_sam_set_disabled, + "Disable/Enable a user" }, + { "pwnotreq", net_sam_set_pwnotreq, + "Disable/Enable the password not required flag" }, + { "autolock", net_sam_set_autolock, + "Disable/Enable a user's lockout flag" }, + { "pwnoexp", net_sam_set_pwnoexp, + "Disable/Enable whether a user's pw does not expire" }, + { "pwdmustchange", net_sam_set_pwdmustchange, + "Set a users password must change time" }, + { "pwdcanchange", net_sam_set_pwdcanchange, + "Set a users password can change time" }, + {NULL, NULL} + }; + + return net_run_function2(argc, argv, "net sam set", func); +} + +/* + * Map a unix group to a domain group + */ + +static int net_sam_mapunixgroup(int argc, const char **argv) +{ + NTSTATUS status; + GROUP_MAP map; + struct group *grp; + + if (argc != 1) { + d_fprintf(stderr, "usage: net sam mapunixgroup \n"); + return -1; + } + + grp = getgrnam(argv[0]); + if (grp == NULL) { + d_fprintf(stderr, "Could not find group %s\n", argv[0]); + return -1; + } + + status = map_unix_group(grp, &map); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Mapping group %s failed with %s\n", + argv[0], nt_errstr(status)); + return -1; + } + + d_printf("Mapped unix group %s to SID %s\n", argv[0], + sid_string_static(&map.sid)); + + return 0; +} + +/* + * Create a local group + */ + +static int net_sam_createlocalgroup(int argc, const char **argv) +{ + NTSTATUS status; + uint32 rid; + + if (argc != 1) { + d_fprintf(stderr, "usage: net sam createlocalgroup \n"); + return -1; + } + + if (!winbind_ping()) { + d_fprintf(stderr, "winbind seems not to run. createlocalgroup " + "only works when winbind runs.\n"); + return -1; + } + + status = pdb_create_alias(argv[0], &rid); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Creating %s failed with %s\n", + argv[0], nt_errstr(status)); + return -1; + } + + d_printf("Created local group %s with RID %d\n", argv[0], rid); + + return 0; +} + +/* + * Add a group member + */ + +static int net_sam_addmem(int argc, const char **argv) +{ + const char *groupdomain, *groupname, *memberdomain, *membername; + DOM_SID group, member; + enum SID_NAME_USE grouptype, membertype; + NTSTATUS status; + + if (argc != 2) { + d_fprintf(stderr, "usage: net sam addmem \n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &groupdomain, &groupname, &group, &grouptype)) { + d_fprintf(stderr, "Could not find group %s\n", argv[0]); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[1], LOOKUP_NAME_ISOLATED, + &memberdomain, &membername, &member, &membertype)) { + d_fprintf(stderr, "Could not find member %s\n", argv[1]); + return -1; + } + + if ((grouptype == SID_NAME_ALIAS) || (grouptype == SID_NAME_WKN_GRP)) { + if ((membertype != SID_NAME_USER) && + (membertype != SID_NAME_DOM_GRP)) { + d_fprintf(stderr, "%s is a local group, only users " + "and domain groups can be added.\n" + "%s is a %s\n", argv[0], argv[1], + sid_type_lookup(membertype)); + return -1; + } + status = pdb_add_aliasmem(&group, &member); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Adding local group member failed " + "with %s\n", nt_errstr(status)); + return -1; + } + } else { + d_fprintf(stderr, "Can only add members to local groups so " + "far, %s is a %s\n", argv[0], + sid_type_lookup(grouptype)); + return -1; + } + + d_printf("Added %s\\%s to %s\\%s\n", + memberdomain, membername, groupdomain, groupname); + + return 0; +} + +/* + * Delete a group member + */ + +static int net_sam_delmem(int argc, const char **argv) +{ + const char *groupdomain, *groupname; + const char *memberdomain = NULL; + const char *membername = NULL; + DOM_SID group, member; + enum SID_NAME_USE grouptype; + NTSTATUS status; + + if (argc != 2) { + d_fprintf(stderr, "usage: net sam delmem \n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &groupdomain, &groupname, &group, &grouptype)) { + d_fprintf(stderr, "Could not find group %s\n", argv[0]); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[1], LOOKUP_NAME_ISOLATED, + &memberdomain, &membername, &member, NULL)) { + if (!string_to_sid(&member, argv[1])) { + d_fprintf(stderr, "Could not find member %s\n", + argv[1]); + return -1; + } + } + + if ((grouptype == SID_NAME_ALIAS) || + (grouptype == SID_NAME_WKN_GRP)) { + status = pdb_del_aliasmem(&group, &member); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Deleting local group member failed " + "with %s\n", nt_errstr(status)); + return -1; + } + } else { + d_fprintf(stderr, "Can only delete members from local groups " + "so far, %s is a %s\n", argv[0], + sid_type_lookup(grouptype)); + return -1; + } + + if (membername != NULL) { + d_printf("Deleted %s\\%s from %s\\%s\n", + memberdomain, membername, groupdomain, groupname); + } else { + d_printf("Deleted %s from %s\\%s\n", + sid_string_static(&member), groupdomain, groupname); + } + + return 0; +} + +/* + * List group members + */ + +static int net_sam_listmem(int argc, const char **argv) +{ + const char *groupdomain, *groupname; + DOM_SID group; + enum SID_NAME_USE grouptype; + NTSTATUS status; + + if (argc != 1) { + d_fprintf(stderr, "usage: net sam listmem \n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &groupdomain, &groupname, &group, &grouptype)) { + d_fprintf(stderr, "Could not find group %s\n", argv[0]); + return -1; + } + + if ((grouptype == SID_NAME_ALIAS) || + (grouptype == SID_NAME_WKN_GRP)) { + DOM_SID *members = NULL; + size_t i, num_members = 0; + + status = pdb_enum_aliasmem(&group, &members, &num_members); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "Listing group members failed with " + "%s\n", nt_errstr(status)); + return -1; + } + + d_printf("%s\\%s has %d members\n", groupdomain, groupname, + num_members); + for (i=0; i 1) || + ((argc == 1) && !strequal(argv[0], "verbose"))) { + d_fprintf(stderr, "usage: net sam list %s [verbose]\n", what); + return -1; + } + + if (search == NULL) { + d_fprintf(stderr, "Could not start search\n"); + return -1; + } + + while (True) { + struct samr_displayentry entry; + if (!search->next_entry(search, &entry)) { + break; + } + if (verbose) { + d_printf("%s:%d:%s\n", + entry.account_name, + entry.rid, + entry.description); + } else { + d_printf("%s\n", entry.account_name); + } + } + + search->search_end(search); + return 0; +} + +static int net_sam_list_users(int argc, const char **argv) +{ + return net_sam_do_list(argc, argv, pdb_search_users(ACB_NORMAL), + "users"); +} + +static int net_sam_list_groups(int argc, const char **argv) +{ + return net_sam_do_list(argc, argv, pdb_search_groups(), "groups"); +} + +static int net_sam_list_localgroups(int argc, const char **argv) +{ + return net_sam_do_list(argc, argv, + pdb_search_aliases(get_global_sam_sid()), + "localgroups"); +} + +static int net_sam_list_builtin(int argc, const char **argv) +{ + return net_sam_do_list(argc, argv, + pdb_search_aliases(&global_sid_Builtin), + "builtin"); +} + +static int net_sam_list_workstations(int argc, const char **argv) +{ + return net_sam_do_list(argc, argv, + pdb_search_users(ACB_WSTRUST), + "workstations"); +} + +/* + * List stuff + */ + +static int net_sam_list(int argc, const char **argv) +{ + struct functable2 func[] = { + { "users", net_sam_list_users, + "List SAM users" }, + { "groups", net_sam_list_groups, + "List SAM groups" }, + { "localgroups", net_sam_list_localgroups, + "List SAM local groups" }, + { "builtin", net_sam_list_builtin, + "List builtin groups" }, + { "workstations", net_sam_list_workstations, + "List domain member workstations" }, + {NULL, NULL} + }; + + return net_run_function2(argc, argv, "net sam list", func); +} + +/* + * Show details of SAM entries + */ + +static int net_sam_show(int argc, const char **argv) +{ + DOM_SID sid; + enum SID_NAME_USE type; + const char *dom, *name; + + if (argc != 1) { + d_fprintf(stderr, "usage: net sam show \n"); + return -1; + } + + if (!lookup_name(tmp_talloc_ctx(), argv[0], LOOKUP_NAME_ISOLATED, + &dom, &name, &sid, &type)) { + d_fprintf(stderr, "Could not find name %s\n", argv[0]); + return -1; + } + + d_printf("%s\\%s is a %s with SID %s\n", dom, name, + sid_type_lookup(type), sid_string_static(&sid)); + + return 0; +} + +/*********************************************************** + migrated functionality from smbgroupedit + **********************************************************/ +int net_sam(int argc, const char **argv) +{ + struct functable2 func[] = { + { "createlocalgroup", net_sam_createlocalgroup, + "Create a new local group" }, + { "mapunixgroup", net_sam_mapunixgroup, + "Map a unix group to a domain group" }, + { "addmem", net_sam_addmem, + "Add a member to a group" }, + { "delmem", net_sam_delmem, + "Delete a member from a group" }, + { "listmem", net_sam_listmem, + "List group members" }, + { "list", net_sam_list, + "List users, groups and local groups" }, + { "show", net_sam_show, + "Show details of a SAM entry" }, + { "set", net_sam_set, + "Set details of a SAM account" }, + { NULL, NULL, NULL } + }; + + /* we shouldn't have silly checks like this */ + if (getuid() != 0) { + d_fprintf(stderr, "You must be root to edit the SAM " + "directly.\n"); + return -1; + } + + return net_run_function2(argc, argv, "net sam", func); +} + diff --git a/source3/utils/net_usershare.c b/source3/utils/net_usershare.c new file mode 100644 index 00000000000..c00f239b99a --- /dev/null +++ b/source3/utils/net_usershare.c @@ -0,0 +1,829 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + + Copyright (C) Jeremy Allison (jra@samba.org) 2005 + + 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" +#include "utils/net.h" + +struct { + const char *us_errstr; + enum usershare_err us_err; +} us_errs [] = { + {"",USERSHARE_OK}, + {"Malformed usershare file", USERSHARE_MALFORMED_FILE}, + {"Bad version number", USERSHARE_BAD_VERSION}, + {"Malformed path entry", USERSHARE_MALFORMED_PATH}, + {"Malformed comment entryfile", USERSHARE_MALFORMED_COMMENT_DEF}, + {"Malformed acl definition", USERSHARE_MALFORMED_ACL_DEF}, + {"Acl parse error", USERSHARE_ACL_ERR}, + {"Path not absolute", USERSHARE_PATH_NOT_ABSOLUTE}, + {"Path is denied", USERSHARE_PATH_IS_DENIED}, + {"Path not allowed", USERSHARE_PATH_NOT_ALLOWED}, + {"Path is not a directory", USERSHARE_PATH_NOT_DIRECTORY}, + {"System error", USERSHARE_POSIX_ERR}, + {NULL,(enum usershare_err)-1} +}; + +static const char *get_us_error_code(enum usershare_err us_err) +{ + static pstring out; + int idx = 0; + + while (us_errs[idx].us_errstr != NULL) { + if (us_errs[idx].us_err == us_err) { + return us_errs[idx].us_errstr; + } + idx++; + } + + slprintf(out, sizeof(out), "Usershare error code (0x%x)", (unsigned int)us_err); + return out; +} + +/* The help subsystem for the USERSHARE subcommand */ + +static int net_usershare_add_usage(int argc, const char **argv) +{ + char c = *lp_winbind_separator(); + d_printf( + "net usershare add [-l|--long] [] []\n" + "\tAdds the specified share name for this user.\n" + "\t is the new share name.\n" + "\t is the path on the filesystem to export.\n" + "\t is the optional comment for the new share.\n" + "\t is an optional share acl in the format \"DOMAIN%cname:X,DOMAIN%cname:X,....\"\n" + "\t\t\"X\" represents a permission and can be any one of the characters f, r or d\n" + "\t\twhere \"f\" means full control, \"r\" means read-only, \"d\" means deny access.\n" + "\t\tname may be a domain user or group. For local users use the local server name " + "instead of \"DOMAIN\"\n" + "\t\tThe default acl is \"Everyone:r\" which allows everyone read-only access.\n" + "\tAdd -l or --long to print the info on the newly added share.\n", + c, c ); + return -1; +} + +static int net_usershare_delete_usage(int argc, const char **argv) +{ + d_printf( + "net usershare delete \n"\ + "\tdeletes the specified share name for this user.\n"); + return -1; +} + +static int net_usershare_info_usage(int argc, const char **argv) +{ + d_printf( + "net usershare info [-l|--long] [wildcard sharename]\n"\ + "\tPrints out the path, comment and acl elements of shares that match the wildcard.\n" + "\tBy default only gives info on shares owned by the current user\n" + "\tAdd -l or --long to apply this to all shares\n" + "\tOmit the sharename or use a wildcard of '*' to see all shares\n"); + return -1; +} + +static int net_usershare_list_usage(int argc, const char **argv) +{ + d_printf( + "net usershare list [-l|--long] [wildcard sharename]\n"\ + "\tLists the names of all shares that match the wildcard.\n" + "\tBy default only lists shares owned by the current user\n" + "\tAdd -l or --long to apply this to all shares\n" + "\tOmit the sharename or use a wildcard of '*' to see all shares\n"); + return -1; +} + +int net_usershare_usage(int argc, const char **argv) +{ + d_printf("net usershare add [] [] to add or change a user defined share.\n" + "net usershare delete to delete a user defined share.\n" + "net usershare info [-l|--long] [wildcard sharename] to print info about a user defined share.\n" + "net usershare list [-l|--long] [wildcard sharename] to list user defined shares.\n" + "net usershare help\n"\ + "\nType \"net usershare help