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