summaryrefslogtreecommitdiff
path: root/source3/utils
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2006-02-03 22:19:41 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:06:23 -0500
commit0af1500fc0bafe61019f1b2ab1d9e1d369221240 (patch)
tree653fc2533795458d5f9696402285d9f14e527a21 /source3/utils
parent21a30a1346c9f9a25659a0cea0d276d8c2e6ddca (diff)
downloadsamba-0af1500fc0bafe61019f1b2ab1d9e1d369221240.tar.gz
samba-0af1500fc0bafe61019f1b2ab1d9e1d369221240.tar.bz2
samba-0af1500fc0bafe61019f1b2ab1d9e1d369221240.zip
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.c27
-rw-r--r--source3/utils/net.h23
-rw-r--r--source3/utils/net_ads_gpo.c436
-rw-r--r--source3/utils/net_groupmap.c38
-rw-r--r--source3/utils/net_help.c9
-rw-r--r--source3/utils/net_lookup.c52
-rw-r--r--source3/utils/net_rpc.c557
-rw-r--r--source3/utils/net_rpc_rights.c55
-rw-r--r--source3/utils/net_rpc_samsync.c141
-rw-r--r--source3/utils/net_rpc_shell.c270
-rw-r--r--source3/utils/net_sam.c784
-rw-r--r--source3/utils/net_usershare.c829
-rw-r--r--source3/utils/net_util.c89
-rw-r--r--source3/utils/netlookup.c209
-rw-r--r--source3/utils/ntlm_auth.c6
-rw-r--r--source3/utils/pdbedit.c10
-rw-r--r--source3/utils/smbcacls.c2
-rw-r--r--source3/utils/smbcontrol.c114
-rw-r--r--source3/utils/smbcquotas.c2
-rw-r--r--source3/utils/smbpasswd.c24
20 files changed, 3453 insertions, 224 deletions
diff --git a/source3/utils/net.c b/source3/utils/net.c
index 25e10c6a31..069047c9ec 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 2df13cfb8f..fc3167012d 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 0000000000..fec6fb88fa
--- /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 1cff120c39..96a6aa531a 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 c5188c3608..79062345ab 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 8ee63515d4..dd2d666d5a 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 0495a7b92c..a9dc3a1fc6 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 2c15fef5a0..2f02b40948 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 09e62d9def..45fdfbfad3 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 0000000000..f9675e430b
--- /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 0000000000..ba3ec5c57f
--- /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 0000000000..c00f239b99
--- /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 0000000000..805104cefa
--- /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 0000000000..edb2f7d5ba
--- /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 4759aec0cc..c22f4b5e09 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 f41bbb8caa..0b17d50ad3 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 26362c6270..cff3bc5dde 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 a4d2766b13..405e51cd25 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 b1a14685f5..7b3268e783 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 7eb11137d7..4323ee29e0 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;