diff options
-rw-r--r-- | source3/include/ntdomain.h | 3 | ||||
-rw-r--r-- | source3/include/proto.h | 18 | ||||
-rw-r--r-- | source3/include/rpc_samr.h | 32 | ||||
-rw-r--r-- | source3/rpc_client/cli_samr.c | 102 | ||||
-rw-r--r-- | source3/rpc_parse/parse_samr.c | 160 | ||||
-rw-r--r-- | source3/rpcclient/cmd_samr.c | 137 | ||||
-rw-r--r-- | source3/rpcclient/rpcclient.c | 6 |
7 files changed, 457 insertions, 1 deletions
diff --git a/source3/include/ntdomain.h b/source3/include/ntdomain.h index 7f588744752..4f6cc85905e 100644 --- a/source3/include/ntdomain.h +++ b/source3/include/ntdomain.h @@ -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)\ diff --git a/source3/include/proto.h b/source3/include/proto.h index df05f2d7be1..ff553314007 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -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 */ diff --git a/source3/include/rpc_samr.h b/source3/include/rpc_samr.h index 58246488a1a..850e3a8b948 100644 --- a/source3/include/rpc_samr.h +++ b/source3/include/rpc_samr.h @@ -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 { diff --git a/source3/rpc_client/cli_samr.c b/source3/rpc_client/cli_samr.c index 94865e4d3c9..d16098247f4 100644 --- a/source3/rpc_client/cli_samr.c +++ b/source3/rpc_client/cli_samr.c @@ -616,6 +616,108 @@ BOOL samr_query_dom_info(struct cli_state *cli, uint16 fnum, } /**************************************************************************** +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 ****************************************************************************/ uint32 samr_enum_dom_groups(struct cli_state *cli, uint16 fnum, diff --git a/source3/rpc_parse/parse_samr.c b/source3/rpc_parse/parse_samr.c index 2cd796f874b..ab45152db0e 100644 --- a/source3/rpc_parse/parse_samr.c +++ b/source3/rpc_parse/parse_samr.c @@ -2756,6 +2756,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. ********************************************************************/ BOOL make_samr_q_enum_dom_groups(SAMR_Q_ENUM_DOM_GROUPS *q_e, POLICY_HND *pol, diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c index 1327099aac2..e9314bada65 100644 --- a/source3/rpcclient/cmd_samr.c +++ b/source3/rpcclient/cmd_samr.c @@ -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) @@ -757,6 +762,95 @@ static BOOL req_groupmem_info(struct cli_state *cli, uint16 fnum, } /**************************************************************************** +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. ****************************************************************************/ uint32 msrpc_sam_enum_groups(struct cli_state *cli, @@ -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); + } +} + diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c index 06e6d0c089b..f359045baeb 100644 --- a/source3/rpcclient/rpcclient.c +++ b/source3/rpcclient/rpcclient.c @@ -484,6 +484,12 @@ commands[] = {COMPL_NONE, COMPL_NONE} }, { + "enumdomains", + cmd_sam_enum_domains, + "SAM Domains Database Query (experimental!)", + {COMPL_NONE, COMPL_NONE} + }, + { "enumgroups", cmd_sam_enum_groups, "SAM Group Database Query (experimental!)", |