1/* 2 Unix SMB/CIFS implementation. 3 Connect to 445 and 139/nbsesssetup 4 Copyright (C) Volker Lendecke 2010 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 "../lib/async_req/async_sock.h" 22#include "async_smb.h" 23 24struct nb_connect_state { 25 struct tevent_context *ev; 26 const struct sockaddr_storage *addr; 27 const char *called_name; 28 int sock; 29 30 struct nmb_name called; 31 struct nmb_name calling; 32}; 33 34static int nb_connect_state_destructor(struct nb_connect_state *state); 35static void nb_connect_connected(struct tevent_req *subreq); 36static void nb_connect_done(struct tevent_req *subreq); 37 38static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx, 39 struct tevent_context *ev, 40 const struct sockaddr_storage *addr, 41 const char *called_name, 42 int called_type, 43 const char *calling_name, 44 int calling_type) 45{ 46 struct tevent_req *req, *subreq; 47 struct nb_connect_state *state; 48 49 req = tevent_req_create(mem_ctx, &state, struct nb_connect_state); 50 if (req == NULL) { 51 return NULL; 52 } 53 state->ev = ev; 54 state->called_name = called_name; 55 state->addr = addr; 56 57 state->sock = -1; 58 make_nmb_name(&state->called, called_name, called_type); 59 make_nmb_name(&state->calling, calling_name, calling_type); 60 61 talloc_set_destructor(state, nb_connect_state_destructor); 62 63 subreq = open_socket_out_send(state, ev, addr, 139, 5000); 64 if (tevent_req_nomem(subreq, req)) { 65 return tevent_req_post(req, ev); 66 } 67 tevent_req_set_callback(subreq, nb_connect_connected, req); 68 return req; 69} 70 71static int nb_connect_state_destructor(struct nb_connect_state *state) 72{ 73 if (state->sock != -1) { 74 close(state->sock); 75 } 76 return 0; 77} 78 79static void nb_connect_connected(struct tevent_req *subreq) 80{ 81 struct tevent_req *req = tevent_req_callback_data( 82 subreq, struct tevent_req); 83 struct nb_connect_state *state = tevent_req_data( 84 req, struct nb_connect_state); 85 NTSTATUS status; 86 87 status = open_socket_out_recv(subreq, &state->sock); 88 TALLOC_FREE(subreq); 89 if (!NT_STATUS_IS_OK(status)) { 90 tevent_req_nterror(req, status); 91 return; 92 } 93 subreq = cli_session_request_send(state, state->ev, state->sock, 94 &state->called, &state->calling); 95 if (tevent_req_nomem(subreq, req)) { 96 return; 97 } 98 tevent_req_set_callback(subreq, nb_connect_done, req); 99} 100 101static void nb_connect_done(struct tevent_req *subreq) 102{ 103 struct tevent_req *req = tevent_req_callback_data( 104 subreq, struct tevent_req); 105 struct nb_connect_state *state = tevent_req_data( 106 req, struct nb_connect_state); 107 bool ret; 108 int err; 109 uint8_t resp; 110 111 ret = cli_session_request_recv(subreq, &err, &resp); 112 TALLOC_FREE(subreq); 113 if (!ret) { 114 tevent_req_nterror(req, map_nt_error_from_unix(err)); 115 return; 116 } 117 118 /* 119 * RFC1002: 0x82 - POSITIVE SESSION RESPONSE 120 */ 121 122 if (resp != 0x82) { 123 /* 124 * The server did not like our session request 125 */ 126 close(state->sock); 127 state->sock = -1; 128 129 if (strequal(state->called_name, "*SMBSERVER")) { 130 /* 131 * Here we could try a name status request and 132 * use the first 0x20 type name. 133 */ 134 tevent_req_nterror( 135 req, NT_STATUS_RESOURCE_NAME_NOT_FOUND); 136 return; 137 } 138 139 /* 140 * We could be subtle and distinguish between 141 * different failure modes, but what we do here 142 * instead is just retry with *SMBSERVER type 0x20. 143 */ 144 state->called_name = "*SMBSERVER"; 145 make_nmb_name(&state->called, state->called_name, 0x20); 146 147 subreq = open_socket_out_send(state, state->ev, state->addr, 148 139, 5000); 149 if (tevent_req_nomem(subreq, req)) { 150 return; 151 } 152 tevent_req_set_callback(subreq, nb_connect_connected, req); 153 return; 154 } 155 156 tevent_req_done(req); 157 return; 158 159} 160 161static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock) 162{ 163 struct nb_connect_state *state = tevent_req_data( 164 req, struct nb_connect_state); 165 NTSTATUS status; 166 167 if (tevent_req_is_nterror(req, &status)) { 168 return status; 169 } 170 *sock = state->sock; 171 state->sock = -1; 172 return NT_STATUS_OK; 173} 174 175struct smbsock_connect_state { 176 struct tevent_context *ev; 177 const struct sockaddr_storage *addr; 178 const char *called_name; 179 const char *calling_name; 180 struct tevent_req *req_139; 181 struct tevent_req *req_445; 182 int sock; 183 uint16_t port; 184}; 185 186static int smbsock_connect_state_destructor( 187 struct smbsock_connect_state *state); 188static void smbsock_connect_connected(struct tevent_req *subreq); 189static void smbsock_connect_do_139(struct tevent_req *subreq); 190 191struct tevent_req *smbsock_connect_send(TALLOC_CTX *mem_ctx, 192 struct tevent_context *ev, 193 const struct sockaddr_storage *addr, 194 const char *called_name, 195 const char *calling_name) 196{ 197 struct tevent_req *req, *subreq; 198 struct smbsock_connect_state *state; 199 200 req = tevent_req_create(mem_ctx, &state, struct smbsock_connect_state); 201 if (req == NULL) { 202 return NULL; 203 } 204 state->ev = ev; 205 state->addr = addr; 206 state->sock = -1; 207 state->called_name = 208 (called_name != NULL) ? called_name : "*SMBSERVER"; 209 state->calling_name = 210 (calling_name != NULL) ? calling_name : global_myname(); 211 212 talloc_set_destructor(state, smbsock_connect_state_destructor); 213 214 state->req_445 = open_socket_out_send(state, ev, addr, 445, 5000); 215 if (tevent_req_nomem(state->req_445, req)) { 216 return tevent_req_post(req, ev); 217 } 218 tevent_req_set_callback(state->req_445, smbsock_connect_connected, 219 req); 220 221 /* 222 * After 5 msecs, fire the 139 request 223 */ 224 state->req_139 = tevent_wakeup_send( 225 state, ev, timeval_current_ofs(0, 5000)); 226 if (tevent_req_nomem(state->req_139, req)) { 227 TALLOC_FREE(state->req_445); 228 return tevent_req_post(req, ev); 229 } 230 tevent_req_set_callback(state->req_139, smbsock_connect_do_139, 231 req); 232 return req; 233} 234 235static int smbsock_connect_state_destructor( 236 struct smbsock_connect_state *state) 237{ 238 if (state->sock != -1) { 239 close(state->sock); 240 } 241 return 0; 242} 243 244static void smbsock_connect_do_139(struct tevent_req *subreq) 245{ 246 struct tevent_req *req = tevent_req_callback_data( 247 subreq, struct tevent_req); 248 struct smbsock_connect_state *state = tevent_req_data( 249 req, struct smbsock_connect_state); 250 bool ret; 251 252 ret = tevent_wakeup_recv(subreq); 253 TALLOC_FREE(subreq); 254 if (!ret) { 255 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); 256 return; 257 } 258 state->req_139 = nb_connect_send(state, state->ev, state->addr, 259 state->called_name, 0x20, 260 state->calling_name, 0x0); 261 if (tevent_req_nomem(state->req_139, req)) { 262 return; 263 } 264 tevent_req_set_callback(state->req_139, smbsock_connect_connected, 265 req); 266} 267 268static void smbsock_connect_connected(struct tevent_req *subreq) 269{ 270 struct tevent_req *req = tevent_req_callback_data( 271 subreq, struct tevent_req); 272 struct smbsock_connect_state *state = tevent_req_data( 273 req, struct smbsock_connect_state); 274 struct tevent_req *unfinished_req; 275 NTSTATUS status; 276 277 if (subreq == state->req_445) { 278 279 status = open_socket_out_recv(subreq, &state->sock); 280 TALLOC_FREE(state->req_445); 281 unfinished_req = state->req_139; 282 state->port = 445; 283 284 } else if (subreq == state->req_139) { 285 286 status = nb_connect_recv(subreq, &state->sock); 287 TALLOC_FREE(state->req_139); 288 unfinished_req = state->req_445; 289 state->port = 139; 290 291 } else { 292 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); 293 return; 294 } 295 296 if (NT_STATUS_IS_OK(status)) { 297 TALLOC_FREE(unfinished_req); 298 state->req_139 = NULL; 299 state->req_445 = NULL; 300 tevent_req_done(req); 301 return; 302 } 303 if (unfinished_req == NULL) { 304 /* 305 * Both requests failed 306 */ 307 tevent_req_nterror(req, status); 308 return; 309 } 310 /* 311 * Do nothing, wait for the second request to come here. 312 */ 313} 314 315NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock, 316 uint16_t *port) 317{ 318 struct smbsock_connect_state *state = tevent_req_data( 319 req, struct smbsock_connect_state); 320 NTSTATUS status; 321 322 if (tevent_req_is_nterror(req, &status)) { 323 return status; 324 } 325 *sock = state->sock; 326 state->sock = -1; 327 if (port != NULL) { 328 *port = state->port; 329 } 330 return NT_STATUS_OK; 331} 332 333NTSTATUS smbsock_connect(const struct sockaddr_storage *addr, 334 const char *called_name, const char *calling_name, 335 int *pfd, uint16_t *port) 336{ 337 TALLOC_CTX *frame = talloc_stackframe(); 338 struct event_context *ev; 339 struct tevent_req *req; 340 NTSTATUS status = NT_STATUS_NO_MEMORY; 341 342 ev = event_context_init(frame); 343 if (ev == NULL) { 344 goto fail; 345 } 346 req = smbsock_connect_send(frame, ev, addr, called_name, calling_name); 347 if (req == NULL) { 348 goto fail; 349 } 350 if (!tevent_req_poll_ntstatus(req, ev, &status)) { 351 goto fail; 352 } 353 status = smbsock_connect_recv(req, pfd, port); 354 fail: 355 TALLOC_FREE(frame); 356 return status; 357} 358 359struct smbsock_any_connect_state { 360 struct tevent_context *ev; 361 const struct sockaddr_storage *addrs; 362 const char **called_names; 363 size_t num_addrs; 364 365 struct tevent_req **requests; 366 size_t num_sent; 367 size_t num_received; 368 369 int fd; 370 uint16_t port; 371 size_t chosen_index; 372}; 373 374static bool smbsock_any_connect_send_next( 375 struct tevent_req *req, struct smbsock_any_connect_state *state); 376static void smbsock_any_connect_trynext(struct tevent_req *subreq); 377static void smbsock_any_connect_connected(struct tevent_req *subreq); 378 379struct tevent_req *smbsock_any_connect_send(TALLOC_CTX *mem_ctx, 380 struct tevent_context *ev, 381 const struct sockaddr_storage *addrs, 382 const char **called_names, 383 size_t num_addrs) 384{ 385 struct tevent_req *req, *subreq; 386 struct smbsock_any_connect_state *state; 387 388 req = tevent_req_create(mem_ctx, &state, 389 struct smbsock_any_connect_state); 390 if (req == NULL) { 391 return NULL; 392 } 393 state->ev = ev; 394 state->addrs = addrs; 395 state->num_addrs = num_addrs; 396 state->called_names = called_names; 397 398 if (num_addrs == 0) { 399 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); 400 return tevent_req_post(req, ev); 401 } 402 403 state->requests = talloc_zero_array(state, struct tevent_req *, 404 num_addrs); 405 if (tevent_req_nomem(state->requests, req)) { 406 return tevent_req_post(req, ev); 407 } 408 if (!smbsock_any_connect_send_next(req, state)) { 409 return tevent_req_post(req, ev); 410 } 411 if (state->num_sent >= state->num_addrs) { 412 return req; 413 } 414 subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 10000)); 415 if (tevent_req_nomem(subreq, req)) { 416 return tevent_req_post(req, ev); 417 } 418 tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req); 419 return req; 420} 421 422static void smbsock_any_connect_trynext(struct tevent_req *subreq) 423{ 424 struct tevent_req *req = tevent_req_callback_data( 425 subreq, struct tevent_req); 426 struct smbsock_any_connect_state *state = tevent_req_data( 427 req, struct smbsock_any_connect_state); 428 bool ret; 429 430 ret = tevent_wakeup_recv(subreq); 431 TALLOC_FREE(subreq); 432 if (!ret) { 433 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); 434 return; 435 } 436 if (!smbsock_any_connect_send_next(req, state)) { 437 return; 438 } 439 if (state->num_sent >= state->num_addrs) { 440 return; 441 } 442 subreq = tevent_wakeup_send(state, state->ev, 443 tevent_timeval_set(0, 10000)); 444 if (tevent_req_nomem(subreq, req)) { 445 return; 446 } 447 tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req); 448} 449 450static bool smbsock_any_connect_send_next( 451 struct tevent_req *req, struct smbsock_any_connect_state *state) 452{ 453 struct tevent_req *subreq; 454 455 if (state->num_sent >= state->num_addrs) { 456 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); 457 return false; 458 } 459 subreq = smbsock_connect_send( 460 state->requests, state->ev, &state->addrs[state->num_sent], 461 (state->called_names != NULL) 462 ? state->called_names[state->num_sent] : NULL, 463 NULL); 464 if (tevent_req_nomem(subreq, req)) { 465 return false; 466 } 467 tevent_req_set_callback(subreq, smbsock_any_connect_connected, req); 468 469 state->requests[state->num_sent] = subreq; 470 state->num_sent += 1; 471 472 return true; 473} 474 475static void smbsock_any_connect_connected(struct tevent_req *subreq) 476{ 477 struct tevent_req *req = tevent_req_callback_data( 478 subreq, struct tevent_req); 479 struct smbsock_any_connect_state *state = tevent_req_data( 480 req, struct smbsock_any_connect_state); 481 NTSTATUS status; 482 int fd; 483 uint16_t port; 484 size_t i; 485 size_t chosen_index = 0; 486 487 for (i=0; i<state->num_sent; i++) { 488 if (state->requests[i] == subreq) { 489 chosen_index = i; 490 break; 491 } 492 } 493 if (i == state->num_sent) { 494 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); 495 return; 496 } 497 498 status = smbsock_connect_recv(subreq, &fd, &port); 499 500 TALLOC_FREE(subreq); 501 state->requests[chosen_index] = NULL; 502 503 if (NT_STATUS_IS_OK(status)) { 504 /* 505 * This will kill all the other requests 506 */ 507 TALLOC_FREE(state->requests); 508 state->fd = fd; 509 state->port = port; 510 state->chosen_index = chosen_index; 511 tevent_req_done(req); 512 return; 513 } 514 515 state->num_received += 1; 516 if (state->num_received <= state->num_addrs) { 517 /* 518 * More addrs pending, wait for the others 519 */ 520 return; 521 } 522 523 /* 524 * This is the last response, none succeeded. 525 */ 526 tevent_req_nterror(req, status); 527 return; 528} 529 530NTSTATUS smbsock_any_connect_recv(struct tevent_req *req, int *pfd, 531 size_t *chosen_index, uint16_t *port) 532{ 533 struct smbsock_any_connect_state *state = tevent_req_data( 534 req, struct smbsock_any_connect_state); 535 NTSTATUS status; 536 537 if (tevent_req_is_nterror(req, &status)) { 538 return status; 539 } 540 *pfd = state->fd; 541 if (chosen_index != NULL) { 542 *chosen_index = state->chosen_index; 543 } 544 if (port != NULL) { 545 *port = state->port; 546 } 547 return NT_STATUS_OK; 548} 549 550NTSTATUS smbsock_any_connect(const struct sockaddr_storage *addrs, 551 const char **called_names, size_t num_addrs, 552 int *pfd, size_t *chosen_index, uint16_t *port) 553{ 554 TALLOC_CTX *frame = talloc_stackframe(); 555 struct event_context *ev; 556 struct tevent_req *req; 557 NTSTATUS status = NT_STATUS_NO_MEMORY; 558 559 ev = event_context_init(frame); 560 if (ev == NULL) { 561 goto fail; 562 } 563 req = smbsock_any_connect_send(frame, ev, addrs, called_names, 564 num_addrs); 565 if (req == NULL) { 566 goto fail; 567 } 568 if (!tevent_req_poll_ntstatus(req, ev, &status)) { 569 goto fail; 570 } 571 status = smbsock_any_connect_recv(req, pfd, chosen_index, port); 572 fail: 573 TALLOC_FREE(frame); 574 return status; 575} 576