root/source4/nbt_server/wins/winsserver.c

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

DEFINITIONS

This source file includes following definitions.
  1. wins_server_ttl
  2. wrepl_type
  3. wins_register_new
  4. wins_update_ttl
  5. wins_sgroup_merge
  6. nbtd_wins_wack_state_destructor
  7. wins_check_wack_queue
  8. wins_wack_deny
  9. wins_wack_allow
  10. wack_wins_challenge_handler
  11. wins_register_wack
  12. nbtd_winsserver_register
  13. ipv4_match_bits
  14. nbtd_wins_randomize1Clist_sort
  15. nbtd_wins_randomize1Clist
  16. nbtd_winsserver_query
  17. nbtd_winsserver_release
  18. nbtd_winsserver_request
  19. nbtd_winsserver_init

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    core wins server handling
   5 
   6    Copyright (C) Andrew Tridgell        2005
   7    Copyright (C) Stefan Metzmacher      2005
   8       
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 3 of the License, or
  12    (at your option) any later version.
  13    
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18    
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 #include "includes.h"
  24 #include "dlinklist.h"
  25 #include "nbt_server/nbt_server.h"
  26 #include "nbt_server/wins/winsdb.h"
  27 #include "nbt_server/wins/winsserver.h"
  28 #include "librpc/gen_ndr/ndr_nbt.h"
  29 #include "system/time.h"
  30 #include "libcli/composite/composite.h"
  31 #include "smbd/service_task.h"
  32 #include "system/network.h"
  33 #include "lib/socket/socket.h"
  34 #include "lib/socket/netif.h"
  35 #include "lib/ldb/include/ldb.h"
  36 #include "param/param.h"
  37 #include "libcli/resolve/resolve.h"
  38 
  39 /*
  40   work out the ttl we will use given a client requested ttl
  41 */
  42 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
     /* [<][>][^][v][top][bottom][index][help] */
  43 {
  44         ttl = MIN(ttl, winssrv->config.max_renew_interval);
  45         ttl = MAX(ttl, winssrv->config.min_renew_interval);
  46         return ttl;
  47 }
  48 
  49 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, bool mhomed)
     /* [<][>][^][v][top][bottom][index][help] */
  50 {
  51         /* this copes with the nasty hack that is the type 0x1c name */
  52         if (name->type == NBT_NAME_LOGON) {
  53                 return WREPL_TYPE_SGROUP;
  54         }
  55         if (nb_flags & NBT_NM_GROUP) {
  56                 return WREPL_TYPE_GROUP;
  57         }
  58         if (mhomed) {
  59                 return WREPL_TYPE_MHOMED;
  60         }
  61         return WREPL_TYPE_UNIQUE;
  62 }
  63 
  64 /*
  65   register a new name with WINS
  66 */
  67 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock, 
     /* [<][>][^][v][top][bottom][index][help] */
  68                                  struct nbt_name_packet *packet, 
  69                                  const struct socket_address *src,
  70                                  enum wrepl_name_type type)
  71 {
  72         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
  73                                                        struct nbtd_interface);
  74         struct wins_server *winssrv = iface->nbtsrv->winssrv;
  75         struct nbt_name *name = &packet->questions[0].name;
  76         uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
  77         uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
  78         const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
  79         struct winsdb_record rec;
  80         enum wrepl_name_node node;
  81 
  82 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
  83         ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
  84 
  85         node    = WREPL_NODE_NBT_FLAGS(nb_flags);
  86 
  87         rec.name                = name;
  88         rec.type                = type;
  89         rec.state               = WREPL_STATE_ACTIVE;
  90         rec.node                = node;
  91         rec.is_static           = false;
  92         rec.expire_time         = time(NULL) + ttl;
  93         rec.version             = 0; /* will be allocated later */
  94         rec.wins_owner          = NULL; /* will be set later */
  95         rec.registered_by       = src->addr;
  96         rec.addresses           = winsdb_addr_list_make(packet);
  97         if (rec.addresses == NULL) return NBT_RCODE_SVR;
  98 
  99         rec.addresses     = winsdb_addr_list_add(winssrv->wins_db,
 100                                                  &rec, rec.addresses,
 101                                                  address,
 102                                                  winssrv->wins_db->local_owner,
 103                                                  rec.expire_time,
 104                                                  true);
 105         if (rec.addresses == NULL) return NBT_RCODE_SVR;
 106 
 107         DEBUG(4,("WINS: accepted registration of %s with address %s\n",
 108                  nbt_name_string(packet, name), rec.addresses[0]->address));
 109         
 110         return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
 111 }
 112 
 113 
 114 /*
 115   update the ttl on an existing record
 116 */
 117 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock, 
     /* [<][>][^][v][top][bottom][index][help] */
 118                                struct nbt_name_packet *packet, 
 119                                struct winsdb_record *rec,
 120                                struct winsdb_addr *winsdb_addr,
 121                                const struct socket_address *src)
 122 {
 123         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 124                                                        struct nbtd_interface);
 125         struct wins_server *winssrv = iface->nbtsrv->winssrv;
 126         uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
 127         const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
 128         uint32_t modify_flags = 0;
 129 
 130         rec->expire_time   = time(NULL) + ttl;
 131         rec->registered_by = src->addr;
 132 
 133         if (winsdb_addr) {
 134                 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
 135                                                       rec, rec->addresses,
 136                                                       winsdb_addr->address,
 137                                                       winssrv->wins_db->local_owner,
 138                                                       rec->expire_time,
 139                                                       true);
 140                 if (rec->addresses == NULL) return NBT_RCODE_SVR;
 141         }
 142 
 143         if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
 144                 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
 145         }
 146 
 147         DEBUG(5,("WINS: refreshed registration of %s at %s\n",
 148                  nbt_name_string(packet, rec->name), address));
 149         
 150         return winsdb_modify(winssrv->wins_db, rec, modify_flags);
 151 }
 152 
 153 /*
 154   do a sgroup merge
 155 */
 156 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock, 
     /* [<][>][^][v][top][bottom][index][help] */
 157                                  struct nbt_name_packet *packet, 
 158                                  struct winsdb_record *rec,
 159                                  const char *address,
 160                                  const struct socket_address *src)
 161 {
 162         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 163                                                        struct nbtd_interface);
 164         struct wins_server *winssrv = iface->nbtsrv->winssrv;
 165         uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
 166 
 167         rec->expire_time   = time(NULL) + ttl;
 168         rec->registered_by = src->addr;
 169 
 170         rec->addresses     = winsdb_addr_list_add(winssrv->wins_db,
 171                                                   rec, rec->addresses,
 172                                                   address,
 173                                                   winssrv->wins_db->local_owner,
 174                                                   rec->expire_time,
 175                                                   true);
 176         if (rec->addresses == NULL) return NBT_RCODE_SVR;
 177 
 178         DEBUG(5,("WINS: sgroup merge of %s at %s\n",
 179                  nbt_name_string(packet, rec->name), address));
 180         
 181         return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
 182 }
 183 
 184 struct nbtd_wins_wack_state {
 185         struct nbtd_wins_wack_state *prev, *next;
 186         struct wins_server *winssrv;
 187         struct nbt_name_socket *nbtsock;
 188         struct nbtd_interface *iface;
 189         struct nbt_name_packet *request_packet;
 190         struct winsdb_record *rec;
 191         struct socket_address *src;
 192         const char *reg_address;
 193         enum wrepl_name_type new_type;
 194         struct wins_challenge_io io;
 195         NTSTATUS status;
 196 };
 197 
 198 static int nbtd_wins_wack_state_destructor(struct nbtd_wins_wack_state *s)
     /* [<][>][^][v][top][bottom][index][help] */
 199 {
 200         DLIST_REMOVE(s->iface->wack_queue, s);
 201         return 0;
 202 }
 203 
 204 static bool wins_check_wack_queue(struct nbtd_interface *iface,
     /* [<][>][^][v][top][bottom][index][help] */
 205                                   struct nbt_name_packet *packet,
 206                                   struct socket_address *src)
 207 {
 208         struct nbtd_wins_wack_state *s;
 209 
 210         for (s= iface->wack_queue; s; s = s->next) {
 211                 if (packet->name_trn_id != s->request_packet->name_trn_id) {
 212                         continue;
 213                 }
 214                 if (packet->operation != s->request_packet->operation) {
 215                         continue;
 216                 }
 217                 if (src->port != s->src->port) {
 218                         continue;
 219                 }
 220                 if (strcmp(src->addr, s->src->addr) != 0) {
 221                         continue;
 222                 }
 223 
 224                 return true;
 225         }
 226 
 227         return false;
 228 }
 229 
 230 /*
 231   deny a registration request
 232 */
 233 static void wins_wack_deny(struct nbtd_wins_wack_state *s)
     /* [<][>][^][v][top][bottom][index][help] */
 234 {
 235         nbtd_name_registration_reply(s->nbtsock, s->request_packet, 
 236                                      s->src, NBT_RCODE_ACT);
 237         DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
 238                  nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
 239         talloc_free(s);
 240 }
 241 
 242 /*
 243   allow a registration request
 244 */
 245 static void wins_wack_allow(struct nbtd_wins_wack_state *s)
     /* [<][>][^][v][top][bottom][index][help] */
 246 {
 247         NTSTATUS status;
 248         uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
 249         struct winsdb_record *rec = s->rec, *rec2;
 250         uint32_t i,j;
 251 
 252         status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
 253         if (!NT_STATUS_IS_OK(status) ||
 254             rec2->version != rec->version ||
 255             strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
 256                 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
 257                          nbt_name_string(s, rec->name)));
 258                 wins_wack_deny(s);
 259                 return;
 260         }
 261 
 262         /*
 263          * if the old name owner doesn't hold the name anymore
 264          * handle the request as new registration for the new name owner
 265          */
 266         if (!NT_STATUS_IS_OK(s->status)) {
 267                 uint8_t rcode;
 268 
 269                 winsdb_delete(s->winssrv->wins_db, rec);
 270                 rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
 271                 if (rcode != NBT_RCODE_OK) {
 272                         DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
 273                                  nbt_name_string(s, rec->name)));
 274                         wins_wack_deny(s);
 275                         return;
 276                 }
 277                 goto done;
 278         }
 279 
 280         rec->expire_time = time(NULL) + ttl;
 281         rec->registered_by = s->src->addr;
 282 
 283         /*
 284          * now remove all addresses that're the client doesn't hold anymore
 285          * and update the time stamp and owner for the ownes that are still there
 286          */
 287         for (i=0; rec->addresses[i]; i++) {
 288                 bool found = false;
 289                 for (j=0; j < s->io.out.num_addresses; j++) {
 290                         if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
 291 
 292                         found = true;
 293                         break;
 294                 }
 295                 if (found) {
 296                         rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
 297                                                               rec, rec->addresses,
 298                                                               s->reg_address,
 299                                                               s->winssrv->wins_db->local_owner,
 300                                                               rec->expire_time,
 301                                                               true);
 302                         if (rec->addresses == NULL) goto failed;
 303                         continue;
 304                 }
 305 
 306                 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
 307         }
 308 
 309         rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
 310                                               rec, rec->addresses,
 311                                               s->reg_address,
 312                                               s->winssrv->wins_db->local_owner,
 313                                               rec->expire_time,
 314                                               true);
 315         if (rec->addresses == NULL) goto failed;
 316 
 317         /* if we have more than one address, this becomes implicit a MHOMED record */
 318         if (winsdb_addr_list_length(rec->addresses) > 1) {
 319                 rec->type = WREPL_TYPE_MHOMED;
 320         }
 321 
 322         winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
 323 
 324         DEBUG(4,("WINS: accepted registration of %s with address %s\n",
 325                  nbt_name_string(s, rec->name), s->reg_address));
 326 
 327 done:
 328         nbtd_name_registration_reply(s->nbtsock, s->request_packet, 
 329                                      s->src, NBT_RCODE_OK);
 330 failed:
 331         talloc_free(s);
 332 }
 333 
 334 /*
 335   called when a name query to a current owner completes
 336 */
 337 static void wack_wins_challenge_handler(struct composite_context *c_req)
     /* [<][>][^][v][top][bottom][index][help] */
 338 {
 339         struct nbtd_wins_wack_state *s = talloc_get_type(c_req->async.private_data,
 340                                          struct nbtd_wins_wack_state);
 341         bool found;
 342         uint32_t i;
 343 
 344         s->status = wins_challenge_recv(c_req, s, &s->io);
 345 
 346         /*
 347          * if the owner denies it holds the name, then allow
 348          * the registration
 349          */
 350         if (!NT_STATUS_IS_OK(s->status)) {
 351                 wins_wack_allow(s);
 352                 return;
 353         }
 354 
 355         if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
 356                 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
 357                          nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
 358                 wins_wack_deny(s);
 359                 return;
 360         }
 361 
 362         /*
 363          * if the owner still wants the name and doesn't reply
 364          * with the address trying to be registered, then deny
 365          * the registration
 366          */
 367         found = false;
 368         for (i=0; i < s->io.out.num_addresses; i++) {
 369                 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
 370 
 371                 found = true;
 372                 break;
 373         }
 374         if (!found) {
 375                 wins_wack_deny(s);
 376                 return;
 377         }
 378 
 379         wins_wack_allow(s);
 380         return;
 381 }
 382 
 383 
 384 /*
 385   a client has asked to register a unique name that someone else owns. We
 386   need to ask each of the current owners if they still want it. If they do
 387   then reject the registration, otherwise allow it
 388 */
 389 static void wins_register_wack(struct nbt_name_socket *nbtsock, 
     /* [<][>][^][v][top][bottom][index][help] */
 390                                struct nbt_name_packet *packet, 
 391                                struct winsdb_record *rec,
 392                                struct socket_address *src,
 393                                enum wrepl_name_type new_type)
 394 {
 395         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 396                                                        struct nbtd_interface);
 397         struct wins_server *winssrv = iface->nbtsrv->winssrv;
 398         struct nbtd_wins_wack_state *s;
 399         struct composite_context *c_req;
 400         uint32_t ttl;
 401 
 402         s = talloc_zero(nbtsock, struct nbtd_wins_wack_state);
 403         if (s == NULL) goto failed;
 404 
 405         /* package up the state variables for this wack request */
 406         s->winssrv              = winssrv;
 407         s->nbtsock              = nbtsock;
 408         s->iface                = iface;
 409         s->request_packet       = talloc_steal(s, packet);
 410         s->rec                  = talloc_steal(s, rec);
 411         s->reg_address          = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
 412         s->new_type             = new_type;
 413         s->src                  = src;
 414         if (talloc_reference(s, src) == NULL) goto failed;
 415 
 416         s->io.in.nbtd_server    = iface->nbtsrv;
 417         s->io.in.nbt_port       = lp_nbt_port(iface->nbtsrv->task->lp_ctx);
 418         s->io.in.event_ctx      = iface->nbtsrv->task->event_ctx;
 419         s->io.in.name           = rec->name;
 420         s->io.in.num_addresses  = winsdb_addr_list_length(rec->addresses);
 421         s->io.in.addresses      = winsdb_addr_string_list(s, rec->addresses);
 422         if (s->io.in.addresses == NULL) goto failed;
 423 
 424         DLIST_ADD_END(iface->wack_queue, s, struct nbtd_wins_wack_state *);
 425 
 426         talloc_set_destructor(s, nbtd_wins_wack_state_destructor);
 427 
 428         /*
 429          * send a WACK to the client, specifying the maximum time it could
 430          * take to check with the owner, plus some slack
 431          */
 432         ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
 433         nbtd_wack_reply(nbtsock, packet, src, ttl);
 434 
 435         /*
 436          * send the challenge to the old addresses
 437          */
 438         c_req = wins_challenge_send(s, &s->io);
 439         if (c_req == NULL) goto failed;
 440 
 441         c_req->async.fn                 = wack_wins_challenge_handler;
 442         c_req->async.private_data       = s;
 443         return;
 444 
 445 failed:
 446         talloc_free(s);
 447         nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
 448 }
 449 
 450 /*
 451   register a name
 452 */
 453 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock, 
     /* [<][>][^][v][top][bottom][index][help] */
 454                                      struct nbt_name_packet *packet, 
 455                                      struct socket_address *src)
 456 {
 457         NTSTATUS status;
 458         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 459                                                        struct nbtd_interface);
 460         struct wins_server *winssrv = iface->nbtsrv->winssrv;
 461         struct nbt_name *name = &packet->questions[0].name;
 462         struct winsdb_record *rec;
 463         uint8_t rcode = NBT_RCODE_OK;
 464         uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
 465         const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
 466         bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
 467         enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
 468         struct winsdb_addr *winsdb_addr = NULL;
 469         bool duplicate_packet;
 470 
 471         /*
 472          * as a special case, the local master browser name is always accepted
 473          * for registration, but never stored, but w2k3 stores it if it's registered
 474          * as a group name, (but a query for the 0x1D name still returns not found!)
 475          */
 476         if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
 477                 rcode = NBT_RCODE_OK;
 478                 goto done;
 479         }
 480 
 481         /* w2k3 refuses 0x1B names with marked as group */
 482         if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
 483                 rcode = NBT_RCODE_RFS;
 484                 goto done;
 485         }
 486 
 487         /* w2k3 refuses 0x1C names with out marked as group */
 488         if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
 489                 rcode = NBT_RCODE_RFS;
 490                 goto done;
 491         }
 492 
 493         /* w2k3 refuses 0x1E names with out marked as group */
 494         if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
 495                 rcode = NBT_RCODE_RFS;
 496                 goto done;
 497         }
 498 
 499         duplicate_packet = wins_check_wack_queue(iface, packet, src);
 500         if (duplicate_packet) {
 501                 /* just ignore the packet */
 502                 DEBUG(5,("Ignoring duplicate packet while WACK is pending from %s:%d\n",
 503                          src->addr, src->port));
 504                 return;
 505         }
 506 
 507         status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
 508         if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
 509                 rcode = wins_register_new(nbtsock, packet, src, new_type);
 510                 goto done;
 511         } else if (!NT_STATUS_IS_OK(status)) {
 512                 rcode = NBT_RCODE_SVR;
 513                 goto done;
 514         } else if (rec->is_static) {
 515                 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
 516                         rcode = NBT_RCODE_OK;
 517                         goto done;
 518                 }
 519                 rcode = NBT_RCODE_ACT;
 520                 goto done;
 521         }
 522 
 523         if (rec->type == WREPL_TYPE_GROUP) {
 524                 if (new_type != WREPL_TYPE_GROUP) {
 525                         DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
 526                                  " while a normal group is already there\n",
 527                                  nbt_name_string(packet, name), new_type));
 528                         rcode = NBT_RCODE_ACT;
 529                         goto done;
 530                 }
 531 
 532                 if (rec->state == WREPL_STATE_ACTIVE) {
 533                         /* TODO: is this correct? */
 534                         rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
 535                         goto done;
 536                 }
 537 
 538                 /* TODO: is this correct? */
 539                 winsdb_delete(winssrv->wins_db, rec);
 540                 rcode = wins_register_new(nbtsock, packet, src, new_type);
 541                 goto done;
 542         }
 543 
 544         if (rec->state != WREPL_STATE_ACTIVE) {
 545                 winsdb_delete(winssrv->wins_db, rec);
 546                 rcode = wins_register_new(nbtsock, packet, src, new_type);
 547                 goto done;
 548         }
 549 
 550         switch (rec->type) {
 551         case WREPL_TYPE_UNIQUE:
 552         case WREPL_TYPE_MHOMED:
 553                 /* 
 554                  * if its an active unique name, and the registration is for a group, then
 555                  * see if the unique name owner still wants the name
 556                  * TODO: is this correct?
 557                  */
 558                 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
 559                         wins_register_wack(nbtsock, packet, rec, src, new_type);
 560                         return;
 561                 }
 562 
 563                 /* 
 564                  * if the registration is for an address that is currently active, then 
 565                  * just update the expiry time of the record and the address
 566                  */
 567                 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
 568                 if (winsdb_addr) {
 569                         rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
 570                         goto done;
 571                 }
 572 
 573                 /*
 574                  * we have to do a WACK to see if the current owner is willing
 575                  * to give up its claim
 576                  */
 577                 wins_register_wack(nbtsock, packet, rec, src, new_type);
 578                 return;
 579 
 580         case WREPL_TYPE_GROUP:
 581                 /* this should not be reached as normal groups are handled above */
 582                 DEBUG(0,("BUG at %s\n",__location__));
 583                 rcode = NBT_RCODE_ACT;
 584                 goto done;
 585 
 586         case WREPL_TYPE_SGROUP:
 587                 /* if the new record isn't also a special group, refuse the registration */ 
 588                 if (new_type != WREPL_TYPE_SGROUP) {
 589                         DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
 590                                  " while a special group is already there\n",
 591                                  nbt_name_string(packet, name), new_type));
 592                         rcode = NBT_RCODE_ACT;
 593                         goto done;
 594                 }
 595 
 596                 /* 
 597                  * if the registration is for an address that is currently active, then 
 598                  * just update the expiry time of the record and the address
 599                  */
 600                 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
 601                 if (winsdb_addr) {
 602                         rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
 603                         goto done;
 604                 }
 605 
 606                 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
 607                 goto done;
 608         }
 609 
 610 done:
 611         nbtd_name_registration_reply(nbtsock, packet, src, rcode);
 612 }
 613 
 614 static uint32_t ipv4_match_bits(struct in_addr ip1, struct in_addr ip2)
     /* [<][>][^][v][top][bottom][index][help] */
 615 {
 616         uint32_t i, j, match=0;
 617         uint8_t *p1, *p2;
 618 
 619         p1 = (uint8_t *)&ip1.s_addr;
 620         p2 = (uint8_t *)&ip2.s_addr;
 621 
 622         for (i=0; i<4; i++) {
 623                 if (p1[i] != p2[i]) break;
 624                 match += 8;
 625         }
 626 
 627         if (i==4) return match;
 628 
 629         for (j=0; j<8; j++) {
 630                 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
 631                         break;
 632                 match++;
 633         }
 634 
 635         return match;
 636 }
 637 
 638 static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
     /* [<][>][^][v][top][bottom][index][help] */
 639                                           void *p2,/* (const char **) */
 640                                           struct socket_address *src)
 641 {
 642         const char *a1 = (const char *)*(const char **)p1;
 643         const char *a2 = (const char *)*(const char **)p2;
 644         uint32_t match_bits1;
 645         uint32_t match_bits2;
 646 
 647         match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
 648         match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
 649 
 650         return match_bits2 - match_bits1;
 651 }
 652 
 653 static void nbtd_wins_randomize1Clist(struct loadparm_context *lp_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 654                                       const char **addresses, struct socket_address *src)
 655 {
 656         const char *mask;
 657         const char *tmp;
 658         uint32_t num_addrs;
 659         uint32_t idx, sidx;
 660         int r;
 661 
 662         for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
 663 
 664         if (num_addrs <= 1) return; /* nothing to do */
 665 
 666         /* first sort the addresses depending on the matching to the client */
 667         ldb_qsort(addresses, num_addrs , sizeof(addresses[0]),
 668                   src, (ldb_qsort_cmp_fn_t)nbtd_wins_randomize1Clist_sort);
 669 
 670         mask = lp_parm_string(lp_ctx, NULL, "nbtd", "wins_randomize1Clist_mask");
 671         if (!mask) {
 672                 mask = "255.255.255.0";
 673         }
 674 
 675         /* 
 676          * choose a random address to be the first in the response to the client,
 677          * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
 678          */
 679         r = random();
 680         idx = sidx = r % num_addrs;
 681 
 682         while (1) {
 683                 bool same;
 684 
 685                 /* if the current one is in the same subnet, use it */
 686                 same = iface_same_net(addresses[idx], src->addr, mask);
 687                 if (same) {
 688                         sidx = idx;
 689                         break;
 690                 }
 691 
 692                 /* we need to check for idx == 0, after checking for the same net */
 693                 if (idx == 0) break;
 694                 /* 
 695                  * if we haven't found an address in the same subnet, search in ones
 696                  * which match the client more
 697                  *
 698                  * some notes:
 699                  *
 700                  * it's not "idx = idx % r" but "idx = r % idx"
 701                  * because in "a % b" b is the allowed range
 702                  * and b-1 is the maximum possible result, so it must be decreasing
 703                  * and the above idx == 0 check breaks the while(1) loop.
 704                  */
 705                 idx = r % idx;
 706         }
 707 
 708         /* note sidx == 0 is also valid here ... */
 709         tmp             = addresses[0];
 710         addresses[0]    = addresses[sidx];
 711         addresses[sidx] = tmp;
 712 }
 713 
 714 /*
 715   query a name
 716 */
 717 static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 718                                   struct nbt_name_socket *nbtsock, 
 719                                   struct nbt_name_packet *packet, 
 720                                   struct socket_address *src)
 721 {
 722         NTSTATUS status;
 723         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 724                                                        struct nbtd_interface);
 725         struct wins_server *winssrv = iface->nbtsrv->winssrv;
 726         struct nbt_name *name = &packet->questions[0].name;
 727         struct winsdb_record *rec;
 728         struct winsdb_record *rec_1b = NULL;
 729         const char **addresses;
 730         const char **addresses_1b = NULL;
 731         uint16_t nb_flags = 0;
 732 
 733         if (name->type == NBT_NAME_MASTER) {
 734                 goto notfound;
 735         }
 736 
 737         /*
 738          * w2k3 returns the first address of the 0x1B record as first address
 739          * to a 0x1C query
 740          *
 741          * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
 742          *
 743          * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
 744          * Typ: Daten REG_DWORD
 745          * Value: 0 = deactivated, 1 = activated
 746          */
 747         if (name->type == NBT_NAME_LOGON && 
 748             lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
 749                 struct nbt_name name_1b;
 750 
 751                 name_1b = *name;
 752                 name_1b.type = NBT_NAME_PDC;
 753 
 754                 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
 755                 if (NT_STATUS_IS_OK(status)) {
 756                         addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
 757                 }
 758         }
 759 
 760         status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
 761         if (!NT_STATUS_IS_OK(status)) {
 762                 if (!lp_wins_dns_proxy(lp_ctx)) {
 763                         goto notfound;
 764                 }
 765 
 766                 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
 767                         goto notfound;
 768                 }
 769 
 770                 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
 771                 return;
 772         }
 773 
 774         /*
 775          * for group's we always reply with
 776          * 255.255.255.255 as address, even if
 777          * the record is released or tombstoned
 778          */
 779         if (rec->type == WREPL_TYPE_GROUP) {
 780                 addresses = str_list_add(NULL, "255.255.255.255");
 781                 talloc_steal(packet, addresses);
 782                 if (!addresses) {
 783                         goto notfound;
 784                 }
 785                 nb_flags |= NBT_NM_GROUP;
 786                 goto found;
 787         }
 788 
 789         if (rec->state != WREPL_STATE_ACTIVE) {
 790                 goto notfound;
 791         }
 792 
 793         addresses = winsdb_addr_string_list(packet, rec->addresses);
 794         if (!addresses) {
 795                 goto notfound;
 796         }
 797 
 798         /* 
 799          * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
 800          * first 0x1B address as first address
 801          */
 802         if (addresses_1b && addresses_1b[0]) {
 803                 const char **addresses_1c = addresses;
 804                 uint32_t i;
 805                 uint32_t num_addrs;
 806 
 807                 addresses = str_list_add(NULL, addresses_1b[0]);
 808                 if (!addresses) {
 809                         goto notfound;
 810                 }
 811                 talloc_steal(packet, addresses);
 812                 num_addrs = 1;
 813 
 814                 for (i=0; addresses_1c[i]; i++) {
 815                         if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
 816 
 817                         /*
 818                          * stop when we already have 25 addresses
 819                          */
 820                         if (num_addrs >= 25) break;
 821 
 822                         num_addrs++;                    
 823                         addresses = str_list_add(addresses, addresses_1c[i]);
 824                         if (!addresses) {
 825                                 goto notfound;
 826                         }
 827                 }
 828         }
 829 
 830         if (rec->type == WREPL_TYPE_SGROUP) {
 831                 nb_flags |= NBT_NM_GROUP;
 832         } else {
 833                 nb_flags |= (rec->node <<13);
 834         }
 835 
 836         /*
 837          * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
 838          *
 839          * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
 840          * Typ: Daten REG_DWORD
 841          * Value: 0 = deactivated, 1 = activated
 842          */
 843         if (name->type == NBT_NAME_LOGON && 
 844             lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) {
 845                 nbtd_wins_randomize1Clist(lp_ctx, addresses, src);
 846         }
 847 
 848 found:
 849         nbtd_name_query_reply(nbtsock, packet, src, name, 
 850                               0, nb_flags, addresses);
 851         return;
 852 
 853 notfound:
 854         nbtd_negative_name_query_reply(nbtsock, packet, src);
 855 }
 856 
 857 /*
 858   release a name
 859 */
 860 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, 
     /* [<][>][^][v][top][bottom][index][help] */
 861                                     struct nbt_name_packet *packet, 
 862                                     struct socket_address *src)
 863 {
 864         NTSTATUS status;
 865         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 866                                                        struct nbtd_interface);
 867         struct wins_server *winssrv = iface->nbtsrv->winssrv;
 868         struct nbt_name *name = &packet->questions[0].name;
 869         struct winsdb_record *rec;
 870         uint32_t modify_flags = 0;
 871         uint8_t ret;
 872 
 873         if (name->type == NBT_NAME_MASTER) {
 874                 goto done;
 875         }
 876 
 877         status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
 878         if (!NT_STATUS_IS_OK(status)) {
 879                 goto done;
 880         }
 881 
 882         if (rec->is_static) {
 883                 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
 884                         goto done;
 885                 }
 886                 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
 887                 return;
 888         }
 889 
 890         if (rec->state != WREPL_STATE_ACTIVE) {
 891                 goto done;
 892         }
 893 
 894         /* 
 895          * TODO: do we need to check if
 896          *       src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
 897          *       here?
 898          */
 899 
 900         /* 
 901          * we only allow releases from an owner - other releases are
 902          * silently ignored
 903          */
 904         if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
 905                 int i;
 906                 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
 907                 DEBUGADD(4, ("Registered Addresses: \n"));
 908                 for (i=0; rec->addresses && rec->addresses[i]; i++) {
 909                         DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
 910                 }
 911                 goto done;
 912         }
 913 
 914         DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
 915 
 916         switch (rec->type) {
 917         case WREPL_TYPE_UNIQUE:
 918                 rec->state = WREPL_STATE_RELEASED;
 919                 break;
 920 
 921         case WREPL_TYPE_GROUP:
 922                 rec->state = WREPL_STATE_RELEASED;
 923                 break;
 924 
 925         case WREPL_TYPE_SGROUP:
 926                 winsdb_addr_list_remove(rec->addresses, src->addr);
 927                 /* TODO: do we need to take the ownership here? */
 928                 if (winsdb_addr_list_length(rec->addresses) == 0) {
 929                         rec->state = WREPL_STATE_RELEASED;
 930                 }
 931                 break;
 932 
 933         case WREPL_TYPE_MHOMED:
 934                 winsdb_addr_list_remove(rec->addresses, src->addr);
 935                 /* TODO: do we need to take the ownership here? */
 936                 if (winsdb_addr_list_length(rec->addresses) == 0) {
 937                         rec->state = WREPL_STATE_RELEASED;
 938                 }
 939                 break;
 940         }
 941 
 942         if (rec->state == WREPL_STATE_ACTIVE) {
 943                 /*
 944                  * If the record is still active, we need to update the
 945                  * expire_time.
 946                  *
 947                  * if we're not the owner, we need to take the ownership.
 948                  */
 949                 rec->expire_time= time(NULL) + winssrv->config.max_renew_interval;
 950                 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) != 0) {
 951                         modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
 952                 }
 953                 if (lp_parm_bool(iface->nbtsrv->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false)) {
 954                         /*
 955                          * We have an option to propagate every name release,
 956                          * this is off by default to match windows servers
 957                          */
 958                         modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
 959                 }
 960         } else if (rec->state == WREPL_STATE_RELEASED) {
 961                 /*
 962                  * if we're not the owner, we need to take the owner ship
 963                  * and make the record tombstone, but expire after
 964                  * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
 965                  * like for normal tombstone records.
 966                  * This is to replicate the record directly to the original owner,
 967                  * where the record is still active
 968                  */ 
 969                 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
 970                         rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
 971                 } else {
 972                         rec->state      = WREPL_STATE_TOMBSTONE;
 973                         rec->expire_time= time(NULL) + 
 974                                           winssrv->config.tombstone_interval +
 975                                           winssrv->config.tombstone_timeout;
 976                         modify_flags    = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
 977                 }
 978         }
 979 
 980         ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
 981         if (ret != NBT_RCODE_OK) {
 982                 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
 983                         nbt_name_string(rec, rec->name), src->addr, ret));
 984         }
 985 done:
 986         /* we match w2k3 by always giving a positive reply to name releases. */
 987         nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
 988 }
 989 
 990 
 991 /*
 992   answer a name query
 993 */
 994 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock, 
     /* [<][>][^][v][top][bottom][index][help] */
 995                              struct nbt_name_packet *packet, 
 996                              struct socket_address *src)
 997 {
 998         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 999                                                        struct nbtd_interface);
