root/source3/libads/dns.c

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

DEFINITIONS

This source file includes following definitions.
  1. ads_dns_parse_query
  2. ads_dns_parse_rr
  3. ads_dns_parse_rr_srv
  4. ads_dns_parse_rr_ns
  5. dnssrvcmp
  6. dns_send_req
  7. ads_dns_lookup_srv
  8. ads_dns_lookup_ns
  9. sitename_key
  10. sitename_store
  11. sitename_fetch
  12. stored_sitename_changed
  13. ads_dns_query_internal
  14. ads_dns_query_dcs
  15. ads_dns_query_gcs
  16. ads_dns_query_kdcs
  17. ads_dns_query_pdc
  18. ads_dns_query_dcs_guid

   1 /*
   2    Unix SMB/CIFS implementation.
   3    DNS utility library
   4    Copyright (C) Gerald (Jerry) Carter           2006.
   5    Copyright (C) Jeremy Allison                  2007.
   6 
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11 
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16 
  17    You should have received a copy of the GNU General Public License
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20 
  21 #include "includes.h"
  22 
  23 /* AIX resolv.h uses 'class' in struct ns_rr */
  24 
  25 #if defined(AIX)
  26 #  if defined(class)
  27 #    undef class
  28 #  endif
  29 #endif  /* AIX */
  30 
  31 /* resolver headers */
  32 
  33 #include <sys/types.h>
  34 #include <netinet/in.h>
  35 #include <arpa/nameser.h>
  36 #include <resolv.h>
  37 #include <netdb.h>
  38 
  39 #define MAX_DNS_PACKET_SIZE 0xffff
  40 
  41 #ifdef NS_HFIXEDSZ      /* Bind 8/9 interface */
  42 #if !defined(C_IN)      /* AIX 5.3 already defines C_IN */
  43 #  define C_IN          ns_c_in
  44 #endif
  45 #if !defined(T_A)       /* AIX 5.3 already defines T_A */
  46 #  define T_A           ns_t_a
  47 #endif
  48 
  49 #if defined(HAVE_IPV6)
  50 #if !defined(T_AAAA)
  51 #  define T_AAAA        ns_t_aaaa
  52 #endif
  53 #endif
  54 
  55 #  define T_SRV         ns_t_srv
  56 #if !defined(T_NS)      /* AIX 5.3 already defines T_NS */
  57 #  define T_NS          ns_t_ns
  58 #endif
  59 #else
  60 #  ifdef HFIXEDSZ
  61 #    define NS_HFIXEDSZ HFIXEDSZ
  62 #  else
  63 #    define NS_HFIXEDSZ sizeof(HEADER)
  64 #  endif        /* HFIXEDSZ */
  65 #  ifdef PACKETSZ
  66 #    define NS_PACKETSZ PACKETSZ
  67 #  else /* 512 is usually the default */
  68 #    define NS_PACKETSZ 512
  69 #  endif        /* PACKETSZ */
  70 #  define T_SRV         33
  71 #endif
  72 
  73 /*********************************************************************
  74 *********************************************************************/
  75 
  76 static bool ads_dns_parse_query( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
     /* [<][>][^][v][top][bottom][index][help] */
  77                           uint8 **ptr, struct dns_query *q )
  78 {
  79         uint8 *p = *ptr;
  80         char hostname[MAX_DNS_NAME_LENGTH];
  81         int namelen;
  82 
  83         ZERO_STRUCTP( q );
  84 
  85         if ( !start || !end || !q || !*ptr)
  86                 return False;
  87 
  88         /* See RFC 1035 for details. If this fails, then return. */
  89 
  90         namelen = dn_expand( start, end, p, hostname, sizeof(hostname) );
  91         if ( namelen < 0 ) {
  92                 return False;
  93         }
  94         p += namelen;
  95         q->hostname = talloc_strdup( ctx, hostname );
  96 
  97         /* check that we have space remaining */
  98 
  99         if ( PTR_DIFF(p+4, end) > 0 )
 100                 return False;
 101 
 102         q->type     = RSVAL( p, 0 );
 103         q->in_class = RSVAL( p, 2 );
 104         p += 4;
 105 
 106         *ptr = p;
 107 
 108         return True;
 109 }
 110 
 111 /*********************************************************************
 112 *********************************************************************/
 113 
 114 static bool ads_dns_parse_rr( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
     /* [<][>][^][v][top][bottom][index][help] */
 115                        uint8 **ptr, struct dns_rr *rr )
 116 {
 117         uint8 *p = *ptr;
 118         char hostname[MAX_DNS_NAME_LENGTH];
 119         int namelen;
 120 
 121         if ( !start || !end || !rr || !*ptr)
 122                 return -1;
 123 
 124         ZERO_STRUCTP( rr );
 125         /* pull the name from the answer */
 126 
 127         namelen = dn_expand( start, end, p, hostname, sizeof(hostname) );
 128         if ( namelen < 0 ) {
 129                 return -1;
 130         }
 131         p += namelen;
 132         rr->hostname = talloc_strdup( ctx, hostname );
 133 
 134         /* check that we have space remaining */
 135 
 136         if ( PTR_DIFF(p+10, end) > 0 )
 137                 return False;
 138 
 139         /* pull some values and then skip onto the string */
 140 
 141         rr->type     = RSVAL(p, 0);
 142         rr->in_class = RSVAL(p, 2);
 143         rr->ttl      = RIVAL(p, 4);
 144         rr->rdatalen = RSVAL(p, 8);
 145 
 146         p += 10;
 147 
 148         /* sanity check the available space */
 149 
 150         if ( PTR_DIFF(p+rr->rdatalen, end ) > 0 ) {
 151                 return False;
 152 
 153         }
 154 
 155         /* save a point to the rdata for this section */
 156 
 157         rr->rdata = p;
 158         p += rr->rdatalen;
 159 
 160         *ptr = p;
 161 
 162         return True;
 163 }
 164 
 165 /*********************************************************************
 166 *********************************************************************/
 167 
 168 static bool ads_dns_parse_rr_srv( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
     /* [<][>][^][v][top][bottom][index][help] */
 169                        uint8 **ptr, struct dns_rr_srv *srv )
 170 {
 171         struct dns_rr rr;
 172         uint8 *p;
 173         char dcname[MAX_DNS_NAME_LENGTH];
 174         int namelen;
 175 
 176         if ( !start || !end || !srv || !*ptr)
 177                 return -1;
 178 
 179         /* Parse the RR entry.  Coming out of the this, ptr is at the beginning
 180            of the next record */
 181 
 182         if ( !ads_dns_parse_rr( ctx, start, end, ptr, &rr ) ) {
 183                 DEBUG(1,("ads_dns_parse_rr_srv: Failed to parse RR record\n"));
 184                 return False;
 185         }
 186 
 187         if ( rr.type != T_SRV ) {
 188                 DEBUG(1,("ads_dns_parse_rr_srv: Bad answer type (%d)\n",
 189                                         rr.type));
 190                 return False;
 191         }
 192 
 193         p = rr.rdata;
 194 
 195         srv->priority = RSVAL(p, 0);
 196         srv->weight   = RSVAL(p, 2);
 197         srv->port     = RSVAL(p, 4);
 198 
 199         p += 6;
 200 
 201         namelen = dn_expand( start, end, p, dcname, sizeof(dcname) );
 202         if ( namelen < 0 ) {
 203                 DEBUG(1,("ads_dns_parse_rr_srv: Failed to uncompress name!\n"));
 204                 return False;
 205         }
 206 
 207         srv->hostname = talloc_strdup( ctx, dcname );
 208 
 209         DEBUG(10,("ads_dns_parse_rr_srv: Parsed %s [%u, %u, %u]\n", 
 210                   srv->hostname, 
 211                   srv->priority,
 212                   srv->weight,
 213                   srv->port));
 214 
 215         return True;
 216 }
 217 
 218 /*********************************************************************
 219 *********************************************************************/
 220 
 221 static bool ads_dns_parse_rr_ns( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
     /* [<][>][^][v][top][bottom][index][help] */
 222                        uint8 **ptr, struct dns_rr_ns *nsrec )
 223 {
 224         struct dns_rr rr;
 225         uint8 *p;
 226         char nsname[MAX_DNS_NAME_LENGTH];
 227         int namelen;
 228 
 229         if ( !start || !end || !nsrec || !*ptr)
 230                 return -1;
 231 
 232         /* Parse the RR entry.  Coming out of the this, ptr is at the beginning
 233            of the next record */
 234 
 235         if ( !ads_dns_parse_rr( ctx, start, end, ptr, &rr ) ) {
 236                 DEBUG(1,("ads_dns_parse_rr_ns: Failed to parse RR record\n"));
 237                 return False;
 238         }
 239 
 240         if ( rr.type != T_NS ) {
 241                 DEBUG(1,("ads_dns_parse_rr_ns: Bad answer type (%d)\n",
 242                                         rr.type));
 243                 return False;
 244         }
 245 
 246         p = rr.rdata;
 247 
 248         /* ame server hostname */
 249 
 250         namelen = dn_expand( start, end, p, nsname, sizeof(nsname) );
 251         if ( namelen < 0 ) {
 252                 DEBUG(1,("ads_dns_parse_rr_ns: Failed to uncompress name!\n"));
 253                 return False;
 254         }
 255         nsrec->hostname = talloc_strdup( ctx, nsname );
 256 
 257         return True;
 258 }
 259 
 260 /*********************************************************************
 261  Sort SRV record list based on weight and priority.  See RFC 2782.
 262 *********************************************************************/
 263 
 264 static int dnssrvcmp( struct dns_rr_srv *a, struct dns_rr_srv *b )
     /* [<][>][^][v][top][bottom][index][help] */
 265 {
 266         if ( a->priority == b->priority ) {
 267 
 268                 /* randomize entries with an equal weight and priority */
 269                 if ( a->weight == b->weight )
 270                         return 0;
 271 
 272                 /* higher weights should be sorted lower */
 273                 if ( a->weight > b->weight )
 274                         return -1;
 275                 else
 276                         return 1;
 277         }
 278 
 279         if ( a->priority < b->priority )
 280                 return -1;
 281 
 282         return 1;
 283 }
 284 
 285 /*********************************************************************
 286  Simple wrapper for a DNS query
 287 *********************************************************************/
 288 
 289 #define DNS_FAILED_WAITTIME          30
 290 
 291 static NTSTATUS dns_send_req( TALLOC_CTX *ctx, const char *name, int q_type,
     /* [<][>][^][v][top][bottom][index][help] */
 292                               uint8 **buf, int *resp_length )
 293 {
 294         uint8 *buffer = NULL;
 295         size_t buf_len = 0;
 296         int resp_len = NS_PACKETSZ;
 297         static time_t last_dns_check = 0;
 298         static NTSTATUS last_dns_status = NT_STATUS_OK;
 299         time_t now = time(NULL);
 300 
 301         /* Try to prevent bursts of DNS lookups if the server is down */
 302 
 303         /* Protect against large clock changes */
 304 
 305         if ( last_dns_check > now )
 306                 last_dns_check = 0;
 307 
 308         /* IF we had a DNS timeout or a bad server and we are still
 309            in the 30 second cache window, just return the previous
 310            status and save the network timeout. */
 311 
 312         if ( (NT_STATUS_EQUAL(last_dns_status,NT_STATUS_IO_TIMEOUT) ||
 313               NT_STATUS_EQUAL(last_dns_status,NT_STATUS_CONNECTION_REFUSED)) &&
 314              (last_dns_check+DNS_FAILED_WAITTIME) > now )
 315         {
 316                 DEBUG(10,("last_dns_check: Returning cached status (%s)\n",
 317                           nt_errstr(last_dns_status) ));
 318                 return last_dns_status;
 319         }
 320 
 321         /* Send the Query */
 322         do {
 323                 if ( buffer )
 324                         TALLOC_FREE( buffer );
 325 
 326                 buf_len = resp_len * sizeof(uint8);
 327 
 328                 if (buf_len) {
 329                         if ((buffer = TALLOC_ARRAY(ctx, uint8, buf_len))
 330                                         == NULL ) {
 331                                 DEBUG(0,("ads_dns_lookup_srv: "
 332                                         "talloc() failed!\n"));
 333                                 last_dns_status = NT_STATUS_NO_MEMORY;
 334                                 last_dns_check = time(NULL);
 335                                 return last_dns_status;
 336                         }
 337                 }
 338 
 339                 if ((resp_len = res_query(name, C_IN, q_type, buffer, buf_len))
 340                                 < 0 ) {
 341                         DEBUG(3,("ads_dns_lookup_srv: "
 342                                 "Failed to resolve %s (%s)\n",
 343                                 name, strerror(errno)));
 344                         TALLOC_FREE( buffer );
 345                         last_dns_status = NT_STATUS_UNSUCCESSFUL;
 346 
 347                         if (errno == ETIMEDOUT) {
 348                                 last_dns_status = NT_STATUS_IO_TIMEOUT;
 349                         }
 350                         if (errno == ECONNREFUSED) {
 351                                 last_dns_status = NT_STATUS_CONNECTION_REFUSED;
 352                         }
 353                         last_dns_check = time(NULL);
 354                         return last_dns_status;
 355                 }
 356 
 357                 /* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8)
 358                    truncated replies never give back a resp_len > buflen
 359                    which ends up causing DNS resolve failures on large tcp DNS replies */
 360 
 361                 if (buf_len == resp_len) {
 362                         if (resp_len == MAX_DNS_PACKET_SIZE) {
 363                                 DEBUG(1,("dns_send_req: DNS reply too large when resolving %s\n",
 364                                         name));
 365                                 TALLOC_FREE( buffer );
 366                                 last_dns_status = NT_STATUS_BUFFER_TOO_SMALL;
 367                                 last_dns_check = time(NULL);
 368                                 return last_dns_status;
 369                         }
 370 
 371                         resp_len = MIN(resp_len*2, MAX_DNS_PACKET_SIZE);
 372                 }
 373 
 374 
 375         } while ( buf_len < resp_len && resp_len <= MAX_DNS_PACKET_SIZE );
 376 
 377         *buf = buffer;
 378         *resp_length = resp_len;
 379 
 380         last_dns_check = time(NULL);
 381         last_dns_status = NT_STATUS_OK;
 382         return last_dns_status;
 383 }
 384 
 385 /*********************************************************************
 386  Simple wrapper for a DNS SRV query
 387 *********************************************************************/
 388 
 389 static NTSTATUS ads_dns_lookup_srv( TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 390                                 const char *name,
 391                                 struct dns_rr_srv **dclist,
 392                                 int *numdcs)
 393 {
 394         uint8 *buffer = NULL;
 395         int resp_len = 0;
 396         struct dns_rr_srv *dcs = NULL;
 397         int query_count, answer_count, auth_count, additional_count;
 398         uint8 *p = buffer;
 399         int rrnum;
 400         int idx = 0;
 401         NTSTATUS status;
 402 
 403         if ( !ctx || !name || !dclist ) {
 404                 return NT_STATUS_INVALID_PARAMETER;
 405         }
 406 
 407         /* Send the request.  May have to loop several times in case
 408            of large replies */
 409 
 410         status = dns_send_req( ctx, name, T_SRV, &buffer, &resp_len );
 411         if ( !NT_STATUS_IS_OK(status) ) {
 412                 DEBUG(3,("ads_dns_lookup_srv: Failed to send DNS query (%s)\n",
 413                         nt_errstr(status)));
 414                 return status;
 415         }
 416         p = buffer;
 417 
 418         /* For some insane reason, the ns_initparse() et. al. routines are only
 419            available in libresolv.a, and not the shared lib.  Who knows why....
 420            So we have to parse the DNS reply ourselves */
 421 
 422         /* Pull the answer RR's count from the header.
 423          * Use the NMB ordering macros */
 424 
 425         query_count      = RSVAL( p, 4 );
 426         answer_count     = RSVAL( p, 6 );
 427         auth_count       = RSVAL( p, 8 );
 428         additional_count = RSVAL( p, 10 );
 429 
 430         DEBUG(4,("ads_dns_lookup_srv: "
 431                 "%d records returned in the answer section.\n",
 432                 answer_count));
 433 
 434         if (answer_count) {
 435                 if ((dcs = TALLOC_ZERO_ARRAY(ctx, struct dns_rr_srv,
 436                                                 answer_count)) == NULL ) {
 437                         DEBUG(0,("ads_dns_lookup_srv: "
 438                                 "talloc() failure for %d char*'s\n",
 439                                 answer_count));
 440                         return NT_STATUS_NO_MEMORY;
 441                 }
 442         } else {
 443                 dcs = NULL;
 444         }
 445 
 446         /* now skip the header */
 447 
 448         p += NS_HFIXEDSZ;
 449 
 450         /* parse the query section */
 451 
 452         for ( rrnum=0; rrnum<query_count; rrnum++ ) {
 453                 struct dns_query q;
 454 
 455                 if (!ads_dns_parse_query(ctx, buffer,
 456                                         buffer+resp_len, &p, &q)) {
 457                         DEBUG(1,("ads_dns_lookup_srv: "
 458                                  "Failed to parse query record [%d]!\n", rrnum));
 459                         return NT_STATUS_UNSUCCESSFUL;
 460                 }
 461         }
 462 
 463         /* now we are at the answer section */
 464 
 465         for ( rrnum=0; rrnum<answer_count; rrnum++ ) {
 466                 if (!ads_dns_parse_rr_srv(ctx, buffer, buffer+resp_len,
 467                                         &p, &dcs[rrnum])) {
 468                         DEBUG(1,("ads_dns_lookup_srv: "
 469                                  "Failed to parse answer recordi [%d]!\n", rrnum));
 470                         return NT_STATUS_UNSUCCESSFUL;
 471                 }
 472         }
 473         idx = rrnum;
 474 
 475         /* Parse the authority section */
 476         /* just skip these for now */
 477 
 478         for ( rrnum=0; rrnum<auth_count; rrnum++ ) {
 479                 struct dns_rr rr;
 480 
 481                 if (!ads_dns_parse_rr( ctx, buffer,
 482                                         buffer+resp_len, &p, &rr)) {
 483                         DEBUG(1,("ads_dns_lookup_srv: "
 484                                  "Failed to parse authority record! [%d]\n", rrnum));
 485                         return NT_STATUS_UNSUCCESSFUL;
 486                 }
 487         }
 488 
 489         /* Parse the additional records section */
 490 
 491         for ( rrnum=0; rrnum<additional_count; rrnum++ ) {
 492                 struct dns_rr rr;
 493                 int i;
 494 
 495                 if (!ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
 496                                         &p, &rr)) {
 497                         DEBUG(1,("ads_dns_lookup_srv: Failed "
 498                                  "to parse additional records section! [%d]\n", rrnum));
 499                         return NT_STATUS_UNSUCCESSFUL;
 500                 }
 501 
 502                 /* Only interested in A or AAAA records as a shortcut for having
 503                  * to come back later and lookup the name. For multi-homed
 504                  * hosts, the number of additional records and exceed the
 505                  * number of answer records. */
 506 
 507                 if (rr.type != T_A || rr.rdatalen != 4) {
 508 #if defined(HAVE_IPV6)
 509                         /* FIXME. RFC2874 defines A6 records. This
 510                          * requires recusive and horribly complex lookups.
 511                          * Bastards. Ignore this for now.... JRA.
 512                          */
 513                         if (rr.type != T_AAAA || rr.rdatalen != 16)
 514 #endif
 515                                 continue;
 516                 }
 517 
 518                 for ( i=0; i<idx; i++ ) {
 519                         if ( strcmp( rr.hostname, dcs[i].hostname ) == 0 ) {
 520                                 int num_ips = dcs[i].num_ips;
 521                                 struct sockaddr_storage *tmp_ss_s;
 522 
 523                                 /* allocate new memory */
 524 
 525                                 if (dcs[i].num_ips == 0) {
 526                                         if ((dcs[i].ss_s = TALLOC_ARRAY(dcs,
 527                                                 struct sockaddr_storage, 1 ))
 528                                                         == NULL ) {
 529                                                 return NT_STATUS_NO_MEMORY;
 530                                         }
 531                                 } else {
 532                                         if ((tmp_ss_s = TALLOC_REALLOC_ARRAY(dcs,
 533                                                         dcs[i].ss_s,
 534                                                         struct sockaddr_storage,
 535                                                         dcs[i].num_ips+1))
 536                                                                 == NULL ) {
 537                                                 return NT_STATUS_NO_MEMORY;
 538                                         }
 539 
 540                                         dcs[i].ss_s = tmp_ss_s;
 541                                 }
 542                                 dcs[i].num_ips++;
 543 
 544                                 /* copy the new IP address */
 545                                 if (rr.type == T_A) {
 546                                         struct in_addr ip;
 547                                         memcpy(&ip, rr.rdata, 4);
 548                                         in_addr_to_sockaddr_storage(
 549                                                         &dcs[i].ss_s[num_ips],
 550                                                         ip);
 551                                 }
 552 #if defined(HAVE_IPV6)
 553                                 if (rr.type == T_AAAA) {
 554                                         struct in6_addr ip6;
 555                                         memcpy(&ip6, rr.rdata, rr.rdatalen);
 556                                         in6_addr_to_sockaddr_storage(
 557                                                         &dcs[i].ss_s[num_ips],
 558                                                         ip6);
 559                                 }
 560 #endif
 561                         }
 562                 }
 563         }
 564 
 565         qsort( dcs, idx, sizeof(struct dns_rr_srv), QSORT_CAST dnssrvcmp );
 566 
 567         *dclist = dcs;
 568         *numdcs = idx;
 569 
 570         return NT_STATUS_OK;
 571 }
 572 
 573 /*********************************************************************
 574  Simple wrapper for a DNS NS query
 575 *********************************************************************/
 576 
 577 NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 578                                 const char *dnsdomain,
 579                                 struct dns_rr_ns **nslist,
 580                                 int *numns)
 581 {
 582         uint8 *buffer = NULL;
 583         int resp_len = 0;
 584         struct dns_rr_ns *nsarray = NULL;
 585         int query_count, answer_count, auth_count, additional_count;
 586         uint8 *p;
 587         int rrnum;
 588         int idx = 0;
 589         NTSTATUS status;
 590 
 591         if ( !ctx || !dnsdomain || !nslist ) {
 592                 return NT_STATUS_INVALID_PARAMETER;
 593         }
 594 
 595         /* Send the request.  May have to loop several times in case
 596            of large replies */
 597 
 598         status = dns_send_req( ctx, dnsdomain, T_NS, &buffer, &resp_len );
 599         if ( !NT_STATUS_IS_OK(status) ) {
 600                 DEBUG(3,("ads_dns_lookup_ns: Failed to send DNS query (%s)\n",
 601                         nt_errstr(status)));
 602                 return status;
 603         }
 604         p = buffer;
 605 
 606         /* For some insane reason, the ns_initparse() et. al. routines are only
 607            available in libresolv.a, and not the shared lib.  Who knows why....
 608            So we have to parse the DNS reply ourselves */
 609 
 610         /* Pull the answer RR's count from the header.
 611          * Use the NMB ordering macros */
 612 
 613         query_count      = RSVAL( p, 4 );
 614         answer_count     = RSVAL( p, 6 );
 615         auth_count       = RSVAL( p, 8 );
 616         additional_count = RSVAL( p, 10 );
 617 
 618         DEBUG(4,("ads_dns_lookup_ns: "
 619                 "%d records returned in the answer section.\n",
 620                 answer_count));
 621 
 622         if (answer_count) {
 623                 if ((nsarray = TALLOC_ARRAY(ctx, struct dns_rr_ns,
 624                                                 answer_count)) == NULL ) {
 625                         DEBUG(0,("ads_dns_lookup_ns: "
 626                                 "talloc() failure for %d char*'s\n",
 627                                 answer_count));
 628                         return NT_STATUS_NO_MEMORY;
 629                 }
 630         } else {
 631                 nsarray = NULL;
 632         }
 633 
 634         /* now skip the header */
 635 
 636         p += NS_HFIXEDSZ;
 637 
 638         /* parse the query section */
 639 
 640         for ( rrnum=0; rrnum<query_count; rrnum++ ) {
 641                 struct dns_query q;
 642 
 643                 if (!ads_dns_parse_query(ctx, buffer, buffer+resp_len,
 644                                         &p, &q)) {
 645                         DEBUG(1,("ads_dns_lookup_ns: "
 646                                 " Failed to parse query record!\n"));
 647                         return NT_STATUS_UNSUCCESSFUL;
 648                 }
 649         }
 650 
 651         /* now we are at the answer section */
 652 
 653         for ( rrnum=0; rrnum<answer_count; rrnum++ ) {
 654                 if (!ads_dns_parse_rr_ns(ctx, buffer, buffer+resp_len,
 655                                         &p, &nsarray[rrnum])) {
 656                         DEBUG(1,("ads_dns_lookup_ns: "
 657                                 "Failed to parse answer record!\n"));
 658                         return NT_STATUS_UNSUCCESSFUL;
 659                 }
 660         }
 661         idx = rrnum;
 662 
 663         /* Parse the authority section */
 664         /* just skip these for now */
 665 
 666         for ( rrnum=0; rrnum<auth_count; rrnum++ ) {
 667                 struct dns_rr rr;
 668 
 669                 if ( !ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
 670                                         &p, &rr)) {
 671                         DEBUG(1,("ads_dns_lookup_ns: "
 672                                 "Failed to parse authority record!\n"));
 673                         return NT_STATUS_UNSUCCESSFUL;
 674                 }
 675         }
 676 
 677         /* Parse the additional records section */
 678 
 679         for ( rrnum=0; rrnum<additional_count; rrnum++ ) {
 680                 struct dns_rr rr;
 681                 int i;
 682 
 683                 if (!ads_dns_parse_rr(ctx, buffer, buffer+resp_len,
 684                                         &p, &rr)) {
 685                         DEBUG(1,("ads_dns_lookup_ns: Failed "
 686                                 "to parse additional records section!\n"));
 687                         return NT_STATUS_UNSUCCESSFUL;
 688                 }
 689 
 690                 /* only interested in A records as a shortcut for having to come
 691                    back later and lookup the name */
 692 
 693                 if (rr.type != T_A || rr.rdatalen != 4) {
 694 #if defined(HAVE_IPV6)
 695                         if (rr.type != T_AAAA || rr.rdatalen != 16)
 696 #endif
 697                                 continue;
 698                 }
 699 
 700                 for ( i=0; i<idx; i++ ) {
 701                         if (strcmp(rr.hostname, nsarray[i].hostname) == 0) {
 702                                 if (rr.type == T_A) {
 703                                         struct in_addr ip;
 704                                         memcpy(&ip, rr.rdata, 4);
 705                                         in_addr_to_sockaddr_storage(
 706                                                         &nsarray[i].ss,
 707                                                         ip);
 708                                 }
 709 #if defined(HAVE_IPV6)
 710                                 if (rr.type == T_AAAA) {
 711                                         struct in6_addr ip6;
 712                                         memcpy(&ip6, rr.rdata, rr.rdatalen);
 713                                         in6_addr_to_sockaddr_storage(
 714                                                         &nsarray[i].ss,
 715                                                         ip6);
 716                                 }
 717 #endif
 718                         }
 719                 }
 720         }
 721 
 722         *nslist = nsarray;
 723         *numns = idx;
 724 
 725         return NT_STATUS_OK;
 726 }
 727 
 728 /****************************************************************************
 729  Store and fetch the AD client sitename.
 730 ****************************************************************************/
 731 
 732 #define SITENAME_KEY    "AD_SITENAME/DOMAIN/%s"
 733 
 734 static char *sitename_key(const char *realm)
     /* [<][>][^][v][top][bottom][index][help] */
 735 {
 736         char *keystr;
 737 
 738         if (asprintf_strupper_m(&keystr, SITENAME_KEY, realm) == -1) {
 739                 return NULL;
 740         }
 741 
 742         return keystr;
 743 }
 744 
 745 
 746 /****************************************************************************
 747  Store the AD client sitename.
 748  We store indefinately as every new CLDAP query will re-write this.
 749 ****************************************************************************/
 750 
 751 bool sitename_store(const char *realm, const char *sitename)
     /* [<][>][^][v][top][bottom][index][help] */
 752 {
 753         time_t expire;
 754         bool ret = False;
 755         char *key;
 756 
 757         if (!gencache_init()) {
 758                 return False;
 759         }
 760 
 761         if (!realm || (strlen(realm) == 0)) {
 762                 DEBUG(0,("sitename_store: no realm\n"));
 763                 return False;
 764         }
 765 
 766         key = sitename_key(realm);
 767 
 768         if (!sitename || (sitename && !*sitename)) {
 769                 DEBUG(5,("sitename_store: deleting empty sitename!\n"));
 770                 ret = gencache_del(key);
 771                 SAFE_FREE(key);
 772                 return ret;
 773         }
 774 
 775         expire = get_time_t_max(); /* Store indefinately. */
 776 
 777         DEBUG(10,("sitename_store: realm = [%s], sitename = [%s], expire = [%u]\n",
 778                 realm, sitename, (unsigned int)expire ));
 779 
 780         ret = gencache_set( key, sitename, expire );
 781         SAFE_FREE(key);
 782         return ret;
 783 }
 784 
 785 /****************************************************************************
 786  Fetch the AD client sitename.
 787  Caller must free.
 788 ****************************************************************************/
 789 
 790 char *sitename_fetch(const char *realm)
     /* [<][>][^][v][top][bottom][index][help] */
 791 {
 792         char *sitename = NULL;
 793         time_t timeout;
 794         bool ret = False;
 795         const char *query_realm;
 796         char *key;
 797 
 798         if (!gencache_init()) {
 799                 return NULL;
 800         }
 801 
 802         if (!realm || (strlen(realm) == 0)) {
 803                 query_realm = lp_realm();
 804         } else {
 805                 query_realm = realm;
 806         }
 807 
 808         key = sitename_key(query_realm);
 809 
 810         ret = gencache_get( key, &sitename, &timeout );
 811         SAFE_FREE(key);
 812         if ( !ret ) {
 813                 DEBUG(5,("sitename_fetch: No stored sitename for %s\n",
 814                         query_realm));
 815         } else {
 816                 DEBUG(5,("sitename_fetch: Returning sitename for %s: \"%s\"\n",
 817                         query_realm, sitename ));
 818         }
 819         return sitename;
 820 }
 821 
 822 /****************************************************************************
 823  Did the sitename change ?
 824 ****************************************************************************/
 825 
 826 bool stored_sitename_changed(const char *realm, const char *sitename)
     /* [<][>][^][v][top][bottom][index][help] */
 827 {
 828         bool ret = False;
 829 
 830         char *new_sitename;
 831 
 832         if (!realm || (strlen(realm) == 0)) {
 833                 DEBUG(0,("stored_sitename_changed: no realm\n"));
 834                 return False;
 835         }
 836 
 837         new_sitename = sitename_fetch(realm);
 838 
 839         if (sitename && new_sitename && !strequal(sitename, new_sitename)) {
 840                 ret = True;
 841         } else if ((sitename && !new_sitename) ||
 842                         (!sitename && new_sitename)) {
 843                 ret = True;
 844         }
 845         SAFE_FREE(new_sitename);
 846         return ret;
 847 }
 848 
 849 /********************************************************************
 850  Query with optional sitename.
 851 ********************************************************************/
 852 
 853 static NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 854                                        const char *servicename,
 855                                        const char *dc_pdc_gc_domains,
 856                                        const char *realm,
 857                                        const char *sitename,
 858                                        struct dns_rr_srv **dclist,
 859                                        int *numdcs )
 860 {
 861         char *name;
 862         if (sitename) {
 863                 name = talloc_asprintf(ctx, "%s._tcp.%s._sites.%s._msdcs.%s",
 864                                        servicename, sitename,
 865                                        dc_pdc_gc_domains, realm);
 866         } else {
 867                 name = talloc_asprintf(ctx, "%s._tcp.%s._msdcs.%s",
 868                                 servicename, dc_pdc_gc_domains, realm);
 869         }
 870         if (!name) {
 871                 return NT_STATUS_NO_MEMORY;
 872         }
 873         return ads_dns_lookup_srv( ctx, name, dclist, numdcs );
 874 }
 875 
 876 /********************************************************************
 877  Query for AD DC's.
 878 ********************************************************************/
 879 
 880 NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 881                            const char *realm,
 882                            const char *sitename,
 883                            struct dns_rr_srv **dclist,
 884                            int *numdcs )
 885 {
 886         NTSTATUS status;
 887 
 888         status = ads_dns_query_internal(ctx, "_ldap", "dc", realm, sitename,
 889                                         dclist, numdcs);
 890 
 891         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
 892             NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
 893                 return status;
 894         }
 895 
 896         if (sitename &&
 897             ((!NT_STATUS_IS_OK(status)) ||
 898              (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
 899                 /* Sitename DNS query may have failed. Try without. */
 900                 status = ads_dns_query_internal(ctx, "_ldap", "dc", realm,
 901                                                 NULL, dclist, numdcs);
 902         }
 903         return status;
 904 }
 905 
 906 /********************************************************************
 907  Query for AD GC's.
 908 ********************************************************************/
 909 
 910 NTSTATUS ads_dns_query_gcs(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 911                            const char *realm,
 912                            const char *sitename,
 913                            struct dns_rr_srv **dclist,
 914                            int *numdcs )
 915 {
 916         NTSTATUS status;
 917 
 918         status = ads_dns_query_internal(ctx, "_ldap", "gc", realm, sitename,
 919                                         dclist, numdcs);
 920 
 921         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
 922             NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
 923                 return status;
 924         }
 925 
 926         if (sitename &&
 927             ((!NT_STATUS_IS_OK(status)) ||
 928              (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
 929                 /* Sitename DNS query may have failed. Try without. */
 930                 status = ads_dns_query_internal(ctx, "_ldap", "gc", realm,
 931                                                 NULL, dclist, numdcs);
 932         }
 933         return status;
 934 }
 935 
 936 /********************************************************************
 937  Query for AD KDC's.
 938  Even if our underlying kerberos libraries are UDP only, this
 939  is pretty safe as it's unlikely that a KDC supports TCP and not UDP.
 940 ********************************************************************/
 941 
 942 NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 943                             const char *dns_forest_name,
 944                             const char *sitename,
 945                             struct dns_rr_srv **dclist,
 946                             int *numdcs )
 947 {
 948         NTSTATUS status;
 949 
 950         status = ads_dns_query_internal(ctx, "_kerberos", "dc",
 951                                         dns_forest_name, sitename, dclist,
 952                                         numdcs);
 953 
 954         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
 955             NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED)) {
 956                 return status;
 957         }
 958 
 959         if (sitename &&
 960             ((!NT_STATUS_IS_OK(status)) ||
 961              (NT_STATUS_IS_OK(status) && (numdcs == 0)))) {
 962                 /* Sitename DNS query may have failed. Try without. */
 963                 status = ads_dns_query_internal(ctx, "_kerberos", "dc",
 964                                                 dns_forest_name, NULL,
 965                                                 dclist, numdcs);
 966         }
 967         return status;
 968 }
 969 
 970 /********************************************************************
 971  Query for AD PDC. Sitename is obsolete here.
 972 ********************************************************************/
 973 
 974 NTSTATUS ads_dns_query_pdc(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 975                            const char *dns_domain_name,
 976                            struct dns_rr_srv **dclist,
 977                            int *numdcs )
 978 {
 979         return ads_dns_query_internal(ctx, "_ldap", "pdc", dns_domain_name,
 980                                       NULL, dclist, numdcs);
 981 }
 982 
 983 /********************************************************************
 984  Query for AD DC by guid. Sitename is obsolete here.
 985 ********************************************************************/
 986 
 987 NTSTATUS ads_dns_query_dcs_guid(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 988                                 const char *dns_forest_name,
 989                                 const struct GUID *domain_guid,
 990                                 struct dns_rr_srv **dclist,
 991                                 int *numdcs )
 992 {
 993         /*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
 994 
 995         const char *domains;
 996         const char *guid_string;
 997 
 998         guid_string = GUID_string(ctx, domain_guid);
 999         if (!guid_string) {
1000                 return NT_STATUS_NO_MEMORY;
1001         }
1002 
1003         /* little hack */
1004         domains = talloc_asprintf(ctx, "%s.domains", guid_string);
1005         if (!domains) {
1006                 return NT_STATUS_NO_MEMORY;
1007         }
1008 
1009         return ads_dns_query_internal(ctx, "_ldap", domains, dns_forest_name,
1010                                       NULL, dclist, numdcs);
1011 }

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