diff options
-rw-r--r-- | source3/include/rpc_netlogon.h | 34 | ||||
-rw-r--r-- | source3/lib/util_unistr.c | 28 | ||||
-rw-r--r-- | source3/rpc_client/cli_netlogon.c | 123 | ||||
-rw-r--r-- | source3/rpc_parse/parse_net.c | 236 | ||||
-rw-r--r-- | source3/rpcclient/cmd_netlogon.c | 30 |
5 files changed, 451 insertions, 0 deletions
diff --git a/source3/include/rpc_netlogon.h b/source3/include/rpc_netlogon.h index c73cd03f10..bc4c41cd1f 100644 --- a/source3/include/rpc_netlogon.h +++ b/source3/include/rpc_netlogon.h @@ -38,6 +38,7 @@ #define NET_LOGON_CTRL2 0x0e #define NET_SAM_SYNC 0x10 #define NET_TRUST_DOM_LIST 0x13 +#define NET_DSR_GETDCNAME 0x14 #define NET_AUTH3 0x1a /* Secure Channel types. used in NetrServerAuthenticate negotiation */ @@ -934,4 +935,37 @@ typedef struct net_r_sam_deltas_info { NTSTATUS status; } NET_R_SAM_DELTAS; +/* NET_Q_DSR_GETDCNAME - Ask a DC for a trusted DC name and its address */ +typedef struct net_q_dsr_getdcname { + uint32 ptr_server_unc; + UNISTR2 uni_server_unc; + uint32 ptr_domain_name; + UNISTR2 uni_domain_name; + uint32 ptr_domain_guid; + struct uuid *domain_guid; + uint32 ptr_site_guid; + struct uuid *site_guid; + uint32_t flags; +} NET_Q_DSR_GETDCNAME; + +/* NET_R_DSR_GETDCNAME - Ask a DC for a trusted DC name and its address */ +typedef struct net_r_dsr_getdcname { + uint32 ptr_dc_unc; + UNISTR2 uni_dc_unc; + uint32 ptr_dc_address; + UNISTR2 uni_dc_address; + int32 dc_address_type; + struct uuid domain_guid; + uint32 ptr_domain_name; + UNISTR2 uni_domain_name; + uint32 ptr_forest_name; + UNISTR2 uni_forest_name; + uint32 dc_flags; + uint32 ptr_dc_site_name; + UNISTR2 uni_dc_site_name; + uint32 ptr_client_site_name; + UNISTR2 uni_client_site_name; + WERROR result; +} NET_R_DSR_GETDCNAME; + #endif /* _RPC_NETLOGON_H */ diff --git a/source3/lib/util_unistr.c b/source3/lib/util_unistr.c index d80bb2ce52..b979745d36 100644 --- a/source3/lib/util_unistr.c +++ b/source3/lib/util_unistr.c @@ -265,6 +265,34 @@ int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src) src->uni_str_len * 2, 0); } +/* Helper function to return a talloc'ed string. I have implemented it with a + * copy because I don't really know how pull_ucs2 and friends calculate the + * target size. If this turns out to be a major bottleneck someone with deeper + * multi-byte knowledge needs to revisit this. + * My (VL) use is dsr_getdcname, which returns 6 strings, the alternative would + * have been to manually talloc_strdup them in rpc_client/cli_netlogon.c. + */ + +size_t rpcstr_pull_unistr2_talloc(TALLOC_CTX *mem_ctx, char **dest, + UNISTR2 *src) +{ + pstring tmp; + size_t result; + + result = pull_ucs2(NULL, tmp, src->buffer, sizeof(tmp), + src->uni_str_len * 2, 0); + if (result < 0) { + return result; + } + + *dest = talloc_strdup(mem_ctx, tmp); + if (*dest == NULL) { + return -1; + } + + return result; +} + /* Converts a string from internal samba format to unicode */ diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index af0062f2b3..f12f7d09fa 100644 --- a/source3/rpc_client/cli_netlogon.c +++ b/source3/rpc_client/cli_netlogon.c @@ -417,6 +417,129 @@ NTSTATUS rpccli_netlogon_getdcname(struct rpc_pipe_client *cli, return result; } +/* Dsr_GetDCName */ + +WERROR rpccli_netlogon_dsr_getdcname(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + const char *server_name, + const char *domain_name, + struct uuid *domain_guid, + struct uuid *site_guid, + uint32_t flags, + char **dc_unc, char **dc_address, + int32 *dc_address_type, + struct uuid *domain_guid_out, + char **domain_name_out, + char **forest_name, + uint32 *dc_flags, + char **dc_site_name, + char **client_site_name) +{ + prs_struct qbuf, rbuf; + NET_Q_DSR_GETDCNAME q; + NET_R_DSR_GETDCNAME r; + char *tmp_str; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + /* Initialize input parameters */ + + tmp_str = talloc_asprintf(mem_ctx, "\\\\%s", server_name); + if (tmp_str == NULL) { + return WERR_NOMEM; + } + + init_net_q_dsr_getdcname(&q, tmp_str, domain_name, domain_guid, + site_guid, flags); + + /* Marshall data and send request */ + + CLI_DO_RPC_WERR(cli, mem_ctx, PI_NETLOGON, NET_DSR_GETDCNAME, + q, r, + qbuf, rbuf, + net_io_q_dsr_getdcname, + net_io_r_dsr_getdcname, + WERR_GENERAL_FAILURE); + + if (!W_ERROR_IS_OK(r.result)) { + return r.result; + } + + if (dc_unc != NULL) { + char *tmp; + if (rpcstr_pull_unistr2_talloc(mem_ctx, &tmp, + &r.uni_dc_unc) < 0) { + return WERR_GENERAL_FAILURE; + } + if (*tmp == '\\') tmp += 1; + if (*tmp == '\\') tmp += 1; + + /* We have to talloc_strdup, otherwise a talloc_steal would + fail */ + *dc_unc = talloc_strdup(mem_ctx, tmp); + if (*dc_unc == NULL) { + return WERR_NOMEM; + } + } + + if (dc_address != NULL) { + char *tmp; + if (rpcstr_pull_unistr2_talloc(mem_ctx, &tmp, + &r.uni_dc_address) < 0) { + return WERR_GENERAL_FAILURE; + } + if (*tmp == '\\') tmp += 1; + if (*tmp == '\\') tmp += 1; + + /* We have to talloc_strdup, otherwise a talloc_steal would + fail */ + *dc_address = talloc_strdup(mem_ctx, tmp); + if (*dc_address == NULL) { + return WERR_NOMEM; + } + } + + if (dc_address_type != NULL) { + *dc_address_type = r.dc_address_type; + } + + if (domain_guid_out != NULL) { + *domain_guid_out = r.domain_guid; + } + + if ((domain_name_out != NULL) && + (rpcstr_pull_unistr2_talloc(mem_ctx, domain_name_out, + &r.uni_domain_name) < 1)) { + return WERR_GENERAL_FAILURE; + } + + if ((forest_name != NULL) && + (rpcstr_pull_unistr2_talloc(mem_ctx, forest_name, + &r.uni_forest_name) < 1)) { + return WERR_GENERAL_FAILURE; + } + + if (dc_flags != NULL) { + *dc_flags = r.dc_flags; + } + + if ((dc_site_name != NULL) && + (rpcstr_pull_unistr2_talloc(mem_ctx, dc_site_name, + &r.uni_dc_site_name) < 1)) { + return WERR_GENERAL_FAILURE; + } + + if ((client_site_name != NULL) && + (rpcstr_pull_unistr2_talloc(mem_ctx, client_site_name, + &r.uni_client_site_name) < 1)) { + return WERR_GENERAL_FAILURE; + } + + return WERR_OK; +} + + /* Sam synchronisation */ NTSTATUS rpccli_netlogon_sam_sync(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, diff --git a/source3/rpc_parse/parse_net.c b/source3/rpc_parse/parse_net.c index a32edd4384..3732ab3a72 100644 --- a/source3/rpc_parse/parse_net.c +++ b/source3/rpc_parse/parse_net.c @@ -3153,3 +3153,239 @@ BOOL net_io_r_sam_deltas(const char *desc, return True; } + +/******************************************************************* + Inits a NET_Q_DSR_GETDCNAME structure. +********************************************************************/ + +void init_net_q_dsr_getdcname(NET_Q_DSR_GETDCNAME *r_t, const char *server_unc, + const char *domain_name, + struct uuid *domain_guid, + struct uuid *site_guid, + uint32_t flags) +{ + DEBUG(5, ("init_net_q_dsr_getdcname\n")); + + r_t->ptr_server_unc = (server_unc != NULL); + init_unistr2(&r_t->uni_server_unc, server_unc, UNI_STR_TERMINATE); + + r_t->ptr_domain_name = (domain_name != NULL); + init_unistr2(&r_t->uni_domain_name, domain_name, UNI_STR_TERMINATE); + + r_t->ptr_domain_guid = (domain_guid != NULL); + r_t->domain_guid = domain_guid; + + r_t->ptr_site_guid = (site_guid != NULL); + r_t->site_guid = site_guid; + + r_t->flags = flags; +} + +/******************************************************************* + Reads or writes an NET_Q_DSR_GETDCNAME structure. +********************************************************************/ + +BOOL net_io_q_dsr_getdcname(const char *desc, NET_Q_DSR_GETDCNAME *r_t, + prs_struct *ps, int depth) +{ + if (r_t == NULL) + return False; + + prs_debug(ps, depth, desc, "net_io_q_dsr_getdcname"); + depth++; + + if (!prs_uint32("ptr_server_unc", ps, depth, &r_t->ptr_server_unc)) + return False; + + if (!smb_io_unistr2("server_unc", &r_t->uni_server_unc, + r_t->ptr_server_unc, ps, depth)) + return False; + + if (!prs_align(ps)) + return False; + + if (!prs_uint32("ptr_domain_name", ps, depth, &r_t->ptr_domain_name)) + return False; + + if (!smb_io_unistr2("domain_name", &r_t->uni_domain_name, + r_t->ptr_domain_name, ps, depth)) + return False; + + if (!prs_align(ps)) + return False; + + if (!prs_uint32("ptr_domain_guid", ps, depth, &r_t->ptr_domain_guid)) + return False; + + if (UNMARSHALLING(ps) && (r_t->ptr_domain_guid)) { + r_t->domain_guid = PRS_ALLOC_MEM(ps, struct uuid, 1); + if (r_t->domain_guid == NULL) + return False; + } + + if ((r_t->ptr_domain_guid) && + (!smb_io_uuid("domain_guid", r_t->domain_guid, ps, depth))) + return False; + + if (!prs_align(ps)) + return False; + + if (!prs_uint32("ptr_site_guid", ps, depth, &r_t->ptr_site_guid)) + return False; + + if (UNMARSHALLING(ps) && (r_t->ptr_site_guid)) { + r_t->site_guid = PRS_ALLOC_MEM(ps, struct uuid, 1); + if (r_t->site_guid == NULL) + return False; + } + + if ((r_t->ptr_site_guid) && + (!smb_io_uuid("site_guid", r_t->site_guid, ps, depth))) + return False; + + if (!prs_align(ps)) + return False; + + if (!prs_uint32("flags", ps, depth, &r_t->flags)) + return False; + + return True; +} + +/******************************************************************* + Inits a NET_R_DSR_GETDCNAME structure. +********************************************************************/ +void init_net_r_dsr_getdcname(NET_R_DSR_GETDCNAME *r_t, const char *dc_unc, + const char *dc_address, int32 dc_address_type, + struct uuid domain_guid, const char *domain_name, + const char *forest_name, uint32 dc_flags, + const char *dc_site_name, + const char *client_site_name) +{ + DEBUG(5, ("init_net_q_dsr_getdcname\n")); + + r_t->ptr_dc_unc = (dc_unc != NULL); + init_unistr2(&r_t->uni_dc_unc, dc_unc, UNI_STR_TERMINATE); + + r_t->ptr_dc_address = (dc_address != NULL); + init_unistr2(&r_t->uni_dc_address, dc_address, UNI_STR_TERMINATE); + + r_t->dc_address_type = dc_address_type; + r_t->domain_guid = domain_guid; + + r_t->ptr_domain_name = (domain_name != NULL); + init_unistr2(&r_t->uni_domain_name, domain_name, UNI_STR_TERMINATE); + + r_t->ptr_forest_name = (forest_name != NULL); + init_unistr2(&r_t->uni_forest_name, forest_name, UNI_STR_TERMINATE); + + r_t->dc_flags = dc_flags; + + r_t->ptr_dc_site_name = (dc_site_name != NULL); + init_unistr2(&r_t->uni_dc_site_name, dc_site_name, UNI_STR_TERMINATE); + + r_t->ptr_client_site_name = (client_site_name != NULL); + init_unistr2(&r_t->uni_client_site_name, client_site_name, + UNI_STR_TERMINATE); +} + +/******************************************************************* + Reads or writes an NET_R_DSR_GETDCNAME structure. +********************************************************************/ + +BOOL net_io_r_dsr_getdcname(const char *desc, NET_R_DSR_GETDCNAME *r_t, + prs_struct *ps, int depth) +{ + uint32 info_ptr = 1; + + if (r_t == NULL) + return False; + + prs_debug(ps, depth, desc, "net_io_r_dsr_getdcname"); + depth++; + + /* The reply contains *just* an info struct, this is the ptr to it */ + if (!prs_uint32("info_ptr", ps, depth, &info_ptr)) + return False; + + if (info_ptr == 0) + return False; + + if (!prs_uint32("ptr_dc_unc", ps, depth, &r_t->ptr_dc_unc)) + return False; + + if (!prs_uint32("ptr_dc_address", ps, depth, &r_t->ptr_dc_address)) + return False; + + if (!prs_uint32("dc_address_type", ps, depth, &r_t->dc_address_type)) + return False; + + if (!smb_io_uuid("domain_guid", &r_t->domain_guid, ps, depth)) + return False; + + if (!prs_uint32("ptr_domain_name", ps, depth, &r_t->ptr_domain_name)) + return False; + + if (!prs_uint32("ptr_forest_name", ps, depth, &r_t->ptr_forest_name)) + return False; + + if (!prs_uint32("dc_flags", ps, depth, &r_t->dc_flags)) + return False; + + if (!prs_uint32("ptr_dc_site_name", ps, depth, &r_t->ptr_dc_site_name)) + return False; + + if (!prs_uint32("ptr_client_site_name", ps, depth, + &r_t->ptr_client_site_name)) + return False; + + if (!prs_align(ps)) + return False; + + if (!smb_io_unistr2("dc_unc", &r_t->uni_dc_unc, + r_t->ptr_dc_unc, ps, depth)) + return False; + + if (!prs_align(ps)) + return False; + + if (!smb_io_unistr2("dc_address", &r_t->uni_dc_address, + r_t->ptr_dc_address, ps, depth)) + return False; + + if (!prs_align(ps)) + return False; + + if (!smb_io_unistr2("domain_name", &r_t->uni_domain_name, + r_t->ptr_domain_name, ps, depth)) + return False; + + if (!prs_align(ps)) + return False; + + if (!smb_io_unistr2("forest_name", &r_t->uni_forest_name, + r_t->ptr_forest_name, ps, depth)) + return False; + + if (!prs_align(ps)) + return False; + + if (!smb_io_unistr2("dc_site_name", &r_t->uni_dc_site_name, + r_t->ptr_dc_site_name, ps, depth)) + return False; + + if (!prs_align(ps)) + return False; + + if (!smb_io_unistr2("client_site_name", &r_t->uni_client_site_name, + r_t->ptr_client_site_name, ps, depth)) + return False; + + if (!prs_align(ps)) + return False; + + if (!prs_werror("result", ps, depth, &r_t->result)) + return False; + + return True; +} diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c index d8f5a75b54..20f11bc3c9 100644 --- a/source3/rpcclient/cmd_netlogon.c +++ b/source3/rpcclient/cmd_netlogon.c @@ -70,6 +70,35 @@ static NTSTATUS cmd_netlogon_getdcname(struct rpc_pipe_client *cli, return result; } +static WERROR cmd_netlogon_dsr_getdcname(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + char *dcname, *dcaddress; + + if (argc != 2) { + fprintf(stderr, "Usage: %s domainname\n", argv[0]); + return WERR_OK; + } + + result = rpccli_netlogon_dsr_getdcname( + cli, mem_ctx, cli->cli->desthost, argv[1], NULL, NULL, + 0x40000000, &dcname, &dcaddress, NULL, NULL, NULL, NULL, + NULL, NULL, NULL); + + if (W_ERROR_IS_OK(result)) { + printf("Domain %s's DC is called %s at IP %s\n", + argv[1], dcname, dcaddress); + return WERR_OK; + } + + printf("rpccli_netlogon_dsr_getdcname returned %s\n", + nt_errstr(werror_to_ntstatus(result))); + + return result; +} + static NTSTATUS cmd_netlogon_logon_ctrl(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) @@ -317,6 +346,7 @@ struct cmd_set netlogon_commands[] = { { "logonctrl2", RPC_RTYPE_NTSTATUS, cmd_netlogon_logon_ctrl2, NULL, PI_NETLOGON, NULL, "Logon Control 2", "" }, { "getdcname", RPC_RTYPE_NTSTATUS, cmd_netlogon_getdcname, NULL, PI_NETLOGON, NULL, "Get trusted DC name", "" }, + { "dsr_getdcname", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getdcname, PI_NETLOGON, NULL, "Get trusted DC name", "" }, { "logonctrl", RPC_RTYPE_NTSTATUS, cmd_netlogon_logon_ctrl, NULL, PI_NETLOGON, NULL, "Logon Control", "" }, { "samsync", RPC_RTYPE_NTSTATUS, cmd_netlogon_sam_sync, NULL, PI_NETLOGON, NULL, "Sam Synchronisation", "" }, { "samdeltas", RPC_RTYPE_NTSTATUS, cmd_netlogon_sam_deltas, NULL, PI_NETLOGON, NULL, "Query Sam Deltas", "" }, |