mirror of
https://github.com/samba-team/samba.git
synced 2025-01-12 09:18:10 +03:00
added rpcclient "enumdomains" command. enumerates names of domains
for which a PDC is responsible. typical answers are: <Name of Domain> plus <Builtin>. against a hierarchical, down-level-compatible NT5 PDC, there's likely to be more than these two entries!!!!!
This commit is contained in:
parent
25c70e3c98
commit
3146aa6b60
@ -170,6 +170,9 @@ struct acct_info
|
||||
uint32, const uint32*, char *const *const,\
|
||||
uint32*const)
|
||||
|
||||
#define DOMAIN_FN(fn)\
|
||||
void (*fn)(const char*)
|
||||
|
||||
#define USER_FN(fn)\
|
||||
void (*fn)(const char*, const DOM_SID*, uint32, const char*)
|
||||
#define USER_INFO_FN(fn)\
|
||||
|
@ -1952,6 +1952,11 @@ BOOL samr_unknown_38(struct cli_state *cli, uint16 fnum, char *srv_name);
|
||||
BOOL samr_query_dom_info(struct cli_state *cli, uint16 fnum,
|
||||
POLICY_HND *domain_pol, uint16 switch_value,
|
||||
SAM_UNK_CTR *ctr);
|
||||
uint32 samr_enum_domains(struct cli_state *cli, uint16 fnum,
|
||||
POLICY_HND *pol,
|
||||
uint32 *start_idx, uint32 size,
|
||||
struct acct_info **sam,
|
||||
uint32 *num_sam_domains);
|
||||
uint32 samr_enum_dom_groups(struct cli_state *cli, uint16 fnum,
|
||||
POLICY_HND *pol,
|
||||
uint32 *start_idx, uint32 size,
|
||||
@ -2703,6 +2708,13 @@ BOOL samr_io_q_query_usergroups(char *desc, SAMR_Q_QUERY_USERGROUPS *q_u, prs_s
|
||||
BOOL make_samr_r_query_usergroups(SAMR_R_QUERY_USERGROUPS *r_u,
|
||||
uint32 num_gids, DOM_GID *gid, uint32 status);
|
||||
BOOL samr_io_r_query_usergroups(char *desc, SAMR_R_QUERY_USERGROUPS *r_u, prs_struct *ps, int depth);
|
||||
BOOL make_samr_q_enum_domains(SAMR_Q_ENUM_DOMAINS *q_e, POLICY_HND *pol,
|
||||
uint32 start_idx, uint32 size);
|
||||
BOOL samr_io_q_enum_domains(char *desc, SAMR_Q_ENUM_DOMAINS *q_e, prs_struct *ps, int depth);
|
||||
BOOL make_samr_r_enum_domains(SAMR_R_ENUM_DOMAINS *r_u,
|
||||
uint32 next_idx,
|
||||
uint32 num_sam_entries, char **doms, uint32 status);
|
||||
BOOL samr_io_r_enum_domains(char *desc, SAMR_R_ENUM_DOMAINS *r_u, prs_struct *ps, int depth);
|
||||
BOOL make_samr_q_enum_dom_groups(SAMR_Q_ENUM_DOM_GROUPS *q_e, POLICY_HND *pol,
|
||||
uint32 start_idx, uint32 size);
|
||||
BOOL samr_io_q_enum_dom_groups(char *desc, SAMR_Q_ENUM_DOM_GROUPS *q_e, prs_struct *ps, int depth);
|
||||
@ -3428,6 +3440,11 @@ BOOL sam_query_groupmem(struct cli_state *cli, uint16 fnum,
|
||||
uint32 **rid_mem,
|
||||
char ***name,
|
||||
uint32 **type);
|
||||
uint32 msrpc_sam_enum_domains(struct cli_state *cli,
|
||||
const char* srv_name,
|
||||
struct acct_info **sam,
|
||||
uint32 *num_sam_entries,
|
||||
DOMAIN_FN(dom_fn));
|
||||
uint32 msrpc_sam_enum_groups(struct cli_state *cli,
|
||||
const char* domain,
|
||||
const DOM_SID *sid1,
|
||||
@ -3469,6 +3486,7 @@ void cmd_sam_query_aliasmem(struct client_info *info);
|
||||
void cmd_sam_query_alias(struct client_info *info);
|
||||
void cmd_sam_enum_aliases(struct client_info *info);
|
||||
void cmd_sam_enum_groups(struct client_info *info);
|
||||
void cmd_sam_enum_domains(struct client_info *info);
|
||||
|
||||
/*The following definitions come from rpcclient/cmd_spoolss.c */
|
||||
|
||||
|
@ -83,6 +83,7 @@ SamrTestPrivateFunctionsUser
|
||||
#define SAMR_QUERY_SEC_OBJECT 0x03
|
||||
#define SAMR_LOOKUP_DOMAIN 0x05
|
||||
#define SAMR_OPEN_DOMAIN 0x07
|
||||
#define SAMR_ENUM_DOMAINS 0x06
|
||||
|
||||
#define SAMR_QUERY_DOMAIN_INFO 0x08
|
||||
|
||||
@ -586,7 +587,6 @@ typedef struct r_samr_open_domain_info
|
||||
|
||||
} SAMR_R_OPEN_DOMAIN;
|
||||
|
||||
|
||||
#define MAX_SAM_ENTRIES 250
|
||||
|
||||
typedef struct samr_entry_info
|
||||
@ -597,6 +597,36 @@ typedef struct samr_entry_info
|
||||
} SAM_ENTRY;
|
||||
|
||||
|
||||
/* SAMR_Q_ENUM_DOMAINS - SAM rids and names */
|
||||
typedef struct q_samr_enum_domains_info
|
||||
{
|
||||
POLICY_HND pol; /* policy handle */
|
||||
|
||||
uint32 start_idx; /* enumeration handle */
|
||||
uint32 max_size; /* 0x0000 ffff */
|
||||
|
||||
} SAMR_Q_ENUM_DOMAINS;
|
||||
|
||||
/* SAMR_R_ENUM_DOMAINS - SAM rids and Domain names */
|
||||
typedef struct r_samr_enum_domains_info
|
||||
{
|
||||
uint32 next_idx; /* next starting index required for enum */
|
||||
uint32 ptr_entries1;
|
||||
|
||||
uint32 num_entries2;
|
||||
uint32 ptr_entries2;
|
||||
|
||||
uint32 num_entries3;
|
||||
|
||||
SAM_ENTRY *sam;
|
||||
UNISTR2 *uni_dom_name;
|
||||
|
||||
uint32 num_entries4;
|
||||
|
||||
uint32 status;
|
||||
|
||||
} SAMR_R_ENUM_DOMAINS;
|
||||
|
||||
/* SAMR_Q_ENUM_DOM_USERS - SAM rids and names */
|
||||
typedef struct q_samr_enum_dom_users_info
|
||||
{
|
||||
|
@ -615,6 +615,108 @@ BOOL samr_query_dom_info(struct cli_state *cli, uint16 fnum,
|
||||
return valid_un8;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
do a SAMR enumerate Domains
|
||||
****************************************************************************/
|
||||
uint32 samr_enum_domains(struct cli_state *cli, uint16 fnum,
|
||||
POLICY_HND *pol,
|
||||
uint32 *start_idx, uint32 size,
|
||||
struct acct_info **sam,
|
||||
uint32 *num_sam_domains)
|
||||
{
|
||||
uint32 status = 0x0;
|
||||
prs_struct data;
|
||||
prs_struct rdata;
|
||||
|
||||
SAMR_Q_ENUM_DOMAINS q_e;
|
||||
|
||||
DEBUG(4,("SAMR Enum SAM DB max size:%x\n", size));
|
||||
|
||||
if (pol == NULL || num_sam_domains == NULL || sam == NULL)
|
||||
{
|
||||
return NT_STATUS_INVALID_PARAMETER | 0xC0000000;
|
||||
}
|
||||
|
||||
/* create and send a MSRPC command with api SAMR_ENUM_DOMAINS */
|
||||
|
||||
prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
|
||||
prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
|
||||
|
||||
/* store the parameters */
|
||||
make_samr_q_enum_domains(&q_e, pol, *start_idx, size);
|
||||
|
||||
/* turn parameters into data stream */
|
||||
samr_io_q_enum_domains("", &q_e, &data, 0);
|
||||
|
||||
/* send the data on \PIPE\ */
|
||||
if (rpc_api_pipe_req(cli, fnum, SAMR_ENUM_DOMAINS, &data, &rdata))
|
||||
{
|
||||
SAMR_R_ENUM_DOMAINS r_e;
|
||||
BOOL p;
|
||||
|
||||
samr_io_r_enum_domains("", &r_e, &rdata, 0);
|
||||
|
||||
status = r_e.status;
|
||||
p = rdata.offset != 0;
|
||||
if (p && r_e.status != 0)
|
||||
{
|
||||
/* report error code */
|
||||
DEBUG(4,("SAMR_R_ENUM_DOMAINS: %s\n", get_nt_error_msg(r_e.status)));
|
||||
p = (r_e.status == STATUS_MORE_ENTRIES);
|
||||
}
|
||||
|
||||
if (p)
|
||||
{
|
||||
uint32 i = (*num_sam_domains);
|
||||
uint32 j = 0;
|
||||
uint32 name_idx = 0;
|
||||
|
||||
(*num_sam_domains) += r_e.num_entries2;
|
||||
(*sam) = (struct acct_info*) Realloc((*sam),
|
||||
sizeof(struct acct_info) * (*num_sam_domains));
|
||||
|
||||
if ((*sam) == NULL)
|
||||
{
|
||||
(*num_sam_domains) = 0;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
for (j = 0; i < (*num_sam_domains) && j < r_e.num_entries2; j++, i++)
|
||||
{
|
||||
(*sam)[i].rid = r_e.sam[j].rid;
|
||||
(*sam)[i].acct_name[0] = 0;
|
||||
(*sam)[i].acct_desc[0] = 0;
|
||||
if (r_e.sam[j].hdr_name.buffer)
|
||||
{
|
||||
unistr2_to_ascii((*sam)[i].acct_name, &r_e.uni_dom_name[name_idx], sizeof((*sam)[i].acct_name)-1);
|
||||
name_idx++;
|
||||
}
|
||||
DEBUG(5,("samr_enum_domains: idx: %4d rid: %8x acct: %s\n",
|
||||
i, (*sam)[i].rid, (*sam)[i].acct_name));
|
||||
}
|
||||
(*start_idx) = r_e.next_idx;
|
||||
}
|
||||
else if (status == 0x0)
|
||||
{
|
||||
status = NT_STATUS_INVALID_PARAMETER | 0xC0000000;
|
||||
}
|
||||
|
||||
if (r_e.sam != NULL)
|
||||
{
|
||||
free(r_e.sam);
|
||||
}
|
||||
if (r_e.uni_dom_name != NULL)
|
||||
{
|
||||
free(r_e.uni_dom_name);
|
||||
}
|
||||
}
|
||||
|
||||
prs_mem_free(&data );
|
||||
prs_mem_free(&rdata );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
do a SAMR enumerate groups
|
||||
****************************************************************************/
|
||||
|
@ -2755,6 +2755,166 @@ BOOL samr_io_r_query_usergroups(char *desc, SAMR_R_QUERY_USERGROUPS *r_u, prs_s
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
makes a SAMR_Q_ENUM_DOMAINS structure.
|
||||
********************************************************************/
|
||||
BOOL make_samr_q_enum_domains(SAMR_Q_ENUM_DOMAINS *q_e, POLICY_HND *pol,
|
||||
uint32 start_idx, uint32 size)
|
||||
{
|
||||
if (q_e == NULL || pol == NULL) return False;
|
||||
|
||||
DEBUG(5,("make_samr_q_enum_domains\n"));
|
||||
|
||||
memcpy(&(q_e->pol), pol, sizeof(*pol));
|
||||
|
||||
q_e->start_idx = start_idx;
|
||||
q_e->max_size = size;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
reads or writes a structure.
|
||||
********************************************************************/
|
||||
BOOL samr_io_q_enum_domains(char *desc, SAMR_Q_ENUM_DOMAINS *q_e, prs_struct *ps, int depth)
|
||||
{
|
||||
if (q_e == NULL) return False;
|
||||
|
||||
prs_debug(ps, depth, desc, "samr_io_q_enum_domains");
|
||||
depth++;
|
||||
|
||||
prs_align(ps);
|
||||
|
||||
smb_io_pol_hnd("pol", &(q_e->pol), ps, depth);
|
||||
prs_align(ps);
|
||||
|
||||
prs_uint32("start_idx", ps, depth, &(q_e->start_idx));
|
||||
prs_uint32("max_size ", ps, depth, &(q_e->max_size ));
|
||||
|
||||
prs_align(ps);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
makes a SAMR_R_ENUM_DOMAINS structure.
|
||||
********************************************************************/
|
||||
BOOL make_samr_r_enum_domains(SAMR_R_ENUM_DOMAINS *r_u,
|
||||
uint32 next_idx,
|
||||
uint32 num_sam_entries, char **doms, uint32 status)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
if (r_u == NULL) return False;
|
||||
|
||||
DEBUG(5,("make_samr_r_enum_domains\n"));
|
||||
|
||||
r_u->next_idx = next_idx;
|
||||
r_u->sam = NULL;
|
||||
r_u->uni_dom_name = NULL;
|
||||
|
||||
if (num_sam_entries != 0)
|
||||
{
|
||||
r_u->ptr_entries1 = 1;
|
||||
r_u->ptr_entries2 = 1;
|
||||
r_u->num_entries2 = num_sam_entries;
|
||||
r_u->num_entries3 = num_sam_entries;
|
||||
|
||||
r_u->sam = (SAM_ENTRY*)Realloc(NULL, r_u->num_entries2 * sizeof(r_u->sam[0]));
|
||||
r_u->uni_dom_name = (UNISTR2*)Realloc(NULL, r_u->num_entries2 * sizeof(r_u->uni_dom_name[0]));
|
||||
|
||||
if (r_u->sam == NULL || r_u->uni_dom_name == NULL)
|
||||
{
|
||||
DEBUG(0,("NULL pointers in SAMR_R_ENUM_DOMAINS\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_sam_entries; i++)
|
||||
{
|
||||
int acct_name_len = doms[i] != NULL ? strlen(doms[i]) : 0;
|
||||
|
||||
make_sam_entry(&(r_u->sam[i]), acct_name_len, 0);
|
||||
make_unistr2(&(r_u->uni_dom_name[i]), doms[i], acct_name_len);
|
||||
}
|
||||
|
||||
r_u->num_entries4 = num_sam_entries;
|
||||
}
|
||||
else
|
||||
{
|
||||
r_u->ptr_entries1 = 0;
|
||||
r_u->num_entries2 = num_sam_entries;
|
||||
r_u->ptr_entries2 = 1;
|
||||
}
|
||||
|
||||
r_u->status = status;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
reads or writes a structure.
|
||||
********************************************************************/
|
||||
BOOL samr_io_r_enum_domains(char *desc, SAMR_R_ENUM_DOMAINS *r_u, prs_struct *ps, int depth)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
if (r_u == NULL) return False;
|
||||
|
||||
prs_debug(ps, depth, desc, "samr_io_r_enum_domains");
|
||||
depth++;
|
||||
|
||||
r_u->sam = NULL;
|
||||
r_u->uni_dom_name = NULL;
|
||||
|
||||
prs_align(ps);
|
||||
|
||||
prs_uint32("next_idx ", ps, depth, &(r_u->next_idx ));
|
||||
prs_uint32("ptr_entries1", ps, depth, &(r_u->ptr_entries1));
|
||||
|
||||
if (r_u->ptr_entries1 != 0)
|
||||
{
|
||||
prs_uint32("num_entries2", ps, depth, &(r_u->num_entries2));
|
||||
prs_uint32("ptr_entries2", ps, depth, &(r_u->ptr_entries2));
|
||||
prs_uint32("num_entries3", ps, depth, &(r_u->num_entries3));
|
||||
|
||||
if (ps->io)
|
||||
{
|
||||
r_u->sam = (SAM_ENTRY*)Realloc(NULL, r_u->num_entries2 * sizeof(r_u->sam[0]));
|
||||
r_u->uni_dom_name = (UNISTR2*)Realloc(NULL, r_u->num_entries2 * sizeof(r_u->uni_dom_name[0]));
|
||||
}
|
||||
|
||||
if ((r_u->sam == NULL || r_u->uni_dom_name == NULL) && r_u->num_entries2 != 0)
|
||||
{
|
||||
DEBUG(0,("NULL pointers in SAMR_R_ENUM_DOMAINS\n"));
|
||||
r_u->num_entries4 = 0;
|
||||
r_u->status = 0xC0000000|NT_STATUS_MEMORY_NOT_ALLOCATED;
|
||||
return False;
|
||||
}
|
||||
|
||||
for (i = 0; i < r_u->num_entries2; i++)
|
||||
{
|
||||
prs_grow(ps);
|
||||
sam_io_sam_entry("", &(r_u->sam[i]), ps, depth);
|
||||
}
|
||||
|
||||
for (i = 0; i < r_u->num_entries2; i++)
|
||||
{
|
||||
prs_grow(ps);
|
||||
smb_io_unistr2("", &(r_u->uni_dom_name[i]), r_u->sam[i].hdr_name.buffer, ps, depth);
|
||||
}
|
||||
|
||||
prs_align(ps);
|
||||
|
||||
}
|
||||
|
||||
prs_uint32("num_entries4", ps, depth, &(r_u->num_entries4));
|
||||
prs_uint32("status", ps, depth, &(r_u->status));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
makes a SAMR_Q_ENUM_DOM_GROUPS structure.
|
||||
********************************************************************/
|
||||
|
@ -37,6 +37,11 @@ extern struct cli_state *smb_cli;
|
||||
|
||||
extern FILE* out_hnd;
|
||||
|
||||
static void sam_display_domain(const char *domain)
|
||||
{
|
||||
report(out_hnd, "Domain Name: %s\n", domain);
|
||||
}
|
||||
|
||||
static void sam_display_alias_info(const char *domain, const DOM_SID *sid,
|
||||
uint32 alias_rid,
|
||||
ALIAS_INFO_CTR *const ctr)
|
||||
@ -756,6 +761,95 @@ static BOOL req_groupmem_info(struct cli_state *cli, uint16 fnum,
|
||||
return False;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
SAM Domains query.
|
||||
DOMAIN_INFO_FN(dom_inf_fn),
|
||||
DOMAIN_MEM_FN(dom_mem_fn))
|
||||
****************************************************************************/
|
||||
uint32 msrpc_sam_enum_domains(struct cli_state *cli,
|
||||
const char* srv_name,
|
||||
struct acct_info **sam,
|
||||
uint32 *num_sam_entries,
|
||||
DOMAIN_FN(dom_fn))
|
||||
{
|
||||
uint16 fnum;
|
||||
BOOL res = True;
|
||||
uint32 ace_perms = 0x02000000; /* access control permissions. */
|
||||
POLICY_HND sam_pol;
|
||||
uint32 status;
|
||||
|
||||
/* open SAMR session. negotiate credentials */
|
||||
res = res ? cli_nt_session_open(cli, PIPE_SAMR, &fnum) : False;
|
||||
|
||||
/* establish a connection. */
|
||||
res = res ? samr_connect(cli, fnum,
|
||||
srv_name, ace_perms,
|
||||
&sam_pol) : False;
|
||||
|
||||
(*sam) = NULL;
|
||||
(*num_sam_entries) = 0;
|
||||
|
||||
if (res)
|
||||
{
|
||||
uint32 domain_idx;
|
||||
uint32 start_idx = 0;
|
||||
/* read some domains */
|
||||
do
|
||||
{
|
||||
status = samr_enum_domains(cli, fnum,
|
||||
&sam_pol,
|
||||
&start_idx, 0x10000,
|
||||
sam, num_sam_entries);
|
||||
|
||||
} while (status == STATUS_MORE_ENTRIES);
|
||||
|
||||
if ((*num_sam_entries) == 0)
|
||||
{
|
||||
report(out_hnd, "No domains\n");
|
||||
}
|
||||
|
||||
for (domain_idx = 0; domain_idx < (*num_sam_entries); domain_idx++)
|
||||
{
|
||||
char *domain_name = (*sam)[domain_idx].acct_name;
|
||||
|
||||
if (dom_fn != NULL)
|
||||
{
|
||||
dom_fn(domain_name);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (dom_inf_fn != NULL)
|
||||
{
|
||||
query_domaininfo(cli, fnum, &sam_pol,
|
||||
domain_name,
|
||||
dom_inf_fn);
|
||||
}
|
||||
if (dom_mem_fn != NULL)
|
||||
{
|
||||
req_domainmem_info(cli, fnum, &sam_pol,
|
||||
domain_name,
|
||||
dom_mem_fn);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
res = res ? samr_close(cli, fnum, &sam_pol) : False;
|
||||
|
||||
/* close the session */
|
||||
cli_nt_session_close(cli, fnum);
|
||||
|
||||
if (res)
|
||||
{
|
||||
DEBUG(5,("msrpc_sam_enum_domains: succeeded\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG(5,("msrpc_sam_enum_domains: failed\n"));
|
||||
}
|
||||
return (*num_sam_entries);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
SAM groups query.
|
||||
****************************************************************************/
|
||||
@ -3133,3 +3227,46 @@ void cmd_sam_enum_groups(struct client_info *info)
|
||||
free(sam);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
experimental SAM domains enum.
|
||||
****************************************************************************/
|
||||
void cmd_sam_enum_domains(struct client_info *info)
|
||||
{
|
||||
BOOL request_domain_info = False;
|
||||
fstring tmp;
|
||||
int i;
|
||||
struct acct_info *sam = NULL;
|
||||
uint32 num_sam_entries = 0;
|
||||
|
||||
fstring srv_name;
|
||||
|
||||
fstrcpy(srv_name, "\\\\");
|
||||
fstrcat(srv_name, info->dest_host);
|
||||
strupper(srv_name);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
/* a bad way to do token parsing... */
|
||||
if (next_token(NULL, tmp, NULL, sizeof(tmp)))
|
||||
{
|
||||
request_domain_info |= strequal(tmp, "-i");
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
report(out_hnd, "SAM Enumerate Domains\n");
|
||||
|
||||
msrpc_sam_enum_domains(smb_cli, srv_name,
|
||||
&sam, &num_sam_entries,
|
||||
sam_display_domain);
|
||||
|
||||
if (sam != NULL)
|
||||
{
|
||||
free(sam);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,6 +483,12 @@ commands[] =
|
||||
"SAM Aliases Database Query (experimental!)",
|
||||
{COMPL_NONE, COMPL_NONE}
|
||||
},
|
||||
{
|
||||
"enumdomains",
|
||||
cmd_sam_enum_domains,
|
||||
"SAM Domains Database Query (experimental!)",
|
||||
{COMPL_NONE, COMPL_NONE}
|
||||
},
|
||||
{
|
||||
"enumgroups",
|
||||
cmd_sam_enum_groups,
|
||||
|
Loading…
Reference in New Issue
Block a user