Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Rafal Szczesniak 2005
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 : /*
21 : a composite function for name resolving
22 : */
23 :
24 : #include "includes.h"
25 : #include "libnet/libnet.h"
26 : #include "libcli/composite/composite.h"
27 : #include "auth/credentials/credentials.h"
28 : #include "libcli/resolve/resolve.h"
29 : #include "libcli/finddc.h"
30 : #include "libcli/security/security.h"
31 : #include "librpc/gen_ndr/ndr_lsa_c.h"
32 : #include "param/param.h"
33 :
34 : struct lookup_state {
35 : struct nbt_name hostname;
36 : const char *address;
37 : };
38 :
39 :
40 : static void continue_name_resolved(struct composite_context *ctx);
41 :
42 :
43 : /**
44 : * Sends asynchronous Lookup request
45 : *
46 : * @param io arguments and result of the call
47 : */
48 :
49 2 : struct composite_context *libnet_Lookup_send(struct libnet_context *ctx,
50 : TALLOC_CTX *mem_ctx,
51 : struct libnet_Lookup *io)
52 : {
53 2 : struct composite_context *c;
54 2 : struct lookup_state *s;
55 2 : struct composite_context *cresolve_req;
56 2 : struct resolve_context *resolve_ctx;
57 :
58 : /* allocate context and state structures */
59 2 : c = composite_create(mem_ctx, ctx->event_ctx);
60 2 : if (c == NULL) return NULL;
61 :
62 2 : s = talloc_zero(c, struct lookup_state);
63 2 : if (composite_nomem(s, c)) return c;
64 :
65 2 : c->private_data = s;
66 :
67 2 : if (io == NULL || io->in.hostname == NULL) {
68 0 : composite_error(c, NT_STATUS_INVALID_PARAMETER);
69 0 : return c;
70 : }
71 :
72 : /* parameters */
73 2 : s->hostname.name = talloc_strdup(s, io->in.hostname);
74 2 : if (composite_nomem(s->hostname.name, c)) return c;
75 :
76 2 : s->hostname.type = io->in.type;
77 2 : s->hostname.scope = NULL;
78 :
79 : /* name resolution methods */
80 2 : if (io->in.resolve_ctx) {
81 0 : resolve_ctx = io->in.resolve_ctx;
82 : } else {
83 2 : resolve_ctx = ctx->resolve_ctx;
84 : }
85 :
86 : /* send resolve request */
87 2 : cresolve_req = resolve_name_send(resolve_ctx, s, &s->hostname, c->event_ctx);
88 2 : if (composite_nomem(cresolve_req, c)) return c;
89 :
90 2 : composite_continue(c, cresolve_req, continue_name_resolved, c);
91 2 : return c;
92 : }
93 :
94 :
95 2 : static void continue_name_resolved(struct composite_context *ctx)
96 : {
97 2 : struct composite_context *c;
98 2 : struct lookup_state *s;
99 :
100 2 : c = talloc_get_type(ctx->async.private_data, struct composite_context);
101 2 : s = talloc_get_type(c->private_data, struct lookup_state);
102 :
103 2 : c->status = resolve_name_recv(ctx, s, &s->address);
104 :
105 2 : composite_done(c);
106 2 : }
107 :
108 :
109 : /**
110 : * Waits for and receives results of asynchronous Lookup call
111 : *
112 : * @param c composite context returned by asynchronous Lookup call
113 : * @param mem_ctx memory context of the call
114 : * @param io pointer to results (and arguments) of the call
115 : * @return nt status code of execution
116 : */
117 :
118 2 : NTSTATUS libnet_Lookup_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
119 : struct libnet_Lookup *io)
120 : {
121 2 : NTSTATUS status;
122 2 : struct lookup_state *s;
123 :
124 2 : status = composite_wait(c);
125 2 : if (NT_STATUS_IS_OK(status)) {
126 2 : char **address;
127 :
128 2 : s = talloc_get_type(c->private_data, struct lookup_state);
129 :
130 2 : address = str_list_make_single(mem_ctx, s->address);
131 2 : NT_STATUS_HAVE_NO_MEMORY(address);
132 2 : io->out.address = discard_const_p(const char *, address);
133 : }
134 :
135 2 : talloc_free(c);
136 2 : return status;
137 : }
138 :
139 :
140 : /**
141 : * Synchronous version of Lookup call
142 : *
143 : * @param mem_ctx memory context for the call
144 : * @param io arguments and results of the call
145 : * @return nt status code of execution
146 : */
147 :
148 1 : NTSTATUS libnet_Lookup(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
149 : struct libnet_Lookup *io)
150 : {
151 1 : struct composite_context *c = libnet_Lookup_send(ctx, mem_ctx, io);
152 1 : return libnet_Lookup_recv(c, mem_ctx, io);
153 : }
154 :
155 :
156 : /*
157 : * Shortcut functions to find common types of name
158 : * (and skip nbt name type argument)
159 : */
160 :
161 :
162 : /**
163 : * Sends asynchronous LookupHost request
164 : */
165 1 : struct composite_context* libnet_LookupHost_send(struct libnet_context *ctx,
166 : TALLOC_CTX *mem_ctx,
167 : struct libnet_Lookup *io)
168 : {
169 1 : io->in.type = NBT_NAME_SERVER;
170 1 : return libnet_Lookup_send(ctx, mem_ctx, io);
171 : }
172 :
173 :
174 :
175 : /**
176 : * Synchronous version of LookupHost call
177 : */
178 1 : NTSTATUS libnet_LookupHost(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
179 : struct libnet_Lookup *io)
180 : {
181 1 : struct composite_context *c = libnet_LookupHost_send(ctx, mem_ctx, io);
182 1 : return libnet_Lookup_recv(c, mem_ctx, io);
183 : }
184 :
185 :
186 : /**
187 : * Sends asynchronous LookupDCs request
188 : */
189 210 : struct tevent_req *libnet_LookupDCs_send(struct libnet_context *ctx,
190 : TALLOC_CTX *mem_ctx,
191 : struct libnet_LookupDCs *io)
192 : {
193 154 : struct tevent_req *req;
194 154 : struct finddcs finddcs_io;
195 :
196 210 : ZERO_STRUCT(finddcs_io);
197 :
198 210 : if (strcasecmp_m(io->in.domain_name, lpcfg_workgroup(ctx->lp_ctx)) == 0) {
199 203 : finddcs_io.in.domain_name = lpcfg_dnsdomain(ctx->lp_ctx);
200 : } else {
201 7 : finddcs_io.in.domain_name = io->in.domain_name;
202 : }
203 210 : finddcs_io.in.minimum_dc_flags = NBT_SERVER_LDAP | NBT_SERVER_DS | NBT_SERVER_WRITABLE;
204 210 : finddcs_io.in.server_address = ctx->server_address;
205 :
206 210 : req = finddcs_cldap_send(mem_ctx, &finddcs_io, ctx->resolve_ctx, ctx->event_ctx);
207 210 : return req;
208 : }
209 :
210 : /**
211 : * Waits for and receives results of asynchronous Lookup call
212 : *
213 : * @param c composite context returned by asynchronous Lookup call
214 : * @param mem_ctx memory context of the call
215 : * @param io pointer to results (and arguments) of the call
216 : * @return nt status code of execution
217 : */
218 :
219 210 : NTSTATUS libnet_LookupDCs_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
220 : struct libnet_LookupDCs *io)
221 : {
222 154 : NTSTATUS status;
223 154 : struct finddcs finddcs_io;
224 210 : status = finddcs_cldap_recv(req, mem_ctx, &finddcs_io);
225 210 : talloc_free(req);
226 210 : io->out.num_dcs = 1;
227 210 : io->out.dcs = talloc(mem_ctx, struct nbt_dc_name);
228 210 : NT_STATUS_HAVE_NO_MEMORY(io->out.dcs);
229 210 : io->out.dcs[0].address = finddcs_io.out.address;
230 210 : io->out.dcs[0].name = finddcs_io.out.netlogon.data.nt5_ex.pdc_dns_name;
231 210 : return status;
232 : }
233 :
234 :
235 : /**
236 : * Synchronous version of LookupDCs
237 : */
238 1 : NTSTATUS libnet_LookupDCs(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
239 : struct libnet_LookupDCs *io)
240 : {
241 1 : struct tevent_req *req = libnet_LookupDCs_send(ctx, mem_ctx, io);
242 1 : return libnet_LookupDCs_recv(req, mem_ctx, io);
243 : }
244 :
245 :
246 : struct lookup_name_state {
247 : struct libnet_context *ctx;
248 : const char *name;
249 : uint32_t count;
250 : struct libnet_DomainOpen domopen;
251 : struct lsa_LookupNames lookup;
252 : struct lsa_TransSidArray sids;
253 : struct lsa_String *names;
254 :
255 : /* information about the progress */
256 : void (*monitor_fn)(struct monitor_msg *);
257 : };
258 :
259 :
260 : static bool prepare_lookup_params(struct libnet_context *ctx,
261 : struct composite_context *c,
262 : struct lookup_name_state *s);
263 : static void continue_lookup_name(struct composite_context *ctx);
264 : static void continue_name_found(struct tevent_req *subreq);
265 :
266 :
267 13 : struct composite_context* libnet_LookupName_send(struct libnet_context *ctx,
268 : TALLOC_CTX *mem_ctx,
269 : struct libnet_LookupName *io,
270 : void (*monitor)(struct monitor_msg*))
271 : {
272 13 : struct composite_context *c;
273 13 : struct lookup_name_state *s;
274 13 : struct tevent_req *subreq;
275 13 : bool prereq_met = false;
276 :
277 13 : c = composite_create(mem_ctx, ctx->event_ctx);
278 13 : if (c == NULL) return NULL;
279 :
280 13 : s = talloc_zero(c, struct lookup_name_state);
281 13 : if (composite_nomem(s, c)) return c;
282 :
283 13 : c->private_data = s;
284 :
285 13 : s->name = talloc_strdup(c, io->in.name);
286 13 : s->monitor_fn = monitor;
287 13 : s->ctx = ctx;
288 :
289 13 : prereq_met = lsa_domain_opened(ctx, c, io->in.domain_name, &c, &s->domopen,
290 : continue_lookup_name, monitor);
291 13 : if (!prereq_met) return c;
292 :
293 9 : if (!prepare_lookup_params(ctx, c, s)) return c;
294 :
295 18 : subreq = dcerpc_lsa_LookupNames_r_send(s, c->event_ctx,
296 9 : ctx->lsa.pipe->binding_handle,
297 : &s->lookup);
298 9 : if (composite_nomem(subreq, c)) return c;
299 :
300 9 : tevent_req_set_callback(subreq, continue_name_found, c);
301 9 : return c;
302 : }
303 :
304 :
305 13 : static bool prepare_lookup_params(struct libnet_context *ctx,
306 : struct composite_context *c,
307 : struct lookup_name_state *s)
308 : {
309 13 : const int single_name = 1;
310 :
311 13 : s->sids.count = 0;
312 13 : s->sids.sids = NULL;
313 :
314 13 : s->names = talloc_array(s, struct lsa_String, single_name);
315 13 : if (composite_nomem(s->names, c)) return false;
316 13 : s->names[0].string = s->name;
317 :
318 13 : s->lookup.in.handle = &ctx->lsa.handle;
319 13 : s->lookup.in.num_names = single_name;
320 13 : s->lookup.in.names = s->names;
321 13 : s->lookup.in.sids = &s->sids;
322 13 : s->lookup.in.level = 1;
323 13 : s->lookup.in.count = &s->count;
324 13 : s->lookup.out.count = &s->count;
325 13 : s->lookup.out.sids = &s->sids;
326 13 : s->lookup.out.domains = talloc_zero(s, struct lsa_RefDomainList *);
327 13 : if (composite_nomem(s->lookup.out.domains, c)) return false;
328 :
329 0 : return true;
330 : }
331 :
332 :
333 4 : static void continue_lookup_name(struct composite_context *ctx)
334 : {
335 4 : struct composite_context *c;
336 4 : struct lookup_name_state *s;
337 4 : struct tevent_req *subreq;
338 :
339 4 : c = talloc_get_type(ctx->async.private_data, struct composite_context);
340 4 : s = talloc_get_type(c->private_data, struct lookup_name_state);
341 :
342 4 : c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domopen);
343 4 : if (!composite_is_ok(c)) return;
344 :
345 4 : if (!prepare_lookup_params(s->ctx, c, s)) return;
346 :
347 8 : subreq = dcerpc_lsa_LookupNames_r_send(s, c->event_ctx,
348 4 : s->ctx->lsa.pipe->binding_handle,
349 : &s->lookup);
350 4 : if (composite_nomem(subreq, c)) return;
351 :
352 4 : tevent_req_set_callback(subreq, continue_name_found, c);
353 : }
354 :
355 :
356 13 : static void continue_name_found(struct tevent_req *subreq)
357 : {
358 13 : struct composite_context *c;
359 13 : struct lookup_name_state *s;
360 :
361 13 : c = tevent_req_callback_data(subreq, struct composite_context);
362 13 : s = talloc_get_type(c->private_data, struct lookup_name_state);
363 :
364 13 : c->status = dcerpc_lsa_LookupNames_r_recv(subreq, s);
365 13 : TALLOC_FREE(subreq);
366 13 : if (!composite_is_ok(c)) return;
367 :
368 13 : c->status = s->lookup.out.result;
369 13 : if (!composite_is_ok(c)) return;
370 :
371 13 : if (s->lookup.out.sids->count != s->lookup.in.num_names) {
372 0 : composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
373 0 : return;
374 : }
375 :
376 13 : composite_done(c);
377 : }
378 :
379 :
380 13 : NTSTATUS libnet_LookupName_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
381 : struct libnet_LookupName *io)
382 : {
383 13 : NTSTATUS status;
384 13 : struct lookup_name_state *s = NULL;
385 13 : struct lsa_RefDomainList *domains = NULL;
386 13 : struct lsa_TransSidArray *sids = NULL;
387 :
388 13 : status = composite_wait(c);
389 13 : ZERO_STRUCT(io->out);
390 :
391 13 : if (!NT_STATUS_IS_OK(status)) {
392 0 : io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s",
393 : nt_errstr(status));
394 0 : goto done;
395 : }
396 :
397 13 : s = talloc_get_type(c->private_data, struct lookup_name_state);
398 :
399 13 : if (*s->lookup.out.count == 0) {
400 0 : goto success;
401 : }
402 :
403 13 : domains = *s->lookup.out.domains;
404 13 : sids = s->lookup.out.sids;
405 :
406 13 : if (domains == NULL || sids == NULL) {
407 0 : status = NT_STATUS_UNSUCCESSFUL;
408 0 : io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s",
409 : nt_errstr(status));
410 0 : goto done;
411 : }
412 :
413 13 : if (sids->count == 0) {
414 0 : goto success;
415 : }
416 :
417 13 : io->out.rid = sids->sids[0].rid;
418 13 : io->out.sid_type = sids->sids[0].sid_type;
419 13 : if (domains->count > 0) {
420 13 : io->out.sid = dom_sid_add_rid(mem_ctx, domains->domains[0].sid,
421 0 : io->out.rid);
422 13 : if (io->out.sid == NULL) {
423 0 : status = NT_STATUS_NO_MEMORY;
424 0 : goto done;
425 : }
426 13 : io->out.sidstr = dom_sid_string(mem_ctx, io->out.sid);
427 13 : if (io->out.sidstr == NULL) {
428 0 : status = NT_STATUS_NO_MEMORY;
429 0 : goto done;
430 : }
431 : }
432 :
433 13 : success:
434 13 : io->out.error_string = talloc_strdup(mem_ctx, "Success");
435 13 : done:
436 13 : talloc_free(c);
437 13 : return status;
438 : }
439 :
440 :
441 1 : NTSTATUS libnet_LookupName(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
442 : struct libnet_LookupName *io)
443 : {
444 1 : struct composite_context *c;
445 :
446 1 : c = libnet_LookupName_send(ctx, mem_ctx, io, NULL);
447 1 : return libnet_LookupName_recv(c, mem_ctx, io);
448 : }
|