/* Unix SMB/CIFS implementation. async implementation of WINBINDD_DSGETDCNAME Copyright (C) Volker Lendecke 2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "includes.h" #include "util/debug.h" #include "winbindd.h" #include "librpc/gen_ndr/ndr_winbind_c.h" #include "lib/util/string_wrappers.h" struct winbindd_dsgetdcname_state { struct GUID guid; struct netr_DsRGetDCNameInfo *dc_info; }; static uint32_t get_dsgetdc_flags(uint32_t wbc_flags); static void winbindd_dsgetdcname_done(struct tevent_req *subreq); struct tevent_req *winbindd_dsgetdcname_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct winbindd_cli_state *cli, struct winbindd_request *request) { struct tevent_req *req, *subreq; struct dcerpc_binding_handle *child_binding_handle = NULL; struct winbindd_dsgetdcname_state *state; struct GUID *guid_ptr = NULL; uint32_t ds_flags = 0; NTSTATUS status; req = tevent_req_create(mem_ctx, &state, struct winbindd_dsgetdcname_state); if (req == NULL) { return NULL; } D_NOTICE("[%s (%u)] Winbind external command DSGETDCNAME start.\n", cli->client_name, (unsigned int)cli->pid); request->data.dsgetdcname.domain_name [sizeof(request->data.dsgetdcname.domain_name)-1] = '\0'; request->data.dsgetdcname.site_name [sizeof(request->data.dsgetdcname.site_name)-1] = '\0'; request->data.dsgetdcname.domain_guid [sizeof(request->data.dsgetdcname.domain_guid)-1] = '\0'; D_NOTICE("Calling DsGetDcName for domain '%s'.\n", request->data.dsgetdcname.domain_name); ds_flags = get_dsgetdc_flags(request->data.dsgetdcname.flags); status = GUID_from_string(request->data.dsgetdcname.domain_guid, &state->guid); if (NT_STATUS_IS_OK(status) && !GUID_all_zero(&state->guid)) { guid_ptr = &state->guid; } child_binding_handle = locator_child_handle(); subreq = dcerpc_wbint_DsGetDcName_send( state, ev, child_binding_handle, request->data.dsgetdcname.domain_name, guid_ptr, request->data.dsgetdcname.site_name, ds_flags, &state->dc_info); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, winbindd_dsgetdcname_done, req); return req; } static void winbindd_dsgetdcname_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); struct winbindd_dsgetdcname_state *state = tevent_req_data( req, struct winbindd_dsgetdcname_state); NTSTATUS status, result; status = dcerpc_wbint_DsGetDcName_recv(subreq, state, &result); TALLOC_FREE(subreq); if (any_nt_status_not_ok(status, result, &status)) { tevent_req_nterror(req, status); return; } tevent_req_done(req); } NTSTATUS winbindd_dsgetdcname_recv(struct tevent_req *req, struct winbindd_response *response) { struct winbindd_dsgetdcname_state *state = tevent_req_data( req, struct winbindd_dsgetdcname_state); struct GUID_txt_buf guid_str_buf; char *guid_str; NTSTATUS status; D_NOTICE("Winbind external command DSGETDCNAME end.\n"); if (tevent_req_is_nterror(req, &status)) { D_WARNING("Failed with: %s\n", nt_errstr(status)); return status; } fstrcpy(response->data.dsgetdcname.dc_unc, state->dc_info->dc_unc); fstrcpy(response->data.dsgetdcname.dc_address, state->dc_info->dc_address); response->data.dsgetdcname.dc_address_type = state->dc_info->dc_address_type; guid_str = GUID_buf_string(&state->dc_info->domain_guid, &guid_str_buf); fstrcpy(response->data.dsgetdcname.domain_guid, guid_str); fstrcpy(response->data.dsgetdcname.domain_name, state->dc_info->domain_name); fstrcpy(response->data.dsgetdcname.forest_name, state->dc_info->forest_name); response->data.dsgetdcname.dc_flags = state->dc_info->dc_flags; fstrcpy(response->data.dsgetdcname.dc_site_name, state->dc_info->dc_site_name); fstrcpy(response->data.dsgetdcname.client_site_name, state->dc_info->client_site_name); return NT_STATUS_OK; } static uint32_t get_dsgetdc_flags(uint32_t wbc_flags) { struct wbc_flag_map { uint32_t wbc_dc_flag; uint32_t ds_dc_flags; } lookup_dc_flags[] = { { WBC_LOOKUP_DC_FORCE_REDISCOVERY, DS_FORCE_REDISCOVERY }, { WBC_LOOKUP_DC_DS_REQUIRED, DS_DIRECTORY_SERVICE_REQUIRED }, { WBC_LOOKUP_DC_DS_PREFERRED, DS_DIRECTORY_SERVICE_PREFERRED}, { WBC_LOOKUP_DC_GC_SERVER_REQUIRED, DS_GC_SERVER_REQUIRED }, { WBC_LOOKUP_DC_PDC_REQUIRED, DS_PDC_REQUIRED}, { WBC_LOOKUP_DC_BACKGROUND_ONLY, DS_BACKGROUND_ONLY }, { WBC_LOOKUP_DC_IP_REQUIRED, DS_IP_REQUIRED }, { WBC_LOOKUP_DC_KDC_REQUIRED, DS_KDC_REQUIRED }, { WBC_LOOKUP_DC_TIMESERV_REQUIRED, DS_TIMESERV_REQUIRED }, { WBC_LOOKUP_DC_WRITABLE_REQUIRED, DS_WRITABLE_REQUIRED }, { WBC_LOOKUP_DC_GOOD_TIMESERV_PREFERRED, DS_GOOD_TIMESERV_PREFERRED }, { WBC_LOOKUP_DC_AVOID_SELF, DS_AVOID_SELF }, { WBC_LOOKUP_DC_ONLY_LDAP_NEEDED, DS_ONLY_LDAP_NEEDED }, { WBC_LOOKUP_DC_IS_FLAT_NAME, DS_IS_FLAT_NAME }, { WBC_LOOKUP_DC_IS_DNS_NAME, DS_IS_DNS_NAME }, { WBC_LOOKUP_DC_TRY_NEXTCLOSEST_SITE, DS_TRY_NEXTCLOSEST_SITE }, { WBC_LOOKUP_DC_DS_6_REQUIRED, DS_DIRECTORY_SERVICE_6_REQUIRED }, { WBC_LOOKUP_DC_RETURN_DNS_NAME, DS_RETURN_DNS_NAME }, { WBC_LOOKUP_DC_RETURN_FLAT_NAME, DS_RETURN_FLAT_NAME } }; uint32_t ds_flags = 0; size_t i = 0; for (i=0; i