root/libcli/nbt/nbtsocket.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nbt_name_request_destructor
  2. nbt_name_socket_send
  3. nbt_name_socket_timeout
  4. nbt_name_socket_recv
  5. nbt_name_socket_handle_response_packet
  6. nbt_name_socket_handler
  7. nbt_name_socket_init
  8. nbt_name_request_send
  9. nbt_name_reply_send
  10. nbt_name_request_recv
  11. nbt_set_incoming_handler
  12. nbt_set_unexpected_handler
  13. nbt_rcode_to_ntstatus

   1 /*
   2    Unix SMB/CIFS implementation.
   3 
   4    low level socket handling for nbt requests
   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 "lib/events/events.h"
  24 #include "../lib/util/dlinklist.h"
  25 #include "../libcli/nbt/libnbt.h"
  26 #include "../libcli/nbt/nbt_proto.h"
  27 #include "lib/socket/socket.h"
  28 #include "librpc/gen_ndr/ndr_nbt.h"
  29 #include "param/param.h"
  30 
  31 #define NBT_MAX_REPLIES 1000
  32 
  33 /*
  34   destroy a pending request
  35 */
  36 static int nbt_name_request_destructor(struct nbt_name_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
  37 {
  38         if (req->state == NBT_REQUEST_SEND) {
  39                 DLIST_REMOVE(req->nbtsock->send_queue, req);
  40         }
  41         if (req->state == NBT_REQUEST_WAIT) {
  42                 req->nbtsock->num_pending--;
  43         }
  44         if (req->name_trn_id != 0 && !req->is_reply) {
  45                 idr_remove(req->nbtsock->idr, req->name_trn_id);
  46                 req->name_trn_id = 0;
  47         }
  48         if (req->te) {
  49                 talloc_free(req->te);
  50                 req->te = NULL;
  51         }
  52         if (req->nbtsock->send_queue == NULL) {
  53                 EVENT_FD_NOT_WRITEABLE(req->nbtsock->fde);
  54         }
  55         if (req->nbtsock->num_pending == 0 &&
  56             req->nbtsock->incoming.handler == NULL) {
  57                 EVENT_FD_NOT_READABLE(req->nbtsock->fde);
  58         }
  59         return 0;
  60 }
  61 
  62 
  63 /*
  64   handle send events on a nbt name socket
  65 */
  66 static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
     /* [<][>][^][v][top][bottom][index][help] */
  67 {
  68         struct nbt_name_request *req = nbtsock->send_queue;
  69         TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
  70         NTSTATUS status;
  71 
  72         while ((req = nbtsock->send_queue)) {
  73                 size_t len;
  74 
  75                 len = req->encoded.length;
  76                 status = socket_sendto(nbtsock->sock, &req->encoded, &len,
  77                                        req->dest);
  78                 if (NT_STATUS_IS_ERR(status)) goto failed;
  79 
  80                 if (!NT_STATUS_IS_OK(status)) {
  81                         talloc_free(tmp_ctx);
  82                         return;
  83                 }
  84 
  85                 DLIST_REMOVE(nbtsock->send_queue, req);
  86                 req->state = NBT_REQUEST_WAIT;
  87                 if (req->is_reply) {
  88                         talloc_free(req);
  89                 } else {
  90                         EVENT_FD_READABLE(nbtsock->fde);
  91                         nbtsock->num_pending++;
  92                 }
  93         }
  94 
  95         EVENT_FD_NOT_WRITEABLE(nbtsock->fde);
  96         talloc_free(tmp_ctx);
  97         return;
  98 
  99 failed:
 100         DLIST_REMOVE(nbtsock->send_queue, req);
 101         nbt_name_request_destructor(req);
 102         req->status = status;
 103         req->state = NBT_REQUEST_ERROR;
 104         talloc_free(tmp_ctx);
 105         if (req->async.fn) {
 106                 req->async.fn(req);
 107         } else if (req->is_reply) {
 108                 talloc_free(req);
 109         }
 110         return;
 111 }
 112 
 113 
 114 /*
 115   handle a request timeout
 116 */
 117 static void nbt_name_socket_timeout(struct tevent_context *ev, struct tevent_timer *te,
     /* [<][>][^][v][top][bottom][index][help] */
 118                                     struct timeval t, void *private_data)
 119 {
 120         struct nbt_name_request *req = talloc_get_type(private_data,
 121                                                        struct nbt_name_request);
 122 
 123         if (req->num_retries != 0) {
 124                 req->num_retries--;
 125                 req->te = event_add_timed(req->nbtsock->event_ctx, req,
 126                                           timeval_add(&t, req->timeout, 0),
 127                                           nbt_name_socket_timeout, req);
 128                 if (req->state != NBT_REQUEST_SEND) {
 129                         req->state = NBT_REQUEST_SEND;
 130                         DLIST_ADD_END(req->nbtsock->send_queue, req,
 131                                       struct nbt_name_request *);
 132                 }
 133                 EVENT_FD_WRITEABLE(req->nbtsock->fde);
 134                 return;
 135         }
 136 
 137         nbt_name_request_destructor(req);
 138         if (req->num_replies == 0) {
 139                 req->state = NBT_REQUEST_TIMEOUT;
 140                 req->status = NT_STATUS_IO_TIMEOUT;
 141         } else {
 142                 req->state = NBT_REQUEST_DONE;
 143                 req->status = NT_STATUS_OK;
 144         }
 145         if (req->async.fn) {
 146                 req->async.fn(req);
 147         } else if (req->is_reply) {
 148                 talloc_free(req);
 149         }
 150 }
 151 
 152 
 153 
 154 /**
 155   handle recv events on a nbt name socket
 156 */
 157 static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
     /* [<][>][^][v][top][bottom][index][help] */
 158 {
 159         TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
 160         NTSTATUS status;
 161         enum ndr_err_code ndr_err;
 162         struct socket_address *src;
 163         DATA_BLOB blob;
 164         size_t nread, dsize;
 165         struct nbt_name_packet *packet;
 166         struct nbt_name_request *req;
 167 
 168         status = socket_pending(nbtsock->sock, &dsize);
 169         if (!NT_STATUS_IS_OK(status)) {
 170                 talloc_free(tmp_ctx);
 171                 return;
 172         }
 173 
 174         blob = data_blob_talloc(tmp_ctx, NULL, dsize);
 175         if (blob.data == NULL) {
 176                 talloc_free(tmp_ctx);
 177                 return;
 178         }
 179 
 180         status = socket_recvfrom(nbtsock->sock, blob.data, blob.length, &nread,
 181                                  tmp_ctx, &src);
 182         if (!NT_STATUS_IS_OK(status)) {
 183                 talloc_free(tmp_ctx);
 184                 return;
 185         }
 186 
 187         packet = talloc(tmp_ctx, struct nbt_name_packet);
 188         if (packet == NULL) {
 189                 talloc_free(tmp_ctx);
 190                 return;
 191         }
 192 
 193         /* parse the request */
 194         ndr_err = ndr_pull_struct_blob(&blob, packet, nbtsock->iconv_convenience, packet,
 195                                        (ndr_pull_flags_fn_t)ndr_pull_nbt_name_packet);
 196         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 197                 status = ndr_map_error2ntstatus(ndr_err);
 198                 DEBUG(2,("Failed to parse incoming NBT name packet - %s\n",
 199                          nt_errstr(status)));
 200                 talloc_free(tmp_ctx);
 201                 return;
 202         }
 203 
 204         if (DEBUGLVL(10)) {
 205                 DEBUG(10,("Received nbt packet of length %d from %s:%d\n",
 206                           (int)blob.length, src->addr, src->port));
 207                 NDR_PRINT_DEBUG(nbt_name_packet, packet);
 208         }
 209 
 210         /* if its not a reply then pass it off to the incoming request
 211            handler, if any */
 212         if (!(packet->operation & NBT_FLAG_REPLY)) {
 213                 if (nbtsock->incoming.handler) {
 214                         nbtsock->incoming.handler(nbtsock, packet, src);
 215                 }
 216                 talloc_free(tmp_ctx);
 217                 return;
 218         }
 219 
 220         /* find the matching request */
 221         req = (struct nbt_name_request *)idr_find(nbtsock->idr,
 222                                                   packet->name_trn_id);
 223         if (req == NULL) {
 224                 if (nbtsock->unexpected.handler) {
 225                         nbtsock->unexpected.handler(nbtsock, packet, src);
 226                 } else {
 227                         DEBUG(10,("Failed to match request for incoming name packet id 0x%04x on %p\n",
 228                                  packet->name_trn_id, nbtsock));
 229                 }
 230                 talloc_free(tmp_ctx);
 231                 return;
 232         }
 233 
 234         talloc_steal(req, packet);
 235         talloc_steal(req, src);
 236         talloc_free(tmp_ctx);
 237         nbt_name_socket_handle_response_packet(req, packet, src);
 238 }
 239 
 240 void nbt_name_socket_handle_response_packet(struct nbt_name_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 241                                             struct nbt_name_packet *packet,
 242                                             struct socket_address *src)
 243 {
 244         /* if this is a WACK response, this we need to go back to waiting,
 245            but perhaps increase the timeout */
 246         if ((packet->operation & NBT_OPCODE) == NBT_OPCODE_WACK) {
 247                 uint32_t ttl;
 248                 if (req->received_wack || packet->ancount < 1) {
 249                         nbt_name_request_destructor(req);
 250                         req->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
 251                         req->state  = NBT_REQUEST_ERROR;
 252                         goto done;
 253                 }
 254                 talloc_free(req->te);
 255                 /* we know we won't need any more retries - the server
 256                    has received our request */
 257                 req->num_retries   = 0;
 258                 req->received_wack = true;
 259                 /*
 260                  * there is a timeout in the packet,
 261                  * it is 5 + 4 * num_old_addresses
 262                  *
 263                  * although w2k3 screws it up
 264                  * and uses num_old_addresses = 0
 265                  *
 266                  * so we better fallback to the maximum
 267                  * of num_old_addresses = 25 if we got
 268                  * a timeout of less than 9s (5 + 4*1)
 269                  * or more than 105s (5 + 4*25).
 270                  */
 271                 ttl = packet->answers[0].ttl;
 272                 if ((ttl < (5 + 4*1)) || (ttl > (5 + 4*25))) {
 273                         ttl = 5 + 4*25;
 274                 }
 275                 req->timeout = ttl;
 276                 req->te = event_add_timed(req->nbtsock->event_ctx, req,
 277                                           timeval_current_ofs(req->timeout, 0),
 278                                           nbt_name_socket_timeout, req);
 279                 return;
 280         }
 281 
 282 
 283         req->replies = talloc_realloc(req, req->replies, struct nbt_name_reply, req->num_replies+1);
 284         if (req->replies == NULL) {
 285                 nbt_name_request_destructor(req);
 286                 req->state  = NBT_REQUEST_ERROR;
 287                 req->status = NT_STATUS_NO_MEMORY;
 288                 goto done;
 289         }
 290 
 291         talloc_steal(req, src);
 292         req->replies[req->num_replies].dest   = src;
 293         talloc_steal(req, packet);
 294         req->replies[req->num_replies].packet = packet;
 295         req->num_replies++;
 296 
 297         /* if we don't want multiple replies then we are done */
 298         if (req->allow_multiple_replies &&
 299             req->num_replies < NBT_MAX_REPLIES) {
 300                 return;
 301         }
 302 
 303         nbt_name_request_destructor(req);
 304         req->state  = NBT_REQUEST_DONE;
 305         req->status = NT_STATUS_OK;
 306 
 307 done:
 308         if (req->async.fn) {
 309                 req->async.fn(req);
 310         }
 311 }
 312 
 313 /*
 314   handle fd events on a nbt_name_socket
 315 */
 316 static void nbt_name_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
     /* [<][>][^][v][top][bottom][index][help] */
 317                                     uint16_t flags, void *private_data)
 318 {
 319         struct nbt_name_socket *nbtsock = talloc_get_type(private_data,
 320                                                           struct nbt_name_socket);
 321         if (flags & EVENT_FD_WRITE) {
 322                 nbt_name_socket_send(nbtsock);
 323         }
 324         if (flags & EVENT_FD_READ) {
 325                 nbt_name_socket_recv(nbtsock);
 326         }
 327 }
 328 
 329 
 330 /*
 331   initialise a nbt_name_socket. The event_ctx is optional, if provided
 332   then operations will use that event context
 333 */
 334 _PUBLIC_ struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 335                                              struct tevent_context *event_ctx,
 336                                              struct smb_iconv_convenience *iconv_convenience)
 337 {
 338         struct nbt_name_socket *nbtsock;
 339         NTSTATUS status;
 340 
 341         nbtsock = talloc(mem_ctx, struct nbt_name_socket);
 342         if (nbtsock == NULL) goto failed;
 343 
 344         nbtsock->event_ctx = talloc_reference(nbtsock, event_ctx);
 345         if (nbtsock->event_ctx == NULL) goto failed;
 346 
 347         status = socket_create("ip", SOCKET_TYPE_DGRAM, &nbtsock->sock, 0);
 348         if (!NT_STATUS_IS_OK(status)) goto failed;
 349 
 350         socket_set_option(nbtsock->sock, "SO_BROADCAST", "1");
 351 
 352         talloc_steal(nbtsock, nbtsock->sock);
 353 
 354         nbtsock->idr = idr_init(nbtsock);
 355         if (nbtsock->idr == NULL) goto failed;
 356 
 357         nbtsock->send_queue = NULL;
 358         nbtsock->num_pending = 0;
 359         nbtsock->incoming.handler = NULL;
 360         nbtsock->unexpected.handler = NULL;
 361         nbtsock->iconv_convenience = iconv_convenience;
 362 
 363         nbtsock->fde = event_add_fd(nbtsock->event_ctx, nbtsock,
 364                                     socket_get_fd(nbtsock->sock), 0,
 365                                     nbt_name_socket_handler, nbtsock);
 366 
 367         return nbtsock;
 368 
 369 failed:
 370         talloc_free(nbtsock);
 371         return NULL;
 372 }
 373 
 374 /*
 375   send off a nbt name request
 376 */
 377 struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
     /* [<][>][^][v][top][bottom][index][help] */
 378                                                struct socket_address *dest,
 379                                                struct nbt_name_packet *request,
 380                                                int timeout, int retries,
 381                                                bool allow_multiple_replies)
 382 {
 383         struct nbt_name_request *req;
 384         int id;
 385         enum ndr_err_code ndr_err;
 386 
 387         req = talloc_zero(nbtsock, struct nbt_name_request);
 388         if (req == NULL) goto failed;
 389 
 390         req->nbtsock                = nbtsock;
 391         req->allow_multiple_replies = allow_multiple_replies;
 392         req->state                  = NBT_REQUEST_SEND;
 393         req->is_reply               = false;
 394         req->timeout                = timeout;
 395         req->num_retries            = retries;
 396         req->dest                   = dest;
 397         if (talloc_reference(req, dest) == NULL) goto failed;
 398 
 399         /* we select a random transaction id unless the user supplied one */
 400         if (request->name_trn_id == 0) {
 401                 id = idr_get_new_random(req->nbtsock->idr, req, UINT16_MAX);
 402         } else {
 403                 if (idr_find(req->nbtsock->idr, request->name_trn_id)) goto failed;
 404                 id = idr_get_new_above(req->nbtsock->idr, req, request->name_trn_id,
 405                                        UINT16_MAX);
 406         }
 407         if (id == -1) goto failed;
 408 
 409         request->name_trn_id = id;
 410         req->name_trn_id     = id;
 411 
 412         req->te = event_add_timed(nbtsock->event_ctx, req,
 413                                   timeval_current_ofs(req->timeout, 0),
 414                                   nbt_name_socket_timeout, req);
 415 
 416         talloc_set_destructor(req, nbt_name_request_destructor);
 417 
 418         ndr_err = ndr_push_struct_blob(&req->encoded, req,
 419                                        req->nbtsock->iconv_convenience,
 420                                        request,
 421                                        (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
 422         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
 423 
 424         DLIST_ADD_END(nbtsock->send_queue, req, struct nbt_name_request *);
 425 
 426         if (DEBUGLVL(10)) {
 427                 DEBUG(10,("Queueing nbt packet to %s:%d\n",
 428                           req->dest->addr, req->dest->port));
 429                 NDR_PRINT_DEBUG(nbt_name_packet, request);
 430         }
 431 
 432         EVENT_FD_WRITEABLE(nbtsock->fde);
 433 
 434         return req;
 435 
 436 failed:
 437         talloc_free(req);
 438         return NULL;
 439 }
 440 
 441 
 442 /*
 443   send off a nbt name reply
 444 */
 445 _PUBLIC_ NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
     /* [<][>][^][v][top][bottom][index][help] */
 446                              struct socket_address *dest,
 447                              struct nbt_name_packet *request)
 448 {
 449         struct nbt_name_request *req;
 450         enum ndr_err_code ndr_err;
 451 
 452         req = talloc_zero(nbtsock, struct nbt_name_request);
 453         NT_STATUS_HAVE_NO_MEMORY(req);
 454 
 455         req->nbtsock   = nbtsock;
 456         req->dest = dest;
 457         if (talloc_reference(req, dest) == NULL) goto failed;
 458         req->state     = NBT_REQUEST_SEND;
 459         req->is_reply = true;
 460 
 461         talloc_set_destructor(req, nbt_name_request_destructor);
 462 
 463         if (DEBUGLVL(10)) {
 464                 NDR_PRINT_DEBUG(nbt_name_packet, request);
 465         }
 466 
 467         ndr_err = ndr_push_struct_blob(&req->encoded, req,
 468                                        req->nbtsock->iconv_convenience,
 469                                        request,
 470                                        (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
 471         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 472                 talloc_free(req);
 473                 return ndr_map_error2ntstatus(ndr_err);
 474         }
 475 
 476         DLIST_ADD_END(nbtsock->send_queue, req, struct nbt_name_request *);
 477 
 478         EVENT_FD_WRITEABLE(nbtsock->fde);
 479 
 480         return NT_STATUS_OK;
 481 
 482 failed:
 483         talloc_free(req);
 484         return NT_STATUS_NO_MEMORY;
 485 }
 486 
 487 /*
 488   wait for a nbt request to complete
 489 */
 490 NTSTATUS nbt_name_request_recv(struct nbt_name_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 491 {
 492         if (!req) return NT_STATUS_NO_MEMORY;
 493 
 494         while (req->state < NBT_REQUEST_DONE) {
 495                 if (event_loop_once(req->nbtsock->event_ctx) != 0) {
 496                         req->state = NBT_REQUEST_ERROR;
 497                         req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
 498                         break;
 499                 }
 500         }
 501         return req->status;
 502 }
 503 
 504 
 505 /*
 506   setup a handler for incoming requests
 507 */
 508 _PUBLIC_ NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
     /* [<][>][^][v][top][bottom][index][help] */
 509                                   void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
 510                                                   struct socket_address *),
 511                                   void *private_data)
 512 {
 513         nbtsock->incoming.handler = handler;
 514         nbtsock->incoming.private_data = private_data;
 515         EVENT_FD_READABLE(nbtsock->fde);
 516         return NT_STATUS_OK;
 517 }
 518 
 519 /*
 520   setup a handler for unexpected requests
 521 */
 522 NTSTATUS nbt_set_unexpected_handler(struct nbt_name_socket *nbtsock,
     /* [<][>][^][v][top][bottom][index][help] */
 523                                     void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
 524                                                     struct socket_address *),
 525                                     void *private_data)
 526 {
 527         nbtsock->unexpected.handler = handler;
 528         nbtsock->unexpected.private_data = private_data;
 529         EVENT_FD_READABLE(nbtsock->fde);
 530         return NT_STATUS_OK;
 531 }
 532 
 533 /*
 534   turn a NBT rcode into a NTSTATUS
 535 */
 536 _PUBLIC_ NTSTATUS nbt_rcode_to_ntstatus(uint8_t rcode)
     /* [<][>][^][v][top][bottom][index][help] */
 537 {
 538         int i;
 539         struct {
 540                 enum nbt_rcode rcode;
 541                 NTSTATUS status;
 542         } map[] = {
 543                 { NBT_RCODE_FMT, NT_STATUS_INVALID_PARAMETER },
 544                 { NBT_RCODE_SVR, NT_STATUS_SERVER_DISABLED },
 545                 { NBT_RCODE_NAM, NT_STATUS_OBJECT_NAME_NOT_FOUND },
 546                 { NBT_RCODE_IMP, NT_STATUS_NOT_SUPPORTED },
 547                 { NBT_RCODE_RFS, NT_STATUS_ACCESS_DENIED },
 548                 { NBT_RCODE_ACT, NT_STATUS_ADDRESS_ALREADY_EXISTS },
 549                 { NBT_RCODE_CFT, NT_STATUS_CONFLICTING_ADDRESSES }
 550         };
 551         for (i=0;i<ARRAY_SIZE(map);i++) {
 552                 if (map[i].rcode == rcode) {
 553                         return map[i].status;
 554                 }
 555         }
 556         return NT_STATUS_UNSUCCESSFUL;
 557 }

/* [<][>][^][v][top][bottom][index][help] */