1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

s3: Add wbinfo --dc-info

wbinfo --dc-info prints the current DC name and IP address. This helps
diagnosing problems that might happen when a later wbinfo --ping-dc fails.

This patch started out by using the SAF and NBT cache entires, but those are
relatively short-lived. So I decided to invent a new gencache entry with a very
long timeout. We need to go via the gencache because when for some reason a
winbind child process is stuck, we can't query it for the current DC it's
connected to. This must eventually go away again when we have a fully async
winbind.

Autobuild-User: Volker Lendecke <vlendec@samba.org>
Autobuild-Date: Wed Jan 19 08:40:28 CET 2011 on sn-devel-104
This commit is contained in:
Volker Lendecke 2011-01-10 17:25:00 +01:00 committed by Volker Lendecke
parent 1b43996022
commit 7f87d58900
8 changed files with 284 additions and 2 deletions

View File

@ -203,6 +203,92 @@ 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 = wbcAllocateStringArray(response.data.num_entries);
BAIL_ON_PTR_ERROR(names, wbc_status);
ips = wbcAllocateStringArray(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; i<response.data.num_entries; i++) {
char *q;
q = strchr(p, '\n');
if (q == NULL) {
goto done;
}
names[i] = strndup(p, q-p);
BAIL_ON_PTR_ERROR(names[i], wbc_status);
p = q+1;
q = strchr(p, '\n');
if (q == NULL) {
goto done;
}
ips[i] = strndup(p, q-p);
BAIL_ON_PTR_ERROR(ips[i], wbc_status);
p = q+1;
}
if (p[0] != '\0') {
goto done;
}
wbc_status = WBC_ERR_SUCCESS;
done:
if (response.extra_data.data)
free(response.extra_data.data);
if (WBC_ERROR_IS_OK(wbc_status)) {
*num_dcs = response.data.num_entries;
*dc_names = names;
names = NULL;
*dc_ips = ips;
ips = NULL;
}
wbcFreeMemory(names);
wbcFreeMemory(ips);
return wbc_status;
}
/* Resolve a NetbiosName via WINS */
wbcErr wbcResolveWinsByName(const char *name, char **ip)

View File

