mirror of
https://github.com/samba-team/samba.git
synced 2025-01-12 09:18:10 +03:00
r2935: This is a long-standing one in my patch-queue: A pair of net commands
(usersidlist/allowedusers) to scan a file server's share and list all users who have permission to connect there. Volker
This commit is contained in:
parent
b6193f6d52
commit
f7f84aa1de
@ -225,6 +225,94 @@ WERROR cli_srvsvc_net_share_enum(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
WERROR cli_srvsvc_net_share_get_info(struct cli_state *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const char *sharename,
|
||||
uint32 info_level,
|
||||
SRV_SHARE_INFO *info)
|
||||
{
|
||||
prs_struct qbuf, rbuf;
|
||||
SRV_Q_NET_SHARE_GET_INFO q;
|
||||
SRV_R_NET_SHARE_GET_INFO r;
|
||||
WERROR result = W_ERROR(ERRgeneral);
|
||||
|
||||
ZERO_STRUCT(q);
|
||||
ZERO_STRUCT(r);
|
||||
|
||||
/* Initialise parse structures */
|
||||
|
||||
prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
|
||||
prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
|
||||
|
||||
/* Initialise input parameters */
|
||||
|
||||
init_srv_q_net_share_get_info(&q, cli->srv_name_slash, sharename,
|
||||
info_level);
|
||||
|
||||
/* Marshall data and send request */
|
||||
|
||||
if (!srv_io_q_net_share_get_info("", &q, &qbuf, 0) ||
|
||||
!rpc_api_pipe_req(cli, SRV_NET_SHARE_GET_INFO, &qbuf, &rbuf))
|
||||
goto done;
|
||||
|
||||
/* Unmarshall response */
|
||||
|
||||
if (!srv_io_r_net_share_get_info("", &r, &rbuf, 0))
|
||||
goto done;
|
||||
|
||||
result = r.status;
|
||||
|
||||
if (!W_ERROR_IS_OK(result))
|
||||
goto done;
|
||||
|
||||
ZERO_STRUCTP(info);
|
||||
|
||||
info->switch_value = info_level;
|
||||
|
||||
switch(info_level) {
|
||||
case 502:
|
||||
{
|
||||
SRV_SHARE_INFO_502 *info502 = &info->share.info502;
|
||||
SH_INFO_502_STR *info502_str = &info502->info_502_str;
|
||||
|
||||
char *s;
|
||||
|
||||
info->share.info502 = r.info.share.info502;
|
||||
|
||||
/* Duplicate strings */
|
||||
|
||||
s = unistr2_tdup(mem_ctx, &info502_str->uni_netname);
|
||||
if (s)
|
||||
init_unistr2(&info502_str->uni_netname,
|
||||
s, UNI_STR_TERMINATE);
|
||||
|
||||
s = unistr2_tdup(mem_ctx, &info502_str->uni_remark);
|
||||
if (s)
|
||||
init_unistr2(&info502_str->uni_remark,
|
||||
s, UNI_STR_TERMINATE);
|
||||
|
||||
s = unistr2_tdup(mem_ctx, &info502_str->uni_path);
|
||||
if (s)
|
||||
init_unistr2(&info502_str->uni_path,
|
||||
s, UNI_STR_TERMINATE);
|
||||
|
||||
s = unistr2_tdup(mem_ctx, &info502_str->uni_passwd);
|
||||
if (s)
|
||||
init_unistr2(&info502_str->uni_passwd,
|
||||
s, UNI_STR_TERMINATE);
|
||||
|
||||
info502_str->sd = dup_sec_desc(mem_ctx, info502_str->sd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
prs_mem_free(&qbuf);
|
||||
prs_mem_free(&rbuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
WERROR cli_srvsvc_net_share_del(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
const char *sharename)
|
||||
{
|
||||
|
@ -697,6 +697,7 @@ static struct functable net_func[] = {
|
||||
{"MAXRID", net_maxrid},
|
||||
{"IDMAP", net_idmap},
|
||||
{"STATUS", net_status},
|
||||
{"USERSIDLIST", net_usersidlist},
|
||||
#ifdef WITH_FAKE_KASERVER
|
||||
{"AFSKEY", net_afskey},
|
||||
#endif
|
||||
|
@ -121,9 +121,14 @@ int net_help_share(int argc, const char **argv)
|
||||
"\tenumerates all exported resources (network shares) "
|
||||
"on target server\n\n"
|
||||
"net [<method>] share ADD <name=serverpath> [misc. options] [targets]"
|
||||
"\n\tAdds a share from a server (makes the export active)\n\n"
|
||||
"net [<method>] share DELETE <sharename> [misc. options] [targets]"
|
||||
"\n\tDeletes a share from a server (makes the export inactive)\n\n"
|
||||
"\n\tadds a share from a server (makes the export active)\n\n"
|
||||
"net [<method>] share DELETE <sharename> [misc. options] [targets]"
|
||||
"\n\tdeletes a share from a server (makes the export inactive)\n\n"
|
||||
"net [<method>] share ALLOWEDUSERS [<filename>] "
|
||||
"[misc. options] [targets]"
|
||||
"\n\tshows a list of all shares together with all users allowed to"
|
||||
"\n\taccess them. This needs the output of 'net usersidlist' on"
|
||||
"\n\tstdin or in <filename>.\n"
|
||||
"net [<method>] share MIGRATE FILES <sharename> [misc. options] [targets]"
|
||||
"\n\tMigrates files from remote to local server\n\n"
|
||||
"net [<method>] share MIGRATE SHARES <sharename> [misc. options] [targets]"
|
||||
@ -217,6 +222,7 @@ static int net_usage(int argc, const char **argv)
|
||||
" net changesecretpw\tto change the machine password in the local secrets database only\n"\
|
||||
" \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"
|
||||
"\n"\
|
||||
" net ads <command>\tto run ADS commands\n"\
|
||||
" net rap <command>\tto run RAP (pre-RPC) commands\n"\
|
||||
@ -254,6 +260,7 @@ int net_help(int argc, const char **argv)
|
||||
{"PASSWORD", net_rap_password_usage},
|
||||
{"TIME", net_time_usage},
|
||||
{"LOOKUP", net_lookup_usage},
|
||||
{"USERSIDLIST", net_usersidlist_usage},
|
||||
#ifdef WITH_FAKE_KASERVER
|
||||
{"AFSKEY", net_afskey_usage},
|
||||
#endif
|
||||
|
@ -2973,6 +2973,784 @@ static int rpc_share_migrate(int argc, const char **argv)
|
||||
return net_run_function(argc, argv, func, rpc_share_usage);
|
||||
}
|
||||
|
||||
struct full_alias {
|
||||
DOM_SID sid;
|
||||
int num_members;
|
||||
DOM_SID *members;
|
||||
};
|
||||
|
||||
static int num_server_aliases;
|
||||
static struct full_alias *server_aliases;
|
||||
|
||||
/*
|
||||
* Add an alias to the static list.
|
||||
*/
|
||||
static void push_alias(TALLOC_CTX *mem_ctx, struct full_alias *alias)
|
||||
{
|
||||
if (server_aliases == NULL)
|
||||
server_aliases = malloc(100 * sizeof(struct full_alias));
|
||||
|
||||
server_aliases[num_server_aliases] = *alias;
|
||||
num_server_aliases += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a specific domain on the server, fetch all the aliases
|
||||
* and their members. Add all of them to the server_aliases.
|
||||
*/
|
||||
static NTSTATUS
|
||||
rpc_fetch_domain_aliases(struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
POLICY_HND *connect_pol,
|
||||
const DOM_SID *domain_sid)
|
||||
{
|
||||
uint32 start_idx, max_entries, num_entries, i;
|
||||
struct acct_info *groups;
|
||||
NTSTATUS result;
|
||||
POLICY_HND domain_pol;
|
||||
|
||||
/* Get domain policy handle */
|
||||
|
||||
result = cli_samr_open_domain(cli, mem_ctx, connect_pol,
|
||||
MAXIMUM_ALLOWED_ACCESS,
|
||||
domain_sid, &domain_pol);
|
||||
if (!NT_STATUS_IS_OK(result))
|
||||
return result;
|
||||
|
||||
start_idx = 0;
|
||||
max_entries = 250;
|
||||
|
||||
do {
|
||||
result = cli_samr_enum_als_groups(cli, mem_ctx, &domain_pol,
|
||||
&start_idx, max_entries,
|
||||
&groups, &num_entries);
|
||||
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
|
||||
POLICY_HND alias_pol;
|
||||
struct full_alias alias;
|
||||
DOM_SID *members;
|
||||
int j;
|
||||
|
||||
result = cli_samr_open_alias(cli, mem_ctx, &domain_pol,
|
||||
MAXIMUM_ALLOWED_ACCESS,
|
||||
groups[i].rid,
|
||||
&alias_pol);
|
||||
if (!NT_STATUS_IS_OK(result))
|
||||
goto done;
|
||||
|
||||
result = cli_samr_query_aliasmem(cli, mem_ctx,
|
||||
&alias_pol,
|
||||
&alias.num_members,
|
||||
&members);
|
||||
if (!NT_STATUS_IS_OK(result))
|
||||
goto done;
|
||||
|
||||
result = cli_samr_close(cli, mem_ctx, &alias_pol);
|
||||
if (!NT_STATUS_IS_OK(result))
|
||||
goto done;
|
||||
|
||||
alias.members = NULL;
|
||||
|
||||
if (alias.num_members > 0) {
|
||||
alias.members = malloc(alias.num_members *
|
||||
sizeof(DOM_SID));
|
||||
|
||||
for (j = 0; j < alias.num_members; j++)
|
||||
sid_copy(&alias.members[j],
|
||||
&members[j]);
|
||||
}
|
||||
|
||||
sid_copy(&alias.sid, domain_sid);
|
||||
sid_append_rid(&alias.sid, groups[i].rid);
|
||||
|
||||
push_alias(mem_ctx, &alias);
|
||||
}
|
||||
} while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
|
||||
|
||||
result = NT_STATUS_OK;
|
||||
|
||||
done:
|
||||
cli_samr_close(cli, mem_ctx, &domain_pol);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump server_aliases as names for debugging purposes.
|
||||
*/
|
||||
static NTSTATUS
|
||||
rpc_aliaslist_dump(const DOM_SID *domain_sid, const char *domain_name,
|
||||
struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
int i;
|
||||
NTSTATUS result;
|
||||
POLICY_HND lsa_pol;
|
||||
|
||||
result = cli_lsa_open_policy(cli, mem_ctx, True,
|
||||
SEC_RIGHTS_MAXIMUM_ALLOWED,
|
||||
&lsa_pol);
|
||||
if (!NT_STATUS_IS_OK(result))
|
||||
return result;
|
||||
|
||||
for (i=0; i<num_server_aliases; i++) {
|
||||
char **names;
|
||||
char **domains;
|
||||
uint32 *types;
|
||||
int j;
|
||||
|
||||
struct full_alias *alias = &server_aliases[i];
|
||||
|
||||
result = cli_lsa_lookup_sids(cli, mem_ctx, &lsa_pol, 1,
|
||||
&alias->sid,
|
||||
&domains, &names, &types);
|
||||
if (!NT_STATUS_IS_OK(result))
|
||||
continue;
|
||||
|
||||
DEBUG(1, ("%s\\%s %d: ", domains[0], names[0], types[0]));
|
||||
|
||||
if (alias->num_members == 0) {
|
||||
DEBUG(1, ("\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
result = cli_lsa_lookup_sids(cli, mem_ctx, &lsa_pol,
|
||||
alias->num_members,
|
||||
alias->members,
|
||||
&domains, &names, &types);
|
||||
|
||||
if (!NT_STATUS_IS_OK(result) &&
|
||||
!NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
|
||||
continue;
|
||||
|
||||
for (j=0; j<alias->num_members; j++)
|
||||
DEBUG(1, ("%s\\%s (%d); ",
|
||||
domains[j] ? domains[j] : "*unknown*",
|
||||
names[j] ? names[j] : "*unknown*",types[j]));
|
||||
DEBUG(1, ("\n"));
|
||||
}
|
||||
|
||||
cli_lsa_close(cli, mem_ctx, &lsa_pol);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch a list of all server aliases and their members into
|
||||
* server_aliases.
|
||||
*/
|
||||
static NTSTATUS
|
||||
rpc_aliaslist_internals(const DOM_SID *domain_sid, const char *domain_name,
|
||||
struct cli_state *cli, TALLOC_CTX *mem_ctx,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
NTSTATUS result;
|
||||
POLICY_HND connect_pol;
|
||||
DOM_SID global_sid_Builtin;
|
||||
|
||||
result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
|
||||
&connect_pol);
|
||||
|
||||
if (!NT_STATUS_IS_OK(result))
|
||||
goto done;
|
||||
|
||||
string_to_sid(&global_sid_Builtin, "S-1-5-32");
|
||||
|
||||
result = rpc_fetch_domain_aliases(cli, mem_ctx, &connect_pol,
|
||||
&global_sid_Builtin);
|
||||
|
||||
if (!NT_STATUS_IS_OK(result))
|
||||
goto done;
|
||||
|
||||
result = rpc_fetch_domain_aliases(cli, mem_ctx, &connect_pol,
|
||||
domain_sid);
|
||||
|
||||
cli_samr_close(cli, mem_ctx, &connect_pol);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
static void init_user_token(NT_USER_TOKEN *token, DOM_SID *user_sid)
|
||||
{
|
||||
DOM_SID global_sid_World;
|
||||
DOM_SID global_sid_Network;
|
||||
DOM_SID global_sid_Authenticated_Users;
|
||||
|
||||
string_to_sid(&global_sid_World, "S-1-1-0");
|
||||
string_to_sid(&global_sid_Network, "S-1-5-2");
|
||||
string_to_sid(&global_sid_Authenticated_Users, "S-1-5-11");
|
||||
|
||||
token->num_sids = 4;
|
||||
|
||||
token->user_sids = malloc(4 * sizeof(DOM_SID));
|
||||
|
||||
token->user_sids[0] = *user_sid;
|
||||
sid_copy(&token->user_sids[1], &global_sid_World);
|
||||
sid_copy(&token->user_sids[2], &global_sid_Network);
|
||||
sid_copy(&token->user_sids[3], &global_sid_Authenticated_Users);
|
||||
}
|
||||
|
||||
static void free_user_token(NT_USER_TOKEN *token)
|
||||
{
|
||||
SAFE_FREE(token->user_sids);
|
||||
}
|
||||
|
||||
static BOOL is_sid_in_token(NT_USER_TOKEN *token, DOM_SID *sid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<token->num_sids; i++) {
|
||||
if (sid_compare(sid, &token->user_sids[i]) == 0)
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
static void add_sid_to_token(NT_USER_TOKEN *token, DOM_SID *sid)
|
||||
{
|
||||
if (is_sid_in_token(token, sid))
|
||||
return;
|
||||
|
||||
token->user_sids = Realloc(token->user_sids,
|
||||
(token->num_sids+1) * sizeof(DOM_SID));
|
||||
|
||||
sid_copy(&token->user_sids[token->num_sids], sid);
|
||||
|
||||
token->num_sids += 1;
|
||||
}
|
||||
|
||||
struct user_token {
|
||||
fstring name;
|
||||
NT_USER_TOKEN token;
|
||||
};
|
||||
|
||||
static void dump_user_token(struct user_token *token)
|
||||
{
|
||||
int i;
|
||||
|
||||
d_printf("%s\n", token->name);
|
||||
|
||||
for (i=0; i<token->token.num_sids; i++) {
|
||||
d_printf(" %s\n", sid_string_static(&token->token.user_sids[i]));
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL is_alias_member(DOM_SID *sid, struct full_alias *alias)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<alias->num_members; i++) {
|
||||
if (sid_compare(sid, &alias->members[i]) == 0)
|
||||
return True;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
static void collect_sid_memberships(NT_USER_TOKEN *token, DOM_SID sid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<num_server_aliases; i++) {
|
||||
if (is_alias_member(&sid, &server_aliases[i]))
|
||||
add_sid_to_token(token, &server_aliases[i].sid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We got a user token with all the SIDs we can know about without asking the
|
||||
* server directly. These are the user and domain group sids. All of these can
|
||||
* be members of aliases. So scan the list of aliases for each of the SIDs and
|
||||
* add them to the token.
|
||||
*/
|
||||
|
||||
static void collect_alias_memberships(NT_USER_TOKEN *token)
|
||||
{
|
||||
int num_global_sids = token->num_sids;
|
||||
int i;
|
||||
|
||||
for (i=0; i<num_global_sids; i++) {
|
||||
collect_sid_memberships(token, token->user_sids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL get_user_sids(const char *domain, const char *user,
|
||||
NT_USER_TOKEN *token)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
fstring full_name;
|
||||
NSS_STATUS result;
|
||||
|
||||
DOM_SID user_sid;
|
||||
|
||||
int i;
|
||||
|
||||
fstr_sprintf(full_name, "%s%c%s",
|
||||
domain, *lp_winbind_separator(), user);
|
||||
|
||||
/* First let's find out the user sid */
|
||||
|
||||
ZERO_STRUCT(request);
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
fstrcpy(request.data.name.dom_name, domain);
|
||||
fstrcpy(request.data.name.name, user);
|
||||
|
||||
result = winbindd_request(WINBINDD_LOOKUPNAME, &request, &response);
|
||||
|
||||
if (result != NSS_STATUS_SUCCESS) {
|
||||
DEBUG(1, ("winbind could not find %s\n", full_name));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (response.data.sid.type != SID_NAME_USER) {
|
||||
DEBUG(1, ("%s is not a user\n", full_name));
|
||||
return False;
|
||||
}
|
||||
|
||||
string_to_sid(&user_sid, response.data.sid.sid);
|
||||
|
||||
init_user_token(token, &user_sid);
|
||||
|
||||
/* And now the groups winbind knows about */
|
||||
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
fstrcpy(request.data.username, full_name);
|
||||
|
||||
result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
|
||||
|
||||
if (result != NSS_STATUS_SUCCESS) {
|
||||
DEBUG(1, ("winbind could not get groups of %s\n", full_name));
|
||||
return False;
|
||||
}
|
||||
|
||||
for (i = 0; i < response.data.num_entries; i++) {
|
||||
gid_t gid = ((gid_t *)response.extra_data)[i];
|
||||
DOM_SID sid;
|
||||
|
||||
struct winbindd_request sidrequest;
|
||||
struct winbindd_response sidresponse;
|
||||
|
||||
ZERO_STRUCT(sidrequest);
|
||||
ZERO_STRUCT(sidresponse);
|
||||
|
||||
sidrequest.data.gid = gid;
|
||||
|
||||
result = winbindd_request(WINBINDD_GID_TO_SID,
|
||||
&sidrequest, &sidresponse);
|
||||
|
||||
if (result != NSS_STATUS_SUCCESS) {
|
||||
DEBUG(1, ("winbind could not find SID of gid %d\n",
|
||||
gid));
|
||||
return False;
|
||||
}
|
||||
|
||||
DEBUG(3, (" %s\n", sidresponse.data.sid.sid));
|
||||
|
||||
string_to_sid(&sid, sidresponse.data.sid.sid);
|
||||
add_sid_to_token(token, &sid);
|
||||
}
|
||||
|
||||
SAFE_FREE(response.extra_data);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all user tokens we want to look at
|
||||
**/
|
||||
static BOOL get_user_tokens(int *num_tokens, struct user_token **user_tokens)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
const char *extra_data;
|
||||
fstring name;
|
||||
int i;
|
||||
struct user_token *result;
|
||||
|
||||
/* Send request to winbind daemon */
|
||||
|
||||
ZERO_STRUCT(request);
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
if (winbindd_request(WINBINDD_LIST_USERS, &request, &response) !=
|
||||
NSS_STATUS_SUCCESS)
|
||||
return False;
|
||||
|
||||
/* Look through extra data */
|
||||
|
||||
if (!response.extra_data)
|
||||
return False;
|
||||
|
||||
extra_data = (const char *)response.extra_data;
|
||||
*num_tokens = 0;
|
||||
|
||||
while(next_token(&extra_data, name, ",", sizeof(fstring))) {
|
||||
*num_tokens += 1;
|
||||
}
|
||||
|
||||
result = malloc(*num_tokens * sizeof(struct user_token));
|
||||
|
||||
if (result == NULL) {
|
||||
DEBUG(1, ("Could not malloc sid array\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
extra_data = (const char *)response.extra_data;
|
||||
i=0;
|
||||
|
||||
while(next_token(&extra_data, name, ",", sizeof(fstring))) {
|
||||
|
||||
fstring domain, user;
|
||||
char *p;
|
||||
|
||||
fstrcpy(result[i].name, name);
|
||||
|
||||
p = strchr(name, *lp_winbind_separator());
|
||||
|
||||
DEBUG(3, ("%s\n", name));
|
||||
|
||||
if (p == NULL)
|
||||
continue;
|
||||
|
||||
*p++ = '\0';
|
||||
|
||||
fstrcpy(domain, name);
|
||||
strupper_m(domain);
|
||||
fstrcpy(user, p);
|
||||
|
||||
get_user_sids(domain, user, &(result[i].token));
|
||||
i+=1;
|
||||
}
|
||||
|
||||
SAFE_FREE(response.extra_data);
|
||||
|
||||
*user_tokens = result;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static BOOL get_user_tokens_from_file(FILE *f,
|
||||
int *num_tokens,
|
||||
struct user_token **tokens)
|
||||
{
|
||||
struct user_token *token = NULL;
|
||||
|
||||
while (!feof(f)) {
|
||||
fstring line;
|
||||
|
||||
if (fgets(line, sizeof(line)-1, f) == NULL) {
|
||||
return True;
|
||||
}
|
||||
|
||||
if (line[strlen(line)-1] == '\n')
|
||||
line[strlen(line)-1] = '\0';
|
||||
|
||||
if (line[0] == ' ') {
|
||||
/* We have a SID */
|
||||
|
||||
DOM_SID sid;
|
||||
string_to_sid(&sid, &line[1]);
|
||||
|
||||
if (token == NULL) {
|
||||
DEBUG(0, ("File does not begin with username"));
|
||||
return False;
|
||||
}
|
||||
|
||||
add_sid_to_token(&token->token, &sid);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* And a new user... */
|
||||
|
||||
*num_tokens += 1;
|
||||
*tokens = Realloc(*tokens,
|
||||
*num_tokens *
|
||||
sizeof(struct user_token));
|
||||
if (*tokens == NULL) {
|
||||
DEBUG(0, ("Could not realloc tokens\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
token = &((*tokens)[*num_tokens-1]);
|
||||
|
||||
fstrcpy(token->name, line);
|
||||
token->token.num_sids = 0;
|
||||
token->token.user_sids = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Show the list of all users that have access to a share
|
||||
*/
|
||||
|
||||
static void show_userlist(struct cli_state *cli,
|
||||
TALLOC_CTX *mem_ctx, const char *netname,
|
||||
int num_tokens, struct user_token *tokens)
|
||||
{
|
||||
int fnum;
|
||||
SEC_DESC *share_sd = NULL;
|
||||
SEC_DESC *root_sd = NULL;
|
||||
int i;
|
||||
SRV_SHARE_INFO info;
|
||||
WERROR result;
|
||||
uint16 cnum;
|
||||
|
||||
result = cli_srvsvc_net_share_get_info(cli, mem_ctx, netname,
|
||||
502, &info);
|
||||
|
||||
if (!W_ERROR_IS_OK(result)) {
|
||||
DEBUG(1, ("Coult not query secdesc for share %s\n",
|
||||
netname));
|
||||
return;
|
||||
}
|
||||
|
||||
share_sd = info.share.info502.info_502_str.sd;
|
||||
if (share_sd == NULL) {
|
||||
DEBUG(1, ("Got no secdesc for share %s\n",
|
||||
netname));
|
||||
}
|
||||
|
||||
cnum = cli->cnum;
|
||||
|
||||
if (!cli_send_tconX(cli, netname, "A:", "", 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
fnum = cli_nt_create(cli, "\\", READ_CONTROL_ACCESS);
|
||||
|
||||
if (fnum != -1) {
|
||||
root_sd = cli_query_secdesc(cli, fnum, mem_ctx);
|
||||
}
|
||||
|
||||
for (i=0; i<num_tokens; i++) {
|
||||
uint32 acc_granted;
|
||||
NTSTATUS status;
|
||||
|
||||
if (share_sd != NULL) {
|
||||
if (!se_access_check(share_sd, &tokens[i].token,
|
||||
1, &acc_granted, &status)) {
|
||||
DEBUG(1, ("Could not check share_sd for "
|
||||
"user %s\n",
|
||||
tokens[i].name));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (root_sd == NULL) {
|
||||
d_printf(" %s\n", tokens[i].name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!se_access_check(root_sd, &tokens[i].token,
|
||||
1, &acc_granted, &status)) {
|
||||
DEBUG(1, ("Could not check root_sd for user %s\n",
|
||||
tokens[i].name));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status))
|
||||
continue;
|
||||
|
||||
d_printf(" %s\n", tokens[i].name);
|
||||
}
|
||||
|
||||
if (fnum != -1)
|
||||
cli_close(cli, fnum);
|
||||
cli_tdis(cli);
|
||||
cli->cnum = cnum;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct share_list {
|
||||
int num_shares;
|
||||
char **shares;
|
||||
};
|
||||
|
||||
static void collect_share(const char *name, uint32 m,
|
||||
const char *comment, void *state)
|
||||
{
|
||||
struct share_list *share_list = (struct share_list *)state;
|
||||
|
||||
if (m != STYPE_DISKTREE)
|
||||
return;
|
||||
|
||||
share_list->num_shares += 1;
|
||||
share_list->shares = Realloc(share_list->shares,
|
||||
share_list->num_shares * sizeof(char *));
|
||||
share_list->shares[share_list->num_shares-1] = strdup(name);
|
||||
}
|
||||
|
||||
static void rpc_share_userlist_usage(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* List shares on a remote RPC server, including the security descriptors
|
||||
*
|
||||
* All parameters are provided by the run_rpc_command function, except for
|
||||
* argc, argv which are passes through.
|
||||
*
|
||||
* @param domain_sid The domain sid acquired from the remote server
|
||||
* @param cli A cli_state connected to the server.
|
||||
* @param mem_ctx Talloc context, destoyed on completion of the function.
|
||||
* @param argc Standard main() style argc
|
||||
* @param argv Standard main() style argv. Initial components are already
|
||||
* stripped
|
||||
*
|
||||
* @return Normal NTSTATUS return.
|
||||
**/
|
||||
|
||||
static NTSTATUS
|
||||
rpc_share_allowedusers_internals(const DOM_SID *domain_sid,
|
||||
const char *domain_name,
|
||||
struct cli_state *cli,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
int ret;
|
||||
BOOL r;
|
||||
ENUM_HND hnd;
|
||||
uint32 i;
|
||||
FILE *f;
|
||||
|
||||
struct user_token *tokens = NULL;
|
||||
int num_tokens = 0;
|
||||
|
||||
struct share_list share_list;
|
||||
|
||||
if (argc > 1) {
|
||||
rpc_share_userlist_usage();
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
f = stdin;
|
||||
} else {
|
||||
f = fopen(argv[0], "r");
|
||||
}
|
||||
|
||||
if (f == NULL) {
|
||||
DEBUG(0, ("Could not open userlist: %s\n", strerror(errno)));
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
r = get_user_tokens_from_file(f, &num_tokens, &tokens);
|
||||
|
||||
if (f != stdin)
|
||||
fclose(f);
|
||||
|
||||
if (!r) {
|
||||
DEBUG(0, ("Could not read users from file\n"));
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
for (i=0; i<num_tokens; i++)
|
||||
collect_alias_memberships(&tokens[i].token);
|
||||
|
||||
init_enum_hnd(&hnd, 0);
|
||||
|
||||
share_list.num_shares = 0;
|
||||
share_list.shares = NULL;
|
||||
|
||||
ret = cli_RNetShareEnum(cli, collect_share, &share_list);
|
||||
|
||||
if (ret == -1) {
|
||||
DEBUG(0, ("Error returning browse list: %s\n",
|
||||
cli_errstr(cli)));
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < share_list.num_shares; i++) {
|
||||
char *netname = share_list.shares[i];
|
||||
|
||||
if (netname[strlen(netname)-1] == '$')
|
||||
continue;
|
||||
|
||||
d_printf("%s\n", netname);
|
||||
|
||||
show_userlist(cli, mem_ctx, netname,
|
||||
num_tokens, tokens);
|
||||
}
|
||||
done:
|
||||
for (i=0; i<num_tokens; i++) {
|
||||
free_user_token(&tokens[i].token);
|
||||
}
|
||||
SAFE_FREE(tokens);
|
||||
SAFE_FREE(share_list.shares);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_share_allowedusers(int argc, const char **argv)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = run_rpc_command(NULL, PI_SAMR, 0,
|
||||
rpc_aliaslist_internals,
|
||||
argc, argv);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
result = run_rpc_command(NULL, PI_LSARPC, 0,
|
||||
rpc_aliaslist_dump,
|
||||
argc, argv);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
return run_rpc_command(NULL, PI_SRVSVC, 0,
|
||||
rpc_share_allowedusers_internals,
|
||||
argc, argv);
|
||||
}
|
||||
|
||||
int net_usersidlist(int argc, const char **argv)
|
||||
{
|
||||
int num_tokens = 0;
|
||||
struct user_token *tokens = NULL;
|
||||
int i;
|
||||
|
||||
if (argc != 0) {
|
||||
net_usersidlist_usage(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!get_user_tokens(&num_tokens, &tokens)) {
|
||||
DEBUG(0, ("Could not get the user/sid list\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i=0; i<num_tokens; i++) {
|
||||
dump_user_token(&tokens[i]);
|
||||
free_user_token(&tokens[i].token);
|
||||
}
|
||||
|
||||
SAFE_FREE(tokens);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int net_usersidlist_usage(int argc, const char **argv)
|
||||
{
|
||||
d_printf("net usersidlist\n"
|
||||
"\tprints out a list of all users the running winbind knows\n"
|
||||
"\tabout, together with all their SIDs. This is used as\n"
|
||||
"\tinput to the 'net rpc share allowedusers' command.\n\n");
|
||||
|
||||
net_common_flags_usage(argc, argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'net rpc share' entrypoint.
|
||||
* @param argc Standard main() style argc
|
||||
@ -2985,6 +3763,7 @@ int net_rpc_share(int argc, const char **argv)
|
||||
struct functable func[] = {
|
||||
{"add", rpc_share_add},
|
||||
{"delete", rpc_share_delete},
|
||||
{"allowedusers", rpc_share_allowedusers},
|
||||
{"migrate", rpc_share_migrate},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user