1000         struct wins_server *winssrv = iface->nbtsrv->winssrv;
1001         if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
1002                 return;
1003         }
1004 
1005         switch (packet->operation & NBT_OPCODE) {
1006         case NBT_OPCODE_QUERY:
1007                 nbtd_winsserver_query(iface->nbtsrv->task->lp_ctx, nbtsock, packet, src);
1008                 break;
1009 
1010         case NBT_OPCODE_REGISTER:
1011         case NBT_OPCODE_REFRESH:
1012         case NBT_OPCODE_REFRESH2:
1013         case NBT_OPCODE_MULTI_HOME_REG:
1014                 nbtd_winsserver_register(nbtsock, packet, src);
1015                 break;
1016 
1017         case NBT_OPCODE_RELEASE:
1018                 nbtd_winsserver_release(nbtsock, packet, src);
1019                 break;
1020         }
1021 
1022 }
1023 
1024 /*
1025   startup the WINS server, if configured
1026 */
1027 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
     /* [<][>][^][v][top][bottom][index][help] */
1028 {
1029         uint32_t tmp;
1030         const char *owner;
1031 
1032         if (!lp_wins_support(nbtsrv->task->lp_ctx)) {
1033                 nbtsrv->winssrv = NULL;
1034                 return NT_STATUS_OK;
1035         }
1036 
1037         nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
1038         NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
1039 
1040         nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl(nbtsrv->task->lp_ctx);
1041         nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl(nbtsrv->task->lp_ctx);
1042         tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
1043         nbtsrv->winssrv->config.tombstone_interval = tmp;
1044         tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
1045         nbtsrv->winssrv->config.tombstone_timeout = tmp;
1046 
1047         owner = lp_parm_string(nbtsrv->task->lp_ctx, NULL, "winsdb", "local_owner");
1048 
1049         if (owner == NULL) {
1050                 struct interface *ifaces;
1051                 load_interfaces(nbtsrv->task, lp_interfaces(nbtsrv->task->lp_ctx), &ifaces);
1052                 owner = iface_n_ip(ifaces, 0);
1053         }
1054 
1055         nbtsrv->winssrv->wins_db     = winsdb_connect(nbtsrv->winssrv, nbtsrv->task->event_ctx, 
1056                                                       nbtsrv->task->lp_ctx,
1057                                                       owner, WINSDB_HANDLE_CALLER_NBTD);
1058         if (!nbtsrv->winssrv->wins_db) {
1059                 return NT_STATUS_INTERNAL_DB_ERROR;
1060         }
1061 
1062         irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
1063 
1064         return NT_STATUS_OK;
1065 }

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