Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : async dsgetdcname
4 : Copyright (C) Volker Lendecke 2009
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "winbindd.h"
22 : #include "librpc/gen_ndr/ndr_winbind_c.h"
23 : #include "librpc/gen_ndr/ndr_netlogon.h"
24 : #include "lib/gencache.h"
25 :
26 : struct wb_dsgetdcname_state {
27 : struct netr_DsRGetDCNameInfo *dcinfo;
28 : };
29 :
30 : static void wb_dsgetdcname_done(struct tevent_req *subreq);
31 :
32 30 : struct tevent_req *wb_dsgetdcname_send(TALLOC_CTX *mem_ctx,
33 : struct tevent_context *ev,
34 : const char *domain_name,
35 : const struct GUID *domain_guid,
36 : const char *site_name,
37 : uint32_t flags)
38 : {
39 : struct tevent_req *req, *subreq;
40 : struct wb_dsgetdcname_state *state;
41 30 : struct dcerpc_binding_handle *child_binding_handle = NULL;
42 : struct GUID guid;
43 30 : struct GUID *guid_ptr = NULL;
44 :
45 30 : req = tevent_req_create(mem_ctx, &state, struct wb_dsgetdcname_state);
46 30 : if (req == NULL) {
47 0 : return NULL;
48 : }
49 :
50 30 : D_INFO("WB command dsgetdcname start.\n"
51 : "Search domain name %s and site name %s.\n",
52 : domain_name,
53 : site_name);
54 30 : if (strequal(domain_name, "BUILTIN")) {
55 : /*
56 : * This makes no sense
57 : */
58 0 : tevent_req_nterror(req, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND);
59 0 : return tevent_req_post(req, ev);
60 : }
61 :
62 30 : if (strequal(domain_name, get_global_sam_name())) {
63 4 : int role = lp_server_role();
64 4 : if ( role != ROLE_ACTIVE_DIRECTORY_DC ) {
65 : /*
66 : * Two options here: Give back our own address, or say there's
67 : * nobody around. Right now opting for the latter, one measure
68 : * to prevent the loopback connects. This might change if
69 : * needed.
70 : */
71 2 : tevent_req_nterror(req, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND);
72 2 : return tevent_req_post(req, ev);
73 : }
74 : }
75 :
76 28 : if (IS_DC) {
77 : /*
78 : * We have to figure out the DC ourselves
79 : */
80 18 : child_binding_handle = locator_child_handle();
81 : } else {
82 10 : struct winbindd_domain *domain = find_our_domain();
83 10 : child_binding_handle = dom_child_handle(domain);
84 : }
85 :
86 28 : if (domain_guid != NULL) {
87 : /* work around a const issue in rpccli_ autogenerated code */
88 0 : guid = *domain_guid;
89 0 : guid_ptr = &guid;
90 : }
91 :
92 28 : subreq = dcerpc_wbint_DsGetDcName_send(
93 : state, ev, child_binding_handle, domain_name, guid_ptr, site_name,
94 28 : flags, &state->dcinfo);
95 28 : if (tevent_req_nomem(subreq, req)) {
96 0 : return tevent_req_post(req, ev);
97 : }
98 28 : tevent_req_set_callback(subreq, wb_dsgetdcname_done, req);
99 28 : return req;
100 : }
101 :
102 26 : static void wb_dsgetdcname_done(struct tevent_req *subreq)
103 : {
104 26 : struct tevent_req *req = tevent_req_callback_data(
105 : subreq, struct tevent_req);
106 26 : struct wb_dsgetdcname_state *state = tevent_req_data(
107 : req, struct wb_dsgetdcname_state);
108 : NTSTATUS status, result;
109 :
110 26 : status = dcerpc_wbint_DsGetDcName_recv(subreq, state, &result);
111 26 : TALLOC_FREE(subreq);
112 26 : if (any_nt_status_not_ok(status, result, &status)) {
113 0 : tevent_req_nterror(req, status);
114 0 : return;
115 : }
116 26 : tevent_req_done(req);
117 : }
118 :
119 28 : NTSTATUS wb_dsgetdcname_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
120 : struct netr_DsRGetDCNameInfo **pdcinfo)
121 : {
122 28 : struct wb_dsgetdcname_state *state = tevent_req_data(
123 : req, struct wb_dsgetdcname_state);
124 : NTSTATUS status;
125 :
126 28 : D_INFO("WB command dsgetdcname end.\n");
127 28 : if (tevent_req_is_nterror(req, &status)) {
128 2 : D_WARNING("Failed with %s.\n", nt_errstr(status));
129 2 : return status;
130 : }
131 26 : *pdcinfo = talloc_move(mem_ctx, &state->dcinfo);
132 26 : return NT_STATUS_OK;
133 : }
134 :
135 4 : NTSTATUS wb_dsgetdcname_gencache_set(const char *domname,
136 : struct netr_DsRGetDCNameInfo *dcinfo)
137 : {
138 : DATA_BLOB blob;
139 : enum ndr_err_code ndr_err;
140 : char *key;
141 : bool ok;
142 :
143 4 : key = talloc_asprintf_strupper_m(talloc_tos(), "DCINFO/%s", domname);
144 4 : if (key == NULL) {
145 0 : return NT_STATUS_NO_MEMORY;
146 : }
147 :
148 4 : if (DEBUGLEVEL >= 10) {
149 0 : NDR_PRINT_DEBUG(netr_DsRGetDCNameInfo, dcinfo);
150 : }
151 :
152 4 : ndr_err = ndr_push_struct_blob(
153 : &blob, key, dcinfo,
154 : (ndr_push_flags_fn_t)ndr_push_netr_DsRGetDCNameInfo);
155 4 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
156 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
157 0 : DBG_WARNING("ndr_push_struct_blob failed: %s\n",
158 : ndr_errstr(ndr_err));
159 0 : TALLOC_FREE(key);
160 0 : return status;
161 : }
162 :
163 4 : ok = gencache_set_data_blob(key, blob, time(NULL)+3600);
164 :
165 4 : if (!ok) {
166 0 : DBG_WARNING("gencache_set_data_blob for key %s failed\n", key);
167 0 : TALLOC_FREE(key);
168 0 : return NT_STATUS_UNSUCCESSFUL;
169 : }
170 :
171 4 : TALLOC_FREE(key);
172 4 : return NT_STATUS_OK;
173 : }
174 :
175 : struct dcinfo_parser_state {
176 : NTSTATUS status;
177 : TALLOC_CTX *mem_ctx;
178 : struct netr_DsRGetDCNameInfo *dcinfo;
179 : };
180 :
181 0 : static void dcinfo_parser(const struct gencache_timeout *timeout,
182 : DATA_BLOB blob,
183 : void *private_data)
184 : {
185 0 : struct dcinfo_parser_state *state = private_data;
186 : enum ndr_err_code ndr_err;
187 :
188 0 : if (gencache_timeout_expired(timeout)) {
189 0 : return;
190 : }
191 :
192 0 : state->dcinfo = talloc(state->mem_ctx, struct netr_DsRGetDCNameInfo);
193 0 : if (state->dcinfo == NULL) {
194 0 : state->status = NT_STATUS_NO_MEMORY;
195 0 : return;
196 : }
197 :
198 0 : ndr_err = ndr_pull_struct_blob_all(
199 0 : &blob, state->dcinfo, state->dcinfo,
200 : (ndr_pull_flags_fn_t)ndr_pull_netr_DsRGetDCNameInfo);
201 :
202 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
203 0 : DBG_ERR("ndr_pull_struct_blob failed\n");
204 0 : state->status = ndr_map_error2ntstatus(ndr_err);
205 0 : TALLOC_FREE(state->dcinfo);
206 0 : return;
207 : }
208 :
209 0 : state->status = NT_STATUS_OK;
210 : }
211 :
212 0 : NTSTATUS wb_dsgetdcname_gencache_get(TALLOC_CTX *mem_ctx,
213 : const char *domname,
214 : struct netr_DsRGetDCNameInfo **dcinfo)
215 : {
216 : struct dcinfo_parser_state state;
217 : char *key;
218 : bool ok;
219 :
220 0 : key = talloc_asprintf_strupper_m(mem_ctx, "DCINFO/%s", domname);
221 0 : if (key == NULL) {
222 0 : return NT_STATUS_NO_MEMORY;
223 : }
224 :
225 0 : state = (struct dcinfo_parser_state) {
226 : .status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND,
227 : .mem_ctx = mem_ctx,
228 : };
229 :
230 0 : ok = gencache_parse(key, dcinfo_parser, &state);
231 0 : TALLOC_FREE(key);
232 0 : if (!ok) {
233 0 : return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
234 : }
235 :
236 0 : if (!NT_STATUS_IS_OK(state.status)) {
237 0 : return state.status;
238 : }
239 :
240 0 : if (DEBUGLEVEL >= 10) {
241 0 : NDR_PRINT_DEBUG(netr_DsRGetDCNameInfo, state.dcinfo);
242 : }
243 :
244 0 : *dcinfo = state.dcinfo;
245 0 : return NT_STATUS_OK;
246 : }
|