@ -192,7 +192,6 @@ struct wbcDomainInfo {
#define WBC_DOMINFO_TRUSTTYPE_IN_FOREST 0x00000002
#define WBC_DOMINFO_TRUSTTYPE_EXTERNAL 0x00000003
/**
* @brief Auth User Parameters
**/
@ -991,6 +990,20 @@ wbcErr wbcGetGroups(const char *account,
wbcErr wbcDomainInfo(const char *domain,
struct wbcDomainInfo **dinfo);
/**
* @brief Lookup the currently contacted DCs
*
* @param domain The domain to query
*
* @param num_dcs Number of DCs currently known
* @param dc_names Names of the currently known DCs
* @param dc_ips IP addresses of the currently known DCs
*
* @return #wbcErr
**/
wbcErr wbcDcInfo(const char *domain, size_t *num_dcs,
const char ***dc_names, const char ***dc_ips);
/**
* @brief Enumerate the domain trusts known by Winbind
*

View File

@ -787,6 +787,31 @@ static bool wbinfo_check_secret(const char *domain)
return true;
}
/* Find the currently connected DCs */
static bool wbinfo_dc_info(const char *domain_name)
{
wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
size_t i, num_dcs;
const char **dc_names, **dc_ips;
wbc_status = wbcDcInfo(domain_name, &num_dcs,
&dc_names, &dc_ips);
if (!WBC_ERROR_IS_OK(wbc_status)) {
printf("Could not find dc info %s\n",
domain_name ? domain_name : "our domain");
return false;
}
for (i=0; i<num_dcs; i++) {
printf("%s (%s)\n", dc_names[i], dc_ips[i]);
}
wbcFreeMemory(dc_names);
wbcFreeMemory(dc_ips);
return true;
}
/* Change trust account password */
static bool wbinfo_change_secret(const char *domain)
@ -1921,6 +1946,7 @@ enum {
OPT_SEQUENCE,
OPT_GETDCNAME,
OPT_DSGETDCNAME,
OPT_DC_INFO,
OPT_USERDOMGROUPS,
OPT_SIDALIASES,
OPT_USERSIDS,
@ -2030,6 +2056,8 @@ int main(int argc, char **argv, char **envp)
{ "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME,
"Get a DC name for a foreign domain", "domainname" },
{ "dsgetdcname", 0, POPT_ARG_STRING, &string_arg, OPT_DSGETDCNAME, "Find a DC for a domain", "domainname" },
{ "dc-info", 0, POPT_ARG_STRING, &string_arg, OPT_DC_INFO,
"Find the currently known DCs", "domainname" },
{ "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL },
{ "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" },
{ "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" },
@ -2443,6 +2471,11 @@ int main(int argc, char **argv, char **envp)
goto done;
}
break;
case OPT_DC_INFO:
if (!wbinfo_dc_info(string_arg)) {
goto done;
}
break;
case OPT_SEPARATOR: {
const char sep = winbind_separator();
if ( !sep ) {

View File

@ -54,8 +54,9 @@ typedef char fstring[FSTRING_LEN];
* 25: removed WINBINDD_SET_HWM
* removed WINBINDD_SET_MAPPING
* removed WINBINDD_REMOVE_MAPPING
* 26: added WINBINDD_DC_INFO
*/
#define WINBIND_INTERFACE_VERSION 25
#define WINBIND_INTERFACE_VERSION 26
/* Have to deal with time_t being 4 or 8 bytes due to structure alignment.
On a 64bit Linux box, we have to support a constant structure size
@ -132,6 +133,7 @@ enum winbindd_cmd {
struct winbindd_domain */
WINBINDD_GETDCNAME, /* Issue a GetDCName Request */
WINBINDD_DSGETDCNAME, /* Issue a DsGetDCName Request */
WINBINDD_DC_INFO, /* Which DC are we connected to? */
WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */

View File

@ -442,6 +442,7 @@ static struct winbindd_dispatch_table {
"INTERFACE_VERSION" },
{ WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
{ WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
{ WINBINDD_DC_INFO, winbindd_dc_info, "DC_INFO" },
{ WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
{ WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir,
"WINBINDD_PRIV_PIPE_DIR" },

View File

@ -1419,6 +1419,88 @@ static bool find_new_dc(TALLOC_CTX *mem_ctx,
goto again;
}
static char *current_dc_key(TALLOC_CTX *mem_ctx, const char *domain_name)
{
return talloc_asprintf_strupper_m(mem_ctx, "CURRENT_DCNAME/%s",
domain_name);
}
static void store_current_dc_in_gencache(const char *domain_name,
const char *dc_name,
struct cli_state *cli)
{
char addr[INET6_ADDRSTRLEN];
char *key, *value;
if (cli == NULL) {
return;
}
if (cli->fd == -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)
{
@ -1520,6 +1602,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);

View File

@ -314,6 +314,56 @@ static void domain_info_done(struct tevent_req *req)
request_ok(state->cli);
}
void winbindd_dc_info(struct winbindd_cli_state *cli)
{
struct winbindd_domain *domain;
char *dc_name, *dc_ip;
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;
}
cli->response->data.num_entries = 1;
cli->response->extra_data.data = talloc_asprintf(
cli->mem_ctx, "%s\n%s\n", dc_name, dc_ip);
TALLOC_FREE(dc_name);
TALLOC_FREE(dc_ip);
if (cli->response->extra_data.data == NULL) {
request_error(cli);
return;
}
/* 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)

View File

@ -170,6 +170,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 */
@ -322,6 +325,7 @@ enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *
struct winbindd_cli_state *state);
void winbindd_show_sequence(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);