diff options
author | Gerald Carter <jerry@samba.org> | 2006-02-03 22:19:41 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:06:23 -0500 |
commit | 0af1500fc0bafe61019f1b2ab1d9e1d369221240 (patch) | |
tree | 653fc2533795458d5f9696402285d9f14e527a21 /source3/utils | |
parent | 21a30a1346c9f9a25659a0cea0d276d8c2e6ddca (diff) | |
download | samba-0af1500fc0bafe61019f1b2ab1d9e1d369221240.tar.gz |
r13316: Let the carnage begin....
Sync with trunk as off r13315
(This used to be commit 17e63ac4ed8325c0d44fe62b2442449f3298559f)
Diffstat (limited to 'source3/utils')
-rw-r--r-- | source3/utils/net.c | 27 | ||||
-rw-r--r-- | source3/utils/net.h | 23 | ||||
-rw-r--r-- | source3/utils/net_ads_gpo.c | 436 | ||||
-rw-r--r-- | source3/utils/net_groupmap.c | 38 | ||||
-rw-r--r-- | source3/utils/net_help.c | 9 | ||||
-rw-r--r-- | source3/utils/net_lookup.c | 52 | ||||
-rw-r--r-- | source3/utils/net_rpc.c | 557 | ||||
-rw-r--r-- | source3/utils/net_rpc_rights.c | 55 | ||||
-rw-r--r-- | source3/utils/net_rpc_samsync.c | 141 | ||||
-rw-r--r-- | source3/utils/net_rpc_shell.c | 270 | ||||
-rw-r--r-- | source3/utils/net_sam.c | 784 | ||||
-rw-r--r-- | source3/utils/net_usershare.c | 829 | ||||
-rw-r--r-- | source3/utils/net_util.c | 89 | ||||
-rw-r--r-- | source3/utils/netlookup.c | 209 | ||||
-rw-r--r-- | source3/utils/ntlm_auth.c | 6 | ||||
-rw-r--r-- | source3/utils/pdbedit.c | 10 | ||||
-rw-r--r-- | source3/utils/smbcacls.c | 2 | ||||
-rw-r--r-- | source3/utils/smbcontrol.c | 114 | ||||
-rw-r--r-- | source3/utils/smbcquotas.c | 2 | ||||
-rw-r--r-- | source3/utils/smbpasswd.c | 24 |
20 files changed, 3453 insertions, 224 deletions
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 <COMMAND>\n"\ +"<COMMAND> 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 <command>\tto run ADS commands\n"\ " net rap <command>\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 <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 <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 <username>\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 <username>\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 <username> [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 <username> [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 <share> <path> [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 <share>\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 <share>\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; i<delta->num_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; i<delta->num_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; i<delta->num_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 <user> <value>\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 <user> [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 <user> " + "[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 <name> " + "<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 <name>\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 <name>\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 <group> <member>\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 <group> <member>\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 <group>\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<num_members; i++) { + const char *dom, *name; + if (lookup_sid(tmp_talloc_ctx(), &members[i], + &dom, &name, NULL)) { + d_printf(" %s\\%s\n", dom, name); + } else { + d_printf(" %s\n", + sid_string_static(&members[i])); + } + } + } else { + d_fprintf(stderr, "Can only list local group members so far.\n" + "%s is a %s\n", argv[0], sid_type_lookup(grouptype)); + return -1; + } + + return 0; +} + +/* + * Do the listing + */ +static int net_sam_do_list(int argc, const char **argv, + struct pdb_search *search, const char *what) +{ + BOOL verbose = (argc == 1); + + if ((argc > 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 <name>\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] <sharename> <path> [<comment>] [<acl>]\n" + "\tAdds the specified share name for this user.\n" + "\t<sharename> is the new share name.\n" + "\t<path> is the path on the filesystem to export.\n" + "\t<comment> is the optional comment for the new share.\n" + "\t<acl> 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 <sharename>\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 <sharename> <path> [<comment>] [<acl>] to add or change a user defined share.\n" + "net usershare delete <sharename> 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 <option>\" to get more information on that option\n\n"); + + net_common_flags_usage(argc, argv); + return -1; +} + +/*************************************************************************** +***************************************************************************/ + +static void get_basepath(pstring basepath) +{ + pstrcpy(basepath, lp_usershare_path()); + if (basepath[strlen(basepath)-1] == '/') { + basepath[strlen(basepath)-1] = '\0'; + } +} + +/*************************************************************************** + Delete a single userlevel share. +***************************************************************************/ + +static int net_usershare_delete(int argc, const char **argv) +{ + pstring us_path; + char *sharename; + + if (argc != 1) { + return net_usershare_delete_usage(argc, argv); + } + + sharename = strdup_lower(argv[0]); + + if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) { + d_fprintf(stderr, "net usershare delete: share name %s contains " + "invalid characters (any of %s)\n", + sharename, INVALID_SHARENAME_CHARS); + SAFE_FREE(sharename); + return -1; + } + + pstrcpy(us_path, lp_usershare_path()); + pstrcat(us_path, "/"); + pstrcat(us_path, sharename); + + if (unlink(us_path) != 0) { + d_fprintf(stderr, "net usershare delete: unable to remove usershare %s. " + "Error was %s\n", + us_path, strerror(errno)); + SAFE_FREE(sharename); + return -1; + } + SAFE_FREE(sharename); + return 0; +} + +/*************************************************************************** + Data structures to handle a list of usershare files. +***************************************************************************/ + +struct file_list { + struct file_list *next, *prev; + const char *pathname; +}; + +static struct file_list *flist; + +/*************************************************************************** +***************************************************************************/ + +static int get_share_list(TALLOC_CTX *ctx, const char *wcard, BOOL only_ours) +{ + SMB_STRUCT_DIR *dp; + SMB_STRUCT_DIRENT *de; + uid_t myuid = geteuid(); + struct file_list *fl = NULL; + pstring basepath; + + get_basepath(basepath); + dp = sys_opendir(basepath); + if (!dp) { + d_fprintf(stderr, "get_share_list: cannot open usershare directory %s. Error %s\n", + basepath, strerror(errno) ); + return -1; + } + + while((de = sys_readdir(dp)) != 0) { + SMB_STRUCT_STAT sbuf; + pstring path; + const char *n = de->d_name; + + /* Ignore . and .. */ + if (*n == '.') { + if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) { + continue; + } + } + + if (!validate_net_name(n, INVALID_SHARENAME_CHARS, strlen(n))) { + d_fprintf(stderr, "get_share_list: ignoring bad share name %s\n",n); + continue; + } + pstrcpy(path, basepath); + pstrcat(path, "/"); + pstrcat(path, n); + + if (sys_lstat(path, &sbuf) != 0) { + d_fprintf(stderr, "get_share_list: can't lstat file %s. Error was %s\n", + path, strerror(errno) ); + continue; + } + + if (!S_ISREG(sbuf.st_mode)) { + d_fprintf(stderr, "get_share_list: file %s is not a regular file. Ignoring.\n", + path ); + continue; + } + + if (only_ours && sbuf.st_uid != myuid) { + continue; + } + + if (!unix_wild_match(wcard, n)) { + continue; + } + + /* (Finally) - add to list. */ + fl = TALLOC_P(ctx, struct file_list); + if (!fl) { + return -1; + } + fl->pathname = talloc_strdup(ctx, n); + if (!fl->pathname) { + return -1; + } + + DLIST_ADD(flist, fl); + } + + sys_closedir(dp); + return 0; +} + +enum priv_op { US_LIST_OP, US_INFO_OP}; + +struct priv_info { + TALLOC_CTX *ctx; + enum priv_op op; +}; + +/*************************************************************************** + Call a function for every share on the list. +***************************************************************************/ + +static int process_share_list(int (*fn)(struct file_list *, void *), void *private) +{ + struct file_list *fl; + int ret = 0; + + for (fl = flist; fl; fl = fl->next) { + ret = (*fn)(fl, private); + } + + return ret; +} + +/*************************************************************************** + Info function. +***************************************************************************/ + +static int info_fn(struct file_list *fl, void *private) +{ + SMB_STRUCT_STAT sbuf; + char **lines = NULL; + struct priv_info *pi = (struct priv_info *)private; + TALLOC_CTX *ctx = pi->ctx; + int fd = -1; + int numlines = 0; + SEC_DESC *psd = NULL; + pstring basepath; + pstring sharepath; + pstring comment; + pstring acl_str; + int num_aces; + char sep_str[2]; + enum usershare_err us_err; + + sep_str[0] = *lp_winbind_separator(); + sep_str[1] = '\0'; + + get_basepath(basepath); + pstrcat(basepath, "/"); + pstrcat(basepath, fl->pathname); + +#ifdef O_NOFOLLOW + fd = sys_open(basepath, O_RDONLY|O_NOFOLLOW, 0); +#else + fd = sys_open(basepath, O_RDONLY, 0); +#endif + + if (fd == -1) { + d_fprintf(stderr, "info_fn: unable to open %s. %s\n", + basepath, strerror(errno) ); + return -1; + } + + /* Paranoia... */ + if (sys_fstat(fd, &sbuf) != 0) { + d_fprintf(stderr, "info_fn: can't fstat file %s. Error was %s\n", + basepath, strerror(errno) ); + close(fd); + return -1; + } + + if (!S_ISREG(sbuf.st_mode)) { + d_fprintf(stderr, "info_fn: file %s is not a regular file. Ignoring.\n", + basepath ); + close(fd); + return -1; + } + + lines = fd_lines_load(fd, &numlines, 10240); + close(fd); + + if (lines == NULL) { + return -1; + } + + /* Ensure it's well formed. */ + us_err = parse_usershare_file(ctx, &sbuf, fl->pathname, -1, lines, numlines, + sharepath, + comment, + &psd); + + if (us_err != USERSHARE_OK) { + d_fprintf(stderr, "info_fn: file %s is not a well formed usershare file.\n", + basepath ); + d_fprintf(stderr, "info_fn: Error was %s.\n", + get_us_error_code(us_err) ); + return -1; + } + + pstrcpy(acl_str, "usershare_acl="); + + for (num_aces = 0; num_aces < psd->dacl->num_aces; num_aces++) { + char access_str[2]; + const char *domain; + const char *name; + + access_str[1] = '\0'; + + if (net_lookup_name_from_sid(ctx, &psd->dacl->ace[num_aces].trustee, &domain, &name)) { + if (*domain) { + pstrcat(acl_str, domain); + pstrcat(acl_str, sep_str); + } + pstrcat(acl_str,name); + } else { + fstring sidstr; + sid_to_string(sidstr, &psd->dacl->ace[num_aces].trustee); + pstrcat(acl_str,sidstr); + } + pstrcat(acl_str, ":"); + + if (psd->dacl->ace[num_aces].type == SEC_ACE_TYPE_ACCESS_DENIED) { + pstrcat(acl_str, "D,"); + } else { + if (psd->dacl->ace[num_aces].info.mask & GENERIC_ALL_ACCESS) { + pstrcat(acl_str, "F,"); + } else { + pstrcat(acl_str, "R,"); + } + } + } + + acl_str[strlen(acl_str)-1] = '\0'; + + if (pi->op == US_INFO_OP) { + d_printf("[%s]\n", fl->pathname ); + d_printf("path=%s\n", sharepath ); + d_printf("comment=%s\n", comment); + d_printf("%s\n\n", acl_str); + } else if (pi->op == US_LIST_OP) { + d_printf("%s\n", fl->pathname); + } + + return 0; +} + +/*************************************************************************** + Print out info (internal detail) on userlevel shares. +***************************************************************************/ + +static int net_usershare_info(int argc, const char **argv) +{ + fstring wcard; + BOOL only_ours = True; + int ret = -1; + struct priv_info pi; + TALLOC_CTX *ctx; + + fstrcpy(wcard, "*"); + + if (opt_long_list_entries) { + only_ours = False; + } + + switch (argc) { + case 0: + break; + case 1: + fstrcpy(wcard, argv[0]); + break; + default: + return net_usershare_info_usage(argc, argv); + } + + strlower_m(wcard); + + ctx = talloc_init("share_info"); + ret = get_share_list(ctx, wcard, only_ours); + if (ret) { + return ret; + } + + pi.ctx = ctx; + pi.op = US_INFO_OP; + + ret = process_share_list(info_fn, &pi); + talloc_destroy(ctx); + return ret; +} + +/*************************************************************************** + Add a single userlevel share. +***************************************************************************/ + +static int net_usershare_add(int argc, const char **argv) +{ + TALLOC_CTX *ctx = NULL; + SMB_STRUCT_STAT sbuf; + SMB_STRUCT_STAT lsbuf; + char *sharename; + pstring full_path; + pstring full_path_tmp; + const char *us_path; + const char *us_comment; + const char *arg_acl; + char *us_acl; + char *file_img; + int num_aces = 0; + int i; + int tmpfd; + const char *pacl; + size_t to_write; + uid_t myeuid = geteuid(); + + us_comment = ""; + arg_acl = "S-1-1-0:R"; + + switch (argc) { + case 0: + case 1: + default: + return net_usershare_add_usage(argc, argv); + case 2: + sharename = strdup_lower(argv[0]); + us_path = argv[1]; + break; + case 3: + sharename = strdup_lower(argv[0]); + us_path = argv[1]; + us_comment = argv[2]; + break; + case 4: + sharename = strdup_lower(argv[0]); + us_path = argv[1]; + us_comment = argv[2]; + arg_acl = argv[3]; + break; + } + + if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) { + d_fprintf(stderr, "net usershare add: share name %s contains " + "invalid characters (any of %s)\n", + sharename, INVALID_SHARENAME_CHARS); + SAFE_FREE(sharename); + return -1; + } + + /* Disallow shares the same as users. */ + if (getpwnam(sharename)) { + d_fprintf(stderr, "net usershare add: share name %s is already a valid system user name\n", + sharename ); + SAFE_FREE(sharename); + return -1; + } + + /* Construct the full path for the usershare file. */ + get_basepath(full_path); + pstrcat(full_path, "/"); + pstrcpy(full_path_tmp, full_path); + pstrcat(full_path, sharename); + pstrcat(full_path_tmp, ":tmpXXXXXX"); + + /* The path *must* be absolute. */ + if (us_path[0] != '/') { + d_fprintf(stderr,"net usershare add: path %s is not an absolute path.\n", + us_path); + SAFE_FREE(sharename); + return -1; + } + + /* Check the directory to be shared exists. */ + if (sys_stat(us_path, &sbuf) != 0) { + d_fprintf(stderr, "net usershare add: cannot stat path %s to ensure " + "this is a directory. Error was %s\n", + us_path, strerror(errno) ); + SAFE_FREE(sharename); + return -1; + } + + if (!S_ISDIR(sbuf.st_mode)) { + d_fprintf(stderr, "net usershare add: path %s is not a directory.\n", + us_path ); + SAFE_FREE(sharename); + return -1; + } + + /* If we're not root, check if we're restricted to sharing out directories + that we own only. */ + + if ((myeuid != 0) && lp_usershare_owner_only() && (myeuid != sbuf.st_uid)) { + d_fprintf(stderr, "net usershare add: cannot share path %s as " + "we are restricted to only sharing directories we own.\n", + us_path ); + SAFE_FREE(sharename); + return -1; + } + + /* No validation needed on comment. Now go through and validate the + acl string. Convert names to SID's as needed. Then run it through + parse_usershare_acl to ensure it's valid. */ + + ctx = talloc_init("share_info"); + + /* Start off the string we'll append to. */ + us_acl = talloc_strdup(ctx, ""); + + pacl = arg_acl; + num_aces = 1; + + /* Add the number of ',' characters to get the number of aces. */ + num_aces += count_chars(pacl,','); + + for (i = 0; i < num_aces; i++) { + DOM_SID sid; + const char *pcolon = strchr_m(pacl, ':'); + const char *name; + + if (pcolon == NULL) { + d_fprintf(stderr, "net usershare add: malformed acl %s (missing ':').\n", + pacl ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + switch(pcolon[1]) { + case 'f': + case 'F': + case 'd': + case 'r': + case 'R': + break; + default: + d_fprintf(stderr, "net usershare add: malformed acl %s " + "(access control must be 'r', 'f', or 'd')\n", + pacl ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + if (pcolon[2] != ',' && pcolon[2] != '\0') { + d_fprintf(stderr, "net usershare add: malformed terminating character for acl %s\n", + pacl ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + /* Get the name */ + name = talloc_strndup(ctx, pacl, pcolon - pacl); + if (!string_to_sid(&sid, name)) { + /* Convert to a SID */ + if (!net_lookup_sid_from_name(ctx, name, &sid)) { + d_fprintf(stderr, "net usershare add: cannot convert name %s to a SID.\n", + name ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + } + us_acl = talloc_asprintf_append(us_acl, "%s:%c,", sid_string_static(&sid), pcolon[1]); + + /* Move to the next ACL entry. */ + if (pcolon[2] == ',') { + pacl = &pcolon[3]; + } + } + + /* Remove the last ',' */ + us_acl[strlen(us_acl)-1] = '\0'; + + /* Create a temporary filename for this share. */ + tmpfd = smb_mkstemp(full_path_tmp); + + if (tmpfd == -1) { + d_fprintf(stderr, "net usershare add: cannot create tmp file %s\n", + full_path_tmp ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + /* Ensure we opened the file we thought we did. */ + if (sys_lstat(full_path_tmp, &lsbuf) != 0) { + d_fprintf(stderr, "net usershare add: cannot lstat tmp file %s\n", + full_path_tmp ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + /* Check this is the same as the file we opened. */ + if (sys_fstat(tmpfd, &sbuf) != 0) { + d_fprintf(stderr, "net usershare add: cannot fstat tmp file %s\n", + full_path_tmp ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + if (!S_ISREG(sbuf.st_mode) || sbuf.st_dev != lsbuf.st_dev || sbuf.st_ino != lsbuf.st_ino) { + d_fprintf(stderr, "net usershare add: tmp file %s is not a regular file ?\n", + full_path_tmp ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + if (fchmod(tmpfd, 0644) == -1) { + d_fprintf(stderr, "net usershare add: failed to fchmod tmp file %s to 0644n", + full_path_tmp ); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + /* Create the in-memory image of the file. */ + file_img = talloc_strdup(ctx, "#VERSION 1\npath="); + file_img = talloc_asprintf_append(file_img, "%s\ncomment=%s\nusershare_acl=%s\n", + us_path, us_comment, us_acl ); + + to_write = strlen(file_img); + + if (write(tmpfd, file_img, to_write) != to_write) { + d_fprintf(stderr, "net usershare add: failed to write %u bytes to file %s. Error was %s\n", + (unsigned int)to_write, full_path_tmp, strerror(errno)); + unlink(full_path_tmp); + talloc_destroy(ctx); + SAFE_FREE(sharename); + return -1; + } + + /* Attempt to replace any existing share by this name. */ + if (rename(full_path_tmp, full_path) != 0) { + unlink(full_path_tmp); + d_fprintf(stderr, "net usershare add: failed to add share %s. Error was %s\n", + sharename, strerror(errno)); + talloc_destroy(ctx); + close(tmpfd); + SAFE_FREE(sharename); + return -1; + } + + close(tmpfd); + talloc_destroy(ctx); + + if (opt_long_list_entries) { + const char *my_argv[2]; + my_argv[0] = sharename; + my_argv[1] = NULL; + net_usershare_info(1, argv); + } + + SAFE_FREE(sharename); + return 0; +} + +#if 0 +/*************************************************************************** + List function. +***************************************************************************/ + +static int list_fn(struct file_list *fl, void *private) +{ + d_printf("%s\n", fl->pathname); + return 0; +} +#endif + +/*************************************************************************** + List userlevel shares. +***************************************************************************/ + +static int net_usershare_list(int argc, const char **argv) +{ + fstring wcard; + BOOL only_ours = True; + int ret = -1; + struct priv_info pi; + TALLOC_CTX *ctx; + + fstrcpy(wcard, "*"); + + if (opt_long_list_entries) { + only_ours = False; + } + + switch (argc) { + case 0: + break; + case 1: + fstrcpy(wcard, argv[0]); + break; + default: + return net_usershare_list_usage(argc, argv); + } + + strlower_m(wcard); + + ctx = talloc_init("share_list"); + ret = get_share_list(ctx, wcard, only_ours); + if (ret) { + return ret; + } + + pi.ctx = ctx; + pi.op = US_LIST_OP; + + ret = process_share_list(info_fn, &pi); + talloc_destroy(ctx); + return ret; +} + +/*************************************************************************** + Handle "net usershare help *" subcommands. +***************************************************************************/ + +int net_usershare_help(int argc, const char **argv) +{ + struct functable func[] = { + {"ADD", net_usershare_add_usage}, + {"DELETE", net_usershare_delete_usage}, + {"INFO", net_usershare_info_usage}, + {"LIST", net_usershare_list_usage}, + {NULL, NULL}}; + + return net_run_function(argc, argv, func, net_usershare_usage); +} + +/*************************************************************************** + Entry-point for all the USERSHARE functions. +***************************************************************************/ + +int net_usershare(int argc, const char **argv) +{ + SMB_STRUCT_DIR *dp; + + struct functable func[] = { + {"ADD", net_usershare_add}, + {"DELETE", net_usershare_delete}, + {"INFO", net_usershare_info}, + {"LIST", net_usershare_list}, + {"HELP", net_usershare_help}, + {NULL, NULL} + }; + + if (lp_usershare_max_shares() == 0) { + d_fprintf(stderr, "net usershare: usershares are currently disabled\n"); + return -1; + } + + dp = sys_opendir(lp_usershare_path()); + if (!dp) { + int err = errno; + d_fprintf(stderr, "net usershare: cannot open usershare directory %s. Error %s\n", + lp_usershare_path(), strerror(err) ); + if (err == EACCES) { + d_fprintf(stderr, "You do not have permission to create a usershare. Ask your " + "administrator to grant you permissions to create a share.\n"); + } else if (err == ENOENT) { + d_fprintf(stderr, "Please ask your system administrator to " + "enable user sharing.\n"); + } + return -1; + } + sys_closedir(dp); + + return net_run_function(argc, argv, func, net_usershare_usage); +} diff --git a/source3/utils/net_util.c b/source3/utils/net_util.c new file mode 100644 index 00000000000..805104cefa1 --- /dev/null +++ b/source3/utils/net_util.c @@ -0,0 +1,89 @@ +/* + * Unix SMB/CIFS implementation. + * Helper routines for net + * 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" + +BOOL is_valid_policy_hnd(const POLICY_HND *hnd) +{ + POLICY_HND tmp; + ZERO_STRUCT(tmp); + return (memcmp(&tmp, hnd, sizeof(tmp)) != 0); +} + +NTSTATUS net_rpc_lookup_name(TALLOC_CTX *mem_ctx, struct cli_state *cli, + const char *name, const char **ret_domain, + const char **ret_name, DOM_SID *ret_sid, + enum SID_NAME_USE *ret_type) +{ + struct rpc_pipe_client *lsa_pipe; + POLICY_HND pol; + NTSTATUS result = NT_STATUS_OK; + const char **dom_names; + DOM_SID *sids; + uint32_t *types; + + ZERO_STRUCT(pol); + + lsa_pipe = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &result); + if (lsa_pipe == NULL) { + 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)) { + d_fprintf(stderr, "open_policy failed: %s\n", + nt_errstr(result)); + return result; + } + + result = rpccli_lsa_lookup_names(lsa_pipe, mem_ctx, &pol, 1, + &name, &dom_names, &sids, &types); + + if (!NT_STATUS_IS_OK(result)) { + /* This can happen easily, don't log an error */ + goto done; + } + + if (ret_domain != NULL) { + *ret_domain = dom_names[0]; + } + if (ret_name != NULL) { + *ret_name = talloc_strdup(mem_ctx, name); + } + if (ret_sid != NULL) { + sid_copy(ret_sid, &sids[0]); + } + if (ret_type != NULL) { + *ret_type = types[0]; + } + + done: + if (is_valid_policy_hnd(&pol)) { + rpccli_lsa_close(lsa_pipe, mem_ctx, &pol); + } + cli_rpc_pipe_close(lsa_pipe); + + return result; +} diff --git a/source3/utils/netlookup.c b/source3/utils/netlookup.c new file mode 100644 index 00000000000..edb2f7d5bae --- /dev/null +++ b/source3/utils/netlookup.c @@ -0,0 +1,209 @@ +/* + Unix SMB/CIFS implementation. + + Name lookup. + + Copyright (C) Jeremy Allison 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" + +/******************************************************** + Connection cachine struct. Goes away when ctx destroyed. +********************************************************/ + +struct con_struct { + BOOL failed_connect; + struct cli_state *cli; + struct rpc_pipe_client *lsapipe; + POLICY_HND pol; +}; + +static struct con_struct *cs; + +/******************************************************** + Close connection on context destruction. +********************************************************/ + +static int cs_destructor(void *p) +{ + if (cs->cli) { + cli_shutdown(cs->cli); + } + cs = NULL; + return 0; +} + +/******************************************************** + Create the connection to localhost. +********************************************************/ + +static struct con_struct *create_cs(TALLOC_CTX *ctx) +{ + NTSTATUS nt_status; + struct in_addr loopback_ip = *interpret_addr2("127.0.0.1");; + + if (cs) { + if (cs->failed_connect) { + return NULL; + } + return cs; + } + + cs = TALLOC_P(ctx, struct con_struct); + if (!cs) { + return NULL; + } + + ZERO_STRUCTP(cs); + talloc_set_destructor(cs, cs_destructor); + + /* Connect to localhost with given username/password. */ + /* JRA. Pretty sure we can just do this anonymously.... */ +#if 0 + if (!opt_password && !opt_machine_pass) { + char *pass = getpass("Password:"); + if (pass) { + opt_password = SMB_STRDUP(pass); + } + } +#endif + + nt_status = cli_full_connection(&cs->cli, global_myname(), global_myname(), + &loopback_ip, 0, + "IPC$", "IPC", +#if 0 + opt_user_name, + opt_workgroup, + opt_password, +#else + "", + opt_workgroup, + "", +#endif + 0, + Undefined, + NULL); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("create_cs: Connect failed. Error was %s\n", nt_errstr(nt_status))); + cs->failed_connect = True; + return NULL; + } + + cs->lsapipe = cli_rpc_pipe_open_noauth(cs->cli, + PI_LSARPC, + &nt_status); + + if (cs->lsapipe == NULL) { + DEBUG(2,("create_cs: open LSA pipe failed. Error was %s\n", nt_errstr(nt_status))); + cs->failed_connect = True; + return NULL; + } + + nt_status = rpccli_lsa_open_policy(cs->lsapipe, ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &cs->pol); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("create_cs: rpccli_lsa_open_policy failed. Error was %s\n", nt_errstr(nt_status))); + cs->failed_connect = True; + return NULL; + } + + return cs; +} + +/******************************************************** + Do a lookup_sids call to localhost. + Check if the local machine is authoritative for this sid. We can't + check if this is our SID as that's stored in the root-read-only + secrets.tdb. + The local smbd will also ask winbindd for us, so we don't have to. +********************************************************/ + +BOOL net_lookup_name_from_sid(TALLOC_CTX *ctx, + DOM_SID *psid, + const char **ppdomain, + const char **ppname) +{ + NTSTATUS nt_status; + struct con_struct *csp = NULL; + char **domains; + char **names; + uint32 *types; + + *ppdomain = NULL; + *ppname = NULL; + + csp = create_cs(ctx); + if (csp == NULL) { + return False; + } + + nt_status = rpccli_lsa_lookup_sids(csp->lsapipe, ctx, + &csp->pol, + 1, psid, + &domains, + &names, + &types); + + if (!NT_STATUS_IS_OK(nt_status)) { + return False; + } + + *ppdomain = domains[0]; + *ppname = names[0]; + /* Don't care about type here. */ + + /* Converted OK */ + return True; +} + +/******************************************************** + Do a lookup_names call to localhost. +********************************************************/ + +BOOL net_lookup_sid_from_name(TALLOC_CTX *ctx, const char *full_name, DOM_SID *pret_sid) +{ + NTSTATUS nt_status; + struct con_struct *csp = NULL; + DOM_SID *sids = NULL; + uint32 *types = NULL; + + csp = create_cs(ctx); + if (csp == NULL) { + return False; + } + + nt_status = rpccli_lsa_lookup_names(csp->lsapipe, ctx, + &csp->pol, + 1, + &full_name, + NULL, &sids, + &types); + + if (!NT_STATUS_IS_OK(nt_status)) { + return False; + } + + *pret_sid = sids[0]; + + /* Converted OK */ + return True; +} diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 4759aec0ccf..c22f4b5e098 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1173,7 +1173,7 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego) spnego.negTokenInit.mechListMIC.length); principal[spnego.negTokenInit.mechListMIC.length] = '\0'; - retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0); + retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL); if (retval) { @@ -1191,12 +1191,12 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego) pstr_sprintf(user, "%s@%s", opt_username, opt_domain); if ((retval = kerberos_kinit_password(user, opt_password, - 0, NULL, NULL))) { + 0, NULL, NULL, NULL, False, 0))) { DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval))); return False; } - retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0); + retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL); if (retval) { DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval))); diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c index f41bbb8caaf..0b17d50ad31 100644 --- a/source3/utils/pdbedit.c +++ b/source3/utils/pdbedit.c @@ -337,7 +337,7 @@ static int fix_users_list (struct pdb_context *in) while (check && NT_STATUS_IS_OK(in->pdb_getsampwent (in, sam_pwent))) { printf("Updating record for user %s\n", pdb_get_username(sam_pwent)); - if (!pdb_update_sam_account(sam_pwent)) { + if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_pwent))) { printf("Update of user %s failed!\n", pdb_get_username(sam_pwent)); } pdb_free_sam(&sam_pwent); @@ -498,7 +498,7 @@ static int new_user (struct pdb_context *in, const char *username, get_global_sam_sid(); - if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pwent, username, 0))) { + if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pwent, username))) { DEBUG(0, ("could not create account to add new user %s\n", username)); return -1; } @@ -603,13 +603,13 @@ static int new_machine (struct pdb_context *in, const char *machine_in) fstrcpy(machineaccount, machinename); fstrcat(machineaccount, "$"); - if ((pwd = getpwnam_alloc(machineaccount))) { + if ((pwd = getpwnam_alloc(NULL, machineaccount))) { if (!NT_STATUS_IS_OK(pdb_init_sam_pw( &sam_pwent, pwd))) { fprintf(stderr, "Could not init sam from pw\n"); - passwd_free(&pwd); + talloc_free(pwd); return -1; } - passwd_free(&pwd); + talloc_free(&pwd); } else { if (!NT_STATUS_IS_OK(pdb_init_sam (&sam_pwent))) { fprintf(stderr, "Could not init sam from pw\n"); diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c index 26362c6270a..cff3bc5dde4 100644 --- a/source3/utils/smbcacls.c +++ b/source3/utils/smbcacls.c @@ -145,7 +145,7 @@ static BOOL StringToSid(DOM_SID *sid, const char *str) if (!cacls_open_policy_hnd() || !NT_STATUS_IS_OK(rpccli_lsa_lookup_names(global_pipe_hnd, global_hack_cli->mem_ctx, - &pol, 1, &str, &sids, + &pol, 1, &str, NULL, &sids, &types))) { result = False; goto done; diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c index a4d2766b132..405e51cd256 100644 --- a/source3/utils/smbcontrol.c +++ b/source3/utils/smbcontrol.c @@ -584,6 +584,107 @@ static BOOL do_drvupgrade(const struct process_id pid, pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); } +static BOOL do_winbind_online(const struct process_id pid, + const int argc, const char **argv) +{ + TDB_CONTEXT *tdb; + + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol winbindd online\n"); + return False; + } + + if (!lp_winbind_offline_logon()) { + fprintf(stderr, "The parameter \"winbind offline logon\" must " + "be set in the [global] section of smb.conf for this " + "command to be allowed.\n"); + return False; + } + + /* Remove the entry in the winbindd_cache tdb to tell a later + starting winbindd that we're online. */ + + tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600); + if (!tdb) { + fprintf(stderr, "Cannot open the tdb %s for writing.\n", + lock_path("winbindd_cache.tdb")); + return False; + } + + tdb_delete_bystring(tdb, "WINBINDD_OFFLINE"); + tdb_close(tdb); + + return send_message(pid, MSG_WINBIND_ONLINE, NULL, 0, False); +} + +static BOOL do_winbind_offline(const struct process_id pid, + const int argc, const char **argv) +{ + TDB_CONTEXT *tdb; + BOOL ret = False; + int retry = 0; + + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol winbindd offline\n"); + return False; + } + + if (!lp_winbind_offline_logon()) { + fprintf(stderr, "The parameter \"winbind offline logon\" must " + "be set in the [global] section of smb.conf for this " + "command to be allowed.\n"); + return False; + } + + /* Create an entry in the winbindd_cache tdb to tell a later + starting winbindd that we're offline. We may actually create + it here... */ + + tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), + WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, + TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600); + + if (!tdb) { + fprintf(stderr, "Cannot open the tdb %s for writing.\n", + lock_path("winbindd_cache.tdb")); + return False; + } + + /* There's a potential race condition that if a child + winbindd detects a domain is online at the same time + we're trying to tell it to go offline that it might + delete the record we add between us adding it and + sending the message. Minimize this by retrying up to + 5 times. */ + + for (retry = 0; retry < 5; retry++) { + int err; + TDB_DATA d; + ZERO_STRUCT(d); + tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT); + + ret = send_message(pid, MSG_WINBIND_OFFLINE, NULL, 0, False); + + /* Check that the entry "WINBINDD_OFFLINE" still exists. */ + tdb->ecode = 0; + d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" ); + + /* As this is a key with no data we don't need to free, we + check for existence by looking at tdb_err. */ + + err = tdb_error(tdb); + + if (err == TDB_ERR_NOEXIST) { + DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n")); + } else { + break; + } + } + + tdb_close(tdb); + return ret; +} + static BOOL do_reload_config(const struct process_id pid, const int argc, const char **argv) { @@ -668,6 +769,8 @@ static const struct { { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" }, { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"}, { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"}, + { "online", do_winbind_online, "Ask winbind to go into online state"}, + { "offline", do_winbind_offline, "Ask winbind to go into offline state"}, { "noop", do_noop, "Do nothing" }, { NULL } }; @@ -681,7 +784,7 @@ static void usage(poptContext *pc) poptPrintHelp(*pc, stderr, 0); fprintf(stderr, "\n"); - fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\" or a " + fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a " "process ID\n"); fprintf(stderr, "\n"); @@ -715,10 +818,17 @@ static struct process_id parse_dest(const char *dest) return pid_to_procid(sys_getpid()); } + /* Fix winbind typo. */ + if (strequal(dest, "winbind")) { + dest = "winbindd"; + } + /* Check for numeric pid number */ result = interpret_pid(dest); - if (procid_valid(&result)) { + + /* Zero isn't valid if not smbd. */ + if (result.pid && procid_valid(&result)) { return result; } diff --git a/source3/utils/smbcquotas.c b/source3/utils/smbcquotas.c index b1a14685f5e..7b3268e7834 100644 --- a/source3/utils/smbcquotas.c +++ b/source3/utils/smbcquotas.c @@ -116,7 +116,7 @@ static BOOL StringToSid(DOM_SID *sid, const char *str) if (!cli_open_policy_hnd() || !NT_STATUS_IS_OK(rpccli_lsa_lookup_names(global_pipe_hnd, cli_ipc->mem_ctx, - &pol, 1, &str, &sids, + &pol, 1, &str, NULL, &sids, &types))) { result = False; goto done; diff --git a/source3/utils/smbpasswd.c b/source3/utils/smbpasswd.c index 7eb11137d70..4323ee29e0c 100644 --- a/source3/utils/smbpasswd.c +++ b/source3/utils/smbpasswd.c @@ -270,10 +270,11 @@ static char *prompt_for_new_password(BOOL stdin_get) Change a password either locally or remotely. *************************************************************/ -static BOOL password_change(const char *remote_mach, char *username, - char *old_passwd, char *new_pw, int local_flags) +static NTSTATUS password_change(const char *remote_mach, char *username, + char *old_passwd, char *new_pw, + int local_flags) { - BOOL ret; + NTSTATUS ret; pstring err_str; pstring msg_str; @@ -281,7 +282,7 @@ static BOOL password_change(const char *remote_mach, char *username, if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER| LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) { /* these things can't be done remotely yet */ - return False; + return NT_STATUS_UNSUCCESSFUL; } ret = remote_password_change(remote_mach, username, old_passwd, new_pw, err_str, sizeof(err_str)); @@ -370,9 +371,9 @@ static int process_root(int local_flags) load_interfaces(); } - if (!user_name[0] && (pwd = getpwuid_alloc(geteuid()))) { + if (!user_name[0] && (pwd = getpwuid_alloc(NULL, geteuid()))) { fstrcpy(user_name, pwd->pw_name); - passwd_free(&pwd); + talloc_free(pwd); } if (!user_name[0]) { @@ -465,7 +466,9 @@ static int process_root(int local_flags) } } - if (!password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags)) { + if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name, + old_passwd, new_passwd, + local_flags))) { fprintf(stderr,"Failed to modify password entry for user %s\n", user_name); result = 1; goto done; @@ -512,10 +515,10 @@ static int process_nonroot(int local_flags) } if (!user_name[0]) { - pwd = getpwuid_alloc(getuid()); + pwd = getpwuid_alloc(NULL, getuid()); if (pwd) { fstrcpy(user_name,pwd->pw_name); - passwd_free(&pwd); + talloc_free(pwd); } else { fprintf(stderr, "smbpasswd: cannot lookup user name for uid %u\n", (unsigned int)getuid()); exit(1); @@ -549,7 +552,8 @@ static int process_nonroot(int local_flags) exit(1); } - if (!password_change(remote_machine, user_name, old_pw, new_pw, 0)) { + if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name, old_pw, + new_pw, 0))) { fprintf(stderr,"Failed to change password for %s\n", user_name); result = 1; goto done; |