From f970d084dd46b4c1a380d2c8cd0879d39081e745 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 10 Jan 2011 17:25:00 +0100 Subject: [PATCH] s3: Add wbinfo --dc-info --- nsswitch/libwbclient/wbc_util.c | 88 ++++++++++++++++++++++++++++ nsswitch/libwbclient/wbclient.h | 15 ++++- nsswitch/wbinfo.c | 33 +++++++++++ nsswitch/winbind_struct_protocol.h | 4 +- source3/winbindd/winbindd.c | 1 + source3/winbindd/winbindd_cm.c | 93 ++++++++++++++++++++++++++++++ source3/winbindd/winbindd_misc.c | 53 +++++++++++++++++ source3/winbindd/winbindd_proto.h | 4 ++ 8 files changed, 289 insertions(+), 2 deletions(-) diff --git a/nsswitch/libwbclient/wbc_util.c b/nsswitch/libwbclient/wbc_util.c index c39023f15e..2065f4be05 100644 --- a/nsswitch/libwbclient/wbc_util.c +++ b/nsswitch/libwbclient/wbc_util.c @@ -179,6 +179,94 @@ wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo) return wbc_status; } +/* Get the list of current DCs */ +wbcErr wbcDcInfo(const char *domain, size_t *num_dcs, + const char ***dc_names, const char ***dc_ips) +{ + struct winbindd_request request; + struct winbindd_response response; + const char **names = NULL; + const char **ips = NULL; + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + size_t extra_len; + int i; + char *p; + + /* Initialise request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (domain != NULL) { + strncpy(request.domain_name, domain, + sizeof(request.domain_name) - 1); + } + + wbc_status = wbcRequestResponse(WINBINDD_DC_INFO, + &request, &response); + BAIL_ON_WBC_ERROR(wbc_status); + + names = talloc_zero_array(NULL, const char *, + response.data.num_entries); + BAIL_ON_PTR_ERROR(names, wbc_status); + + ips = talloc_zero_array(NULL, const char *, + response.data.num_entries); + BAIL_ON_PTR_ERROR(names, wbc_status); + + wbc_status = WBC_ERR_INVALID_RESPONSE; + + p = (char *)response.extra_data.data; + + if (response.length < (sizeof(struct winbindd_response)+1)) { + goto done; + } + + extra_len = response.length - sizeof(struct winbindd_response); + + if (p[extra_len-1] != '\0') { + goto done; + } + + for (i=0; ifd == -1) { + return; + } + get_peer_addr(cli->fd, addr, sizeof(addr)); + + key = current_dc_key(talloc_tos(), domain_name); + if (key == NULL) { + goto done; + } + + value = talloc_asprintf(talloc_tos(), "%s %s", addr, dc_name); + if (value == NULL) { + goto done; + } + + gencache_set(key, value, 0x7ffffffff); +done: + TALLOC_FREE(value); + TALLOC_FREE(key); +} + +bool fetch_current_dc_from_gencache(TALLOC_CTX *mem_ctx, + const char *domain_name, + char **p_dc_name, char **p_dc_ip) +{ + char *key, *value, *p; + bool ret = false; + char *dc_name = NULL; + char *dc_ip = NULL; + + key = current_dc_key(talloc_tos(), domain_name); + if (key == NULL) { + goto done; + } + if (!gencache_get(key, &value, NULL)) { + goto done; + } + p = strchr(value, ' '); + if (p == NULL) { + goto done; + } + dc_ip = talloc_strndup(mem_ctx, value, p - value); + if (dc_ip == NULL) { + goto done; + } + dc_name = talloc_strdup(mem_ctx, p+1); + if (dc_name == NULL) { + goto done; + } + + if (p_dc_ip != NULL) { + *p_dc_ip = dc_ip; + dc_ip = NULL; + } + if (p_dc_name != NULL) { + *p_dc_name = dc_name; + dc_name = NULL; + } + ret = true; +done: + TALLOC_FREE(dc_name); + TALLOC_FREE(dc_ip); + TALLOC_FREE(key); + return ret; +} + static NTSTATUS cm_open_connection(struct winbindd_domain *domain, struct winbindd_cm_conn *new_conn) { @@ -1480,6 +1562,17 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain, set_global_winbindd_state_online(); } set_domain_online(domain); + + /* + * Much as I hate global state, this seems to be the point + * where we can be certain that we have a proper connection to + * a DC. wbinfo --dc-info needs that information, store it in + * gencache with a looong timeout. This will need revisiting + * once we start to connect to multiple DCs, wbcDcInfo is + * already prepared for that. + */ + store_current_dc_in_gencache(domain->name, domain->dcname, + new_conn->cli); } else { /* Ensure we setup the retry handler. */ set_domain_offline(domain); diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c index 463e8375c8..c3fec223ce 100644 --- a/source3/winbindd/winbindd_misc.c +++ b/source3/winbindd/winbindd_misc.c @@ -790,6 +790,59 @@ void winbindd_ping(struct winbindd_cli_state *state) request_ok(state); } +void winbindd_dc_info(struct winbindd_cli_state *cli) +{ + struct winbindd_domain *domain; + char *dc_name, *dc_ip; + char *extra; + bool ret; + + cli->request.domain_name[sizeof(cli->request.domain_name-1)] = '\0'; + + DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid, + cli->request.domain_name)); + + if (cli->request.domain_name[0] != '\0') { + domain = find_domain_from_name_noinit( + cli->request.domain_name); + DEBUG(10, ("Could not find domain %s\n", + cli->request.domain_name)); + if (domain == NULL) { + request_error(cli); + return; + } + } else { + domain = find_our_domain(); + } + + if (!fetch_current_dc_from_gencache( + talloc_tos(), domain->name, &dc_name, &dc_ip)) { + DEBUG(10, ("fetch_current_dc_from_gencache(%s) failed\n", + domain->name)); + request_error(cli); + return; + } + + ret = (asprintf(&extra, "%s\n%s\n", dc_name, dc_ip) > 0); + + TALLOC_FREE(dc_name); + TALLOC_FREE(dc_ip); + + if (!ret) { + request_error(cli); + return; + } + + cli->response.data.num_entries = 1; + cli->response.extra_data.data = extra; + + /* must add one to length to copy the 0 for string termination */ + cli->response.length += + strlen((char *)cli->response.extra_data.data) + 1; + + request_ok(cli); +} + /* List various tidbits of information */ void winbindd_info(struct winbindd_cli_state *state) diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index d666639420..2384bf2d93 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -229,6 +229,9 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain, struct rpc_pipe_client **cli); NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, struct rpc_pipe_client **cli); +bool fetch_current_dc_from_gencache(TALLOC_CTX *mem_ctx, + const char *domain_name, + char **p_dc_name, char **p_dc_ip); /* The following definitions come from winbindd/winbindd_cred_cache.c */ @@ -426,6 +429,7 @@ void winbindd_show_sequence(struct winbindd_cli_state *state); enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain, struct winbindd_cli_state *state); void winbindd_domain_info(struct winbindd_cli_state *state); +void winbindd_dc_info(struct winbindd_cli_state *state); void winbindd_ping(struct winbindd_cli_state *state); void winbindd_info(struct winbindd_cli_state *state); void winbindd_interface_version(struct winbindd_cli_state *state); -- 2.34.1