1/* 2 Unix SMB/CIFS implementation. 3 4 send out a name refresh 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 28/* 29 send a nbt name refresh request 30*/ 31struct nbt_name_request *nbt_name_refresh_send(struct nbt_name_socket *nbtsock, 32 struct nbt_name_refresh *io) 33{ 34 struct nbt_name_request *req; 35 struct nbt_name_packet *packet; 36 struct socket_address *dest; 37 38 packet = talloc_zero(nbtsock, struct nbt_name_packet); 39 if (packet == NULL) return NULL; 40 41 packet->qdcount = 1; 42 packet->arcount = 1; 43 packet->operation = NBT_OPCODE_REFRESH; 44 if (io->in.broadcast) { 45 packet->operation |= NBT_FLAG_BROADCAST; 46 } 47 48 packet->questions = talloc_array(packet, struct nbt_name_question, 1); 49 if (packet->questions == NULL) goto failed; 50 51 packet->questions[0].name = io->in.name; 52 packet->questions[0].question_type = NBT_QTYPE_NETBIOS; 53 packet->questions[0].question_class = NBT_QCLASS_IP; 54 55 packet->additional = talloc_array(packet, struct nbt_res_rec, 1); 56 if (packet->additional == NULL) goto failed; 57 58 packet->additional[0].name = io->in.name; 59 packet->additional[0].rr_type = NBT_QTYPE_NETBIOS; 60 packet->additional[0].rr_class = NBT_QCLASS_IP; 61 packet->additional[0].ttl = io->in.ttl; 62 packet->additional[0].rdata.netbios.length = 6; 63 packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional, 64 struct nbt_rdata_address, 1); 65 if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed; 66 packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags; 67 packet->additional[0].rdata.netbios.addresses[0].ipaddr = 68 talloc_strdup(packet->additional, io->in.address); 69 70 dest = socket_address_from_strings(nbtsock, 71 nbtsock->sock->backend_name, 72 io->in.dest_addr, io->in.dest_port); 73 if (dest == NULL) goto failed; 74 req = nbt_name_request_send(nbtsock, dest, packet, 75 io->in.timeout, io->in.retries, false); 76 if (req == NULL) goto failed; 77 78 talloc_free(packet); 79 return req; 80 81failed: 82 talloc_free(packet); 83 return NULL; 84} 85 86/* 87 wait for a refresh reply 88*/ 89_PUBLIC_ NTSTATUS nbt_name_refresh_recv(struct nbt_name_request *req, 90 TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io) 91{ 92 NTSTATUS status; 93 struct nbt_name_packet *packet; 94 95 status = nbt_name_request_recv(req); 96 if (!NT_STATUS_IS_OK(status) || 97 req->num_replies == 0) { 98 talloc_free(req); 99 return status; 100 } 101 102 packet = req->replies[0].packet; 103 io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr); 104 105 if (packet->ancount != 1 || 106 packet->answers[0].rr_type != NBT_QTYPE_NETBIOS || 107 packet->answers[0].rr_class != NBT_QCLASS_IP) { 108 talloc_free(req); 109 return NT_STATUS_INVALID_NETWORK_RESPONSE; 110 } 111 112 io->out.rcode = packet->operation & NBT_RCODE; 113 io->out.name = packet->answers[0].name; 114 if (packet->answers[0].rdata.netbios.length < 6) { 115 talloc_free(req); 116 return NT_STATUS_INVALID_NETWORK_RESPONSE; 117 } 118 io->out.reply_addr = talloc_steal(mem_ctx, 119 packet->answers[0].rdata.netbios.addresses[0].ipaddr); 120 talloc_steal(mem_ctx, io->out.name.name); 121 talloc_steal(mem_ctx, io->out.name.scope); 122 123 talloc_free(req); 124 125 return NT_STATUS_OK; 126} 127 128/* 129 synchronous name refresh request 130*/ 131_PUBLIC_ NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock, 132 TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io) 133{ 134 struct nbt_name_request *req = nbt_name_refresh_send(nbtsock, io); 135 return nbt_name_refresh_recv(req, mem_ctx, io); 136} 137 138 139 140/** 141 a wins name refresh with multiple WINS servers and multiple 142 addresses to refresh. Try each WINS server in turn, until we get a 143 reply for each address 144*/ 145struct refresh_wins_state { 146 struct nbt_name_socket *nbtsock; 147 struct nbt_name_refresh *io; 148 const char **wins_servers; 149 uint16_t wins_port; 150 const char **addresses; 151 int address_idx; 152 struct nbt_name_request *req; 153}; 154 155 156/** 157 state handler for WINS multi-homed multi-server name refresh 158*/ 159static void name_refresh_wins_handler(struct nbt_name_request *req) 160{ 161 struct composite_context *c = talloc_get_type(req->async.private_data, 162 struct composite_context); 163 struct refresh_wins_state *state = talloc_get_type(c->private_data, 164 struct refresh_wins_state); 165 NTSTATUS status; 166 167 status = nbt_name_refresh_recv(state->req, state, state->io); 168 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { 169 /* the refresh timed out - try the next WINS server */ 170 state->wins_servers++; 171 state->address_idx = 0; 172 if (state->wins_servers[0] == NULL) { 173 c->state = COMPOSITE_STATE_ERROR; 174 c->status = status; 175 goto done; 176 } 177 state->io->in.dest_addr = state->wins_servers[0]; 178 state->io->in.dest_port = state->wins_port; 179 state->io->in.address = state->addresses[0]; 180 state->req = nbt_name_refresh_send(state->nbtsock, state->io); 181 if (state->req == NULL) { 182 c->state = COMPOSITE_STATE_ERROR; 183 c->status = NT_STATUS_NO_MEMORY; 184 } else { 185 state->req->async.fn = name_refresh_wins_handler; 186 state->req->async.private_data = c; 187 } 188 } else if (!NT_STATUS_IS_OK(status)) { 189 c->state = COMPOSITE_STATE_ERROR; 190 c->status = status; 191 } else { 192 if (state->io->out.rcode == 0 && 193 state->addresses[state->address_idx+1] != NULL) { 194 /* refresh our next address */ 195 state->io->in.address = state->addresses[++(state->address_idx)]; 196 state->req = nbt_name_refresh_send(state->nbtsock, state->io); 197 if (state->req == NULL) { 198 c->state = COMPOSITE_STATE_ERROR; 199 c->status = NT_STATUS_NO_MEMORY; 200 } else { 201 state->req->async.fn = name_refresh_wins_handler; 202 state->req->async.private_data = c; 203 } 204 } else { 205 c->state = COMPOSITE_STATE_DONE; 206 c->status = NT_STATUS_OK; 207 } 208 } 209 210done: 211 if (c->state >= COMPOSITE_STATE_DONE && 212 c->async.fn) { 213 c->async.fn(c); 214 } 215} 216 217/** 218 the async send call for a multi-server WINS refresh 219*/ 220_PUBLIC_ struct composite_context *nbt_name_refresh_wins_send(struct nbt_name_socket *nbtsock, 221 struct nbt_name_refresh_wins *io) 222{ 223 struct composite_context *c; 224 struct refresh_wins_state *state; 225 226 c = talloc_zero(nbtsock, struct composite_context); 227 if (c == NULL) goto failed; 228 229 state = talloc(c, struct refresh_wins_state); 230 if (state == NULL) goto failed; 231 232 state->io = talloc(state, struct nbt_name_refresh); 233 if (state->io == NULL) goto failed; 234 235 state->wins_port = io->in.wins_port; 236 state->wins_servers = (const char **)str_list_copy(state, io->in.wins_servers); 237 if (state->wins_servers == NULL || 238 state->wins_servers[0] == NULL) goto failed; 239 240 state->addresses = (const char **)str_list_copy(state, io->in.addresses); 241 if (state->addresses == NULL || 242 state->addresses[0] == NULL) goto failed; 243 244 state->io->in.name = io->in.name; 245 state->io->in.dest_addr = state->wins_servers[0]; 246 state->io->in.dest_port = state->wins_port; 247 state->io->in.address = io->in.addresses[0]; 248 state->io->in.nb_flags = io->in.nb_flags; 249 state->io->in.broadcast = false; 250 state->io->in.ttl = io->in.ttl; 251 state->io->in.timeout = 2; 252 state->io->in.retries = 2; 253 254 state->nbtsock = nbtsock; 255 state->address_idx = 0; 256 257 state->req = nbt_name_refresh_send(nbtsock, state->io); 258 if (state->req == NULL) goto failed; 259 260 state->req->async.fn = name_refresh_wins_handler; 261 state->req->async.private_data = c; 262 263 c->private_data = state; 264 c->state = COMPOSITE_STATE_IN_PROGRESS; 265 c->event_ctx = nbtsock->event_ctx; 266 267 return c; 268 269failed: 270 talloc_free(c); 271 return NULL; 272} 273 274/* 275 multi-homed WINS name refresh - recv side 276*/ 277_PUBLIC_ NTSTATUS nbt_name_refresh_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 278 struct nbt_name_refresh_wins *io) 279{ 280 NTSTATUS status; 281 status = composite_wait(c); 282 if (NT_STATUS_IS_OK(status)) { 283 struct refresh_wins_state *state = 284 talloc_get_type(c->private_data, struct refresh_wins_state); 285 io->out.wins_server = talloc_steal(mem_ctx, state->wins_servers[0]); 286 io->out.rcode = state->io->out.rcode; 287 } 288 talloc_free(c); 289 return status; 290} 291 292/* 293 multi-homed WINS refresh - sync interface 294*/ 295_PUBLIC_ NTSTATUS nbt_name_refresh_wins(struct nbt_name_socket *nbtsock, 296 TALLOC_CTX *mem_ctx, 297 struct nbt_name_refresh_wins *io) 298{ 299 struct composite_context *c = nbt_name_refresh_wins_send(nbtsock, io); 300 return nbt_name_refresh_wins_recv(c, mem_ctx, io); 301} 302