1/* 2 Unix SMB/CIFS implementation. 3 4 send out a name registration request 5 6 Copyright (C) Andrew Tridgell 2005 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include "../libcli/nbt/libnbt.h" 24#include "../libcli/nbt/nbt_proto.h" 25#include "libcli/composite/composite.h" 26#include "lib/socket/socket.h" 27#include "librpc/gen_ndr/ndr_nbt.h" 28 29/* 30 send a nbt name registration request 31*/ 32struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock, 33 struct nbt_name_register *io) 34{ 35 struct nbt_name_request *req; 36 struct nbt_name_packet *packet; 37 struct socket_address *dest; 38 39 packet = talloc_zero(nbtsock, struct nbt_name_packet); 40 if (packet == NULL) return NULL; 41 42 packet->qdcount = 1; 43 packet->arcount = 1; 44 if (io->in.multi_homed) { 45 packet->operation = NBT_OPCODE_MULTI_HOME_REG; 46 } else { 47 packet->operation = NBT_OPCODE_REGISTER; 48 } 49 if (io->in.broadcast) { 50 packet->operation |= NBT_FLAG_BROADCAST; 51 } 52 if (io->in.register_demand) { 53 packet->operation |= NBT_FLAG_RECURSION_DESIRED; 54 } 55 56 packet->questions = talloc_array(packet, struct nbt_name_question, 1); 57 if (packet->questions == NULL) goto failed; 58 59 packet->questions[0].name = io->in.name; 60 packet->questions[0].question_type = NBT_QTYPE_NETBIOS; 61 packet->questions[0].question_class = NBT_QCLASS_IP; 62 63 packet->additional = talloc_array(packet, struct nbt_res_rec, 1); 64 if (packet->additional == NULL) goto failed; 65 66 packet->additional[0].name = io->in.name; 67 packet->additional[0].rr_type = NBT_QTYPE_NETBIOS; 68 packet->additional[0].rr_class = NBT_QCLASS_IP; 69 packet->additional[0].ttl = io->in.ttl; 70 packet->additional[0].rdata.netbios.length = 6; 71 packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional, 72 struct nbt_rdata_address, 1); 73 if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed; 74 packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags; 75 packet->additional[0].rdata.netbios.addresses[0].ipaddr = 76 talloc_strdup(packet->additional, io->in.address); 77 if (packet->additional[0].rdata.netbios.addresses[0].ipaddr == NULL) goto failed; 78 79 dest = socket_address_from_strings(packet, nbtsock->sock->backend_name, 80 io->in.dest_addr, io->in.dest_port); 81 if (dest == NULL) goto failed; 82 req = nbt_name_request_send(nbtsock, dest, packet, 83 io->in.timeout, io->in.retries, false); 84 if (req == NULL) goto failed; 85 86 talloc_free(packet); 87 return req; 88 89failed: 90 talloc_free(packet); 91 return NULL; 92} 93 94/* 95 wait for a registration reply 96*/ 97_PUBLIC_ NTSTATUS nbt_name_register_recv(struct nbt_name_request *req, 98 TALLOC_CTX *mem_ctx, struct nbt_name_register *io) 99{ 100 NTSTATUS status; 101 struct nbt_name_packet *packet; 102 103 status = nbt_name_request_recv(req); 104 if (!NT_STATUS_IS_OK(status) || 105 req->num_replies == 0) { 106 talloc_free(req); 107 return status; 108 } 109 110 packet = req->replies[0].packet; 111 io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr); 112 113 if (packet->ancount != 1 || 114 packet->answers[0].rr_type != NBT_QTYPE_NETBIOS || 115 packet->answers[0].rr_class != NBT_QCLASS_IP) { 116 talloc_free(req); 117 return NT_STATUS_INVALID_NETWORK_RESPONSE; 118 } 119 120 io->out.rcode = packet->operation & NBT_RCODE; 121 io->out.name = packet->answers[0].name; 122 if (packet->answers[0].rdata.netbios.length < 6) { 123 talloc_free(req); 124 return NT_STATUS_INVALID_NETWORK_RESPONSE; 125 } 126 io->out.reply_addr = talloc_steal(mem_ctx, 127 packet->answers[0].rdata.netbios.addresses[0].ipaddr); 128 talloc_steal(mem_ctx, io->out.name.name); 129 talloc_steal(mem_ctx, io->out.name.scope); 130 131 talloc_free(req); 132 133 return NT_STATUS_OK; 134} 135 136/* 137 synchronous name registration request 138*/ 139_PUBLIC_ NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock, 140 TALLOC_CTX *mem_ctx, struct nbt_name_register *io) 141{ 142 struct nbt_name_request *req = nbt_name_register_send(nbtsock, io); 143 return nbt_name_register_recv(req, mem_ctx, io); 144} 145 146 147/* 148 a 4 step broadcast registration. 3 lots of name registration requests, followed by 149 a name registration demand 150*/ 151struct register_bcast_state { 152 struct nbt_name_socket *nbtsock; 153 struct nbt_name_register *io; 154 struct nbt_name_request *req; 155}; 156 157 158/* 159 state handler for 4 stage name registration 160*/ 161static void name_register_bcast_handler(struct nbt_name_request *req) 162{ 163 struct composite_context *c = talloc_get_type(req->async.private_data, struct composite_context); 164 struct register_bcast_state *state = talloc_get_type(c->private_data, struct register_bcast_state); 165 NTSTATUS status; 166 167 status = nbt_name_register_recv(state->req, state, state->io); 168 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { 169 if (state->io->in.register_demand == true) { 170 /* all done */ 171 c->state = COMPOSITE_STATE_DONE; 172 c->status = NT_STATUS_OK; 173 goto done; 174 } 175 176 /* the registration timed out - good, send the demand */ 177 state->io->in.register_demand = true; 178 state->io->in.retries = 0; 179 state->req = nbt_name_register_send(state->nbtsock, state->io); 180 if (state->req == NULL) { 181 c->state = COMPOSITE_STATE_ERROR; 182 c->status = NT_STATUS_NO_MEMORY; 183 } else { 184 state->req->async.fn = name_register_bcast_handler; 185 state->req->async.private_data = c; 186 } 187 } else if (!NT_STATUS_IS_OK(status)) { 188 c->state = COMPOSITE_STATE_ERROR; 189 c->status = status; 190 } else { 191 c->state = COMPOSITE_STATE_ERROR; 192 c->status = NT_STATUS_CONFLICTING_ADDRESSES; 193 DEBUG(3,("Name registration conflict from %s for %s with ip %s - rcode %d\n", 194 state->io->out.reply_from, 195 nbt_name_string(state, &state->io->out.name), 196 state->io->out.reply_addr, 197 state->io->out.rcode)); 198 } 199 200done: 201 if (c->state >= COMPOSITE_STATE_DONE && 202 c->async.fn) { 203 c->async.fn(c); 204 } 205} 206 207/* 208 the async send call for a 4 stage name registration 209*/ 210_PUBLIC_ struct composite_context *nbt_name_register_bcast_send(struct nbt_name_socket *nbtsock, 211 struct nbt_name_register_bcast *io) 212{ 213 struct composite_context *c; 214 struct register_bcast_state *state; 215 216 c = talloc_zero(nbtsock, struct composite_context); 217 if (c == NULL) goto failed; 218 219 state = talloc(c, struct register_bcast_state); 220 if (state == NULL) goto failed; 221 222 state->io = talloc(state, struct nbt_name_register); 223 if (state->io == NULL) goto failed; 224 225 state->io->in.name = io->in.name; 226 state->io->in.dest_addr = io->in.dest_addr; 227 state->io->in.dest_port = io->in.dest_port; 228 state->io->in.address = io->in.address; 229 state->io->in.nb_flags = io->in.nb_flags; 230 state->io->in.register_demand = false; 231 state->io->in.broadcast = true; 232 state->io->in.multi_homed = false; 233 state->io->in.ttl = io->in.ttl; 234 state->io->in.timeout = 1; 235 state->io->in.retries = 2; 236 237 state->nbtsock = nbtsock; 238 239 state->req = nbt_name_register_send(nbtsock, state->io); 240 if (state->req == NULL) goto failed; 241 242 state->req->async.fn = name_register_bcast_handler; 243 state->req->async.private_data = c; 244 245 c->private_data = state; 246 c->state = COMPOSITE_STATE_IN_PROGRESS; 247 c->event_ctx = nbtsock->event_ctx; 248 249 return c; 250 251failed: 252 talloc_free(c); 253 return NULL; 254} 255 256/* 257 broadcast 4 part name register - recv 258*/ 259_PUBLIC_ NTSTATUS nbt_name_register_bcast_recv(struct composite_context *c) 260{ 261 NTSTATUS status; 262 status = composite_wait(c); 263 talloc_free(c); 264 return status; 265} 266 267/* 268 broadcast 4 part name register - sync interface 269*/ 270NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock, 271 struct nbt_name_register_bcast *io) 272{ 273 struct composite_context *c = nbt_name_register_bcast_send(nbtsock, io); 274 return nbt_name_register_bcast_recv(c); 275} 276 277 278/* 279 a wins name register with multiple WINS servers and multiple 280 addresses to register. Try each WINS server in turn, until we get a 281 reply for each address 282*/ 283struct register_wins_state { 284 struct nbt_name_socket *nbtsock; 285 struct nbt_name_register *io; 286 const char **wins_servers; 287 uint16_t wins_port; 288 const char **addresses; 289 int address_idx; 290 struct nbt_name_request *req; 291}; 292 293 294/* 295 state handler for WINS multi-homed multi-server name register 296*/ 297static void name_register_wins_handler(struct nbt_name_request *req) 298{ 299 struct composite_context *c = talloc_get_type(req->async.private_data, 300 struct composite_context); 301 struct register_wins_state *state = talloc_get_type(c->private_data, 302 struct register_wins_state); 303 NTSTATUS status; 304 305 status = nbt_name_register_recv(state->req, state, state->io); 306 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { 307 /* the register timed out - try the next WINS server */ 308 state->wins_servers++; 309 state->address_idx = 0; 310 if (state->wins_servers[0] == NULL) { 311 c->state = COMPOSITE_STATE_ERROR; 312 c->status = status; 313 goto done; 314 } 315 state->io->in.dest_addr = state->wins_servers[0]; 316 state->io->in.dest_port = state->wins_port; 317 state->io->in.address = state->addresses[0]; 318 state->req = nbt_name_register_send(state->nbtsock, state->io); 319 if (state->req == NULL) { 320 c->state = COMPOSITE_STATE_ERROR; 321 c->status = NT_STATUS_NO_MEMORY; 322 } else { 323 state->req->async.fn = name_register_wins_handler; 324 state->req->async.private_data = c; 325 } 326 } else if (!NT_STATUS_IS_OK(status)) { 327 c->state = COMPOSITE_STATE_ERROR; 328 c->status = status; 329 } else { 330 if (state->io->out.rcode == 0 && 331 state->addresses[state->address_idx+1] != NULL) { 332 /* register our next address */ 333 state->io->in.address = state->addresses[++(state->address_idx)]; 334 state->req = nbt_name_register_send(state->nbtsock, state->io); 335 if (state->req == NULL) { 336 c->state = COMPOSITE_STATE_ERROR; 337 c->status = NT_STATUS_NO_MEMORY; 338 } else { 339 state->req->async.fn = name_register_wins_handler; 340 state->req->async.private_data = c; 341 } 342 } else { 343 c->state = COMPOSITE_STATE_DONE; 344 c->status = NT_STATUS_OK; 345 } 346 } 347 348done: 349 if (c->state >= COMPOSITE_STATE_DONE && 350 c->async.fn) { 351 c->async.fn(c); 352 } 353} 354 355/* 356 the async send call for a multi-server WINS register 357*/ 358_PUBLIC_ struct composite_context *nbt_name_register_wins_send(struct nbt_name_socket *nbtsock, 359 struct nbt_name_register_wins *io) 360{ 361 struct composite_context *c; 362 struct register_wins_state *state; 363 364 c = talloc_zero(nbtsock, struct composite_context); 365 if (c == NULL) goto failed; 366 367 state = talloc(c, struct register_wins_state); 368 if (state == NULL) goto failed; 369 370 state->io = talloc(state, struct nbt_name_register); 371 if (state->io == NULL) goto failed; 372 373 state->wins_port = io->in.wins_port; 374 state->wins_servers = (const char **)str_list_copy(state, io->in.wins_servers); 375 if (state->wins_servers == NULL || 376 state->wins_servers[0] == NULL) goto failed; 377 378 state->addresses = (const char **)str_list_copy(state, io->in.addresses); 379 if (state->addresses == NULL || 380 state->addresses[0] == NULL) goto failed; 381 382 state->io->in.name = io->in.name; 383 state->io->in.dest_addr = state->wins_servers[0]; 384 state->io->in.dest_port = state->wins_port; 385 state->io->in.address = io->in.addresses[0]; 386 state->io->in.nb_flags = io->in.nb_flags; 387 state->io->in.broadcast = false; 388 state->io->in.register_demand = false; 389 state->io->in.multi_homed = (io->in.nb_flags & NBT_NM_GROUP)?false:true; 390 state->io->in.ttl = io->in.ttl; 391 state->io->in.timeout = 3; 392 state->io->in.retries = 2; 393 394 state->nbtsock = nbtsock; 395 state->address_idx = 0; 396 397 state->req = nbt_name_register_send(nbtsock, state->io); 398 if (state->req == NULL) goto failed; 399 400 state->req->async.fn = name_register_wins_handler; 401 state->req->async.private_data = c; 402 403 c->private_data = state; 404 c->state = COMPOSITE_STATE_IN_PROGRESS; 405 c->event_ctx = nbtsock->event_ctx; 406 407 return c; 408 409failed: 410 talloc_free(c); 411 return NULL; 412} 413 414/* 415 multi-homed WINS name register - recv side 416*/ 417_PUBLIC_ NTSTATUS nbt_name_register_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 418 struct nbt_name_register_wins *io) 419{ 420 NTSTATUS status; 421 status = composite_wait(c); 422 if (NT_STATUS_IS_OK(status)) { 423 struct register_wins_state *state = 424 talloc_get_type(c->private_data, struct register_wins_state); 425 io->out.wins_server = talloc_steal(mem_ctx, state->wins_servers[0]); 426 io->out.rcode = state->io->out.rcode; 427 } 428 talloc_free(c); 429 return status; 430} 431 432/* 433 multi-homed WINS register - sync interface 434*/ 435_PUBLIC_ NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock, 436 TALLOC_CTX *mem_ctx, 437 struct nbt_name_register_wins *io) 438{ 439 struct composite_context *c = nbt_name_register_wins_send(nbtsock, io); 440 return nbt_name_register_wins_recv(c, mem_ctx, io); 441} 442