1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "mdns_common.h" 28 29 static int _nss_mdns_queryrecord(const char *rrname, int rrclass, int rrtype, 30 DNSServiceQueryRecordReply callback, 31 struct mdns_querydata *data); 32 static void _nss_mdns_get_svcstatetimestamp(struct timeval *); 33 static void _nss_mdns_loadsmfcfg(mdns_backend_ptr_t); 34 static void _nss_mdns_freesmfcfg(mdns_backend_ptr_t); 35 static boolean_t cmpdmn(char *, char **, int); 36 static char *RDataToName(char *data, char *buffer, int datalen, int buflen); 37 static int searchdomain(mdns_backend_ptr_t, char *, int, char **); 38 static boolean_t validdomain(mdns_backend_ptr_t, char *, int); 39 40 /* 41 * This file includes the functions to query for host name 42 * information via Multicast DNS (mDNS). The function 43 * _nss_mdns_queryrecord queries for the host information via 44 * Multicast DNS. _nss_mdns_querybyname and _nss_mdns_querybyaddr 45 * query for host IP address and hostname by querying for A/AAAA 46 * and PTR DNS resource records respectively. DNSServiceQueryRecord 47 * in libdns_sd sends a request to the mDNS daemon (mdnsd) to place 48 * the DNS query via multicast and return the results. 49 * mdnsd is managed by SMF (FMRI: svc:/network/dns/multicast:default). 50 * 51 * gethostent.c and gethostent6.c implement the nsswitch 'hosts' 52 * backend module getXbyY functions: getbyname and getbyaddr. 53 * getby* functions in gethostent.c supports only IPv4 and 54 * getby* functions in gethostent6.c returns both IPv4 and 55 * IPv6 results. Functions in gethostent.c and gethostent6.c 56 * call the _nss_mdns_queryby* functions in mdns_common.c to 57 * query for host information via mDNS. 58 * 59 * Configuration for mdns is stored in SMF and is accessed using 60 * the FMRI: svc:/network/dns/multicast:default. Configuration 61 * includes the list of valid DNS domains checked before querying host 62 * information via mDNS and the search list to use for host lookup via 63 * mDNS. The default valid domain list in the mDNS service supports host 64 * lookups for hostnames in the ".local" domain and hostname queries 65 * for link-local IPv4 and IPv6 addresses. _nss_mdns_loadsmfcfg 66 * loads the nss_mdns configuration from SMF and the function 67 * _nss_mdns_updatecfg checks for any updates in nss_mdns configuration. 68 */ 69 70 static int 71 _nss_mdns_queryrecord(const char *rrname, int rrclass, int rrtype, 72 DNSServiceQueryRecordReply callback, 73 struct mdns_querydata *data) 74 { 75 int sockfd; 76 int flags = kDNSServiceFlagsForceMulticast; /* Multicast only */ 77 int opinterface = kDNSServiceInterfaceIndexAny; 78 DNSServiceErrorType err; 79 DNSServiceRef ref = NULL; 80 int ret; 81 struct fd_set readfds; 82 struct timeval tv; 83 84 data->status = NSS_NOTFOUND; 85 #ifdef DEBUG 86 syslog(LOG_DEBUG, "nss_mdns: query called rrname:%s rrtype:%d", 87 rrname, rrtype); 88 #endif 89 err = DNSServiceQueryRecord(&ref, flags, opinterface, 90 rrname, rrtype, rrclass, callback, data); 91 if (err != kDNSServiceErr_NoError || ref == NULL || 92 (sockfd = DNSServiceRefSockFD(ref)) == 0) { 93 DNSServiceRefDeallocate(ref); 94 data->status = NSS_UNAVAIL; 95 return (NSS_UNAVAIL); 96 } 97 98 do { 99 FD_ZERO(&readfds); 100 FD_SET(sockfd, &readfds); 101 tv.tv_sec = NSSMDNS_MAXQRYTMO; 102 tv.tv_usec = 0; 103 104 /* Wait until response received from mDNS daemon */ 105 ret = select(sockfd + 1, &readfds, NULL, NULL, &tv); 106 if (!((ret > 0) && FD_ISSET(sockfd, &readfds) && 107 (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError))) { 108 data->status = NSS_NOTFOUND; 109 if (errno != EINTR) 110 data->qrydone = B_TRUE; 111 } 112 } while (data->qrydone != B_TRUE); 113 114 if (data->status == NSS_SUCCESS && (data->withttlbuffer == NULL)) { 115 nss_XbyY_args_t *argp = data->argp; 116 if (argp->buf.result != NULL) { 117 int stat; 118 119 if (data->buffer == NULL) { 120 data->status = NSS_NOTFOUND; 121 DNSServiceRefDeallocate(ref); 122 return (data->status); 123 } 124 stat = (*argp->str2ent)(data->buffer, 125 strlen(data->buffer), 126 argp->buf.result, argp->buf.buffer, 127 argp->buf.buflen); 128 if (stat == NSS_STR_PARSE_SUCCESS) { 129 argp->returnval = argp->buf.result; 130 argp->returnlen = 1; 131 } else { 132 data->status = NSS_NOTFOUND; 133 if (stat == NSS_STR_PARSE_ERANGE) 134 argp->erange = 1; 135 } 136 free(data->buffer); 137 } else { 138 argp->returnval = argp->buf.buffer; 139 argp->returnlen = strlen(argp->buf.buffer); 140 } 141 data->buffer = NULL; 142 data->buflen = 0; 143 } 144 145 if (data->status != NSS_SUCCESS) 146 data->argp->h_errno = HOST_NOT_FOUND; 147 148 DNSServiceRefDeallocate(ref); 149 return (data->status); 150 } 151 152 static void 153 /* LINTED E_FUNC_ARG_UNUSED */ 154 _nss_mdns_querynamereply(DNSServiceRef sdRef, const DNSServiceFlags flags, 155 /* LINTED E_FUNC_ARG_UNUSED */ 156 uint32_t ifIndex, DNSServiceErrorType errorCode, 157 const char *fullname, uint16_t rrtype, uint16_t rrclass, 158 /* LINTED E_FUNC_ARG_UNUSED */ 159 uint16_t rdlen, const void *rdata, uint32_t ttl, 160 void *context) 161 { 162 struct mdns_querydata *qdata; 163 nss_XbyY_args_t *argp; 164 int firstent = 0; 165 int af; 166 char addrstore[INET6_ADDRSTRLEN]; 167 char *buffer; 168 int len; 169 int remlen; 170 171 qdata = (struct mdns_querydata *)context; 172 argp = qdata->argp; 173 174 if (errorCode != kDNSServiceErr_NoError) { 175 qdata->qrydone = B_TRUE; 176 return; 177 } 178 if ((flags & kDNSServiceFlagsMoreComing)) 179 qdata->qrydone = B_FALSE; 180 else 181 qdata->qrydone = B_TRUE; 182 if (!(flags & kDNSServiceFlagsAdd)) 183 return; 184 if (rrclass != kDNSServiceClass_IN) 185 return; 186 187 if (rrtype == kDNSServiceType_A) 188 af = AF_INET; 189 else if (rrtype == kDNSServiceType_AAAA) 190 af = AF_INET6; 191 else 192 return; 193 194 if (qdata->buffer == NULL) { 195 if (qdata->withttlbsize > 0) { 196 remlen = qdata->buflen = 197 qdata->withttlbsize; 198 buffer = qdata->buffer = 199 qdata->withttlbuffer; 200 (void) memset(qdata->buffer, 0, remlen); 201 } else { 202 remlen = qdata->buflen = 203 argp->buf.buflen; 204 if (argp->buf.result != NULL) { 205 buffer = qdata->buffer = 206 calloc(1, remlen); 207 } else { 208 /* Return in file format */ 209 (void) memset(argp->buf.buffer, 210 0, remlen); 211 buffer = qdata->buffer = argp->buf.buffer; 212 } 213 } 214 firstent = 1; 215 } else { 216 buffer = qdata->buffer + strlen(qdata->buffer); 217 remlen = qdata->buflen - strlen(qdata->buffer); 218 } 219 220 #ifdef DEBUG 221 syslog(LOG_DEBUG, "nss_mdns: querynamereply remlen:%d", remlen); 222 #endif 223 if (inet_ntop(af, rdata, addrstore, INET6_ADDRSTRLEN) != NULL) { 224 if (firstent) 225 len = snprintf(buffer, remlen, "%s %s", 226 addrstore, fullname); 227 else 228 len = snprintf(buffer, remlen, "\n%s %s", 229 addrstore, fullname); 230 if (len >= remlen || len < 0) { 231 qdata->status = NSS_NOTFOUND; 232 qdata->argp->erange = 1; 233 qdata->argp->h_errno = HOST_NOT_FOUND; 234 return; 235 } 236 qdata->ttl = ttl; 237 qdata->status = NSS_SUCCESS; 238 #ifdef DEBUG 239 syslog(LOG_DEBUG, "nss_mdns: querynamereply buffer:%s", buffer); 240 #endif 241 } else { 242 qdata->status = NSS_NOTFOUND; 243 qdata->argp->h_errno = HOST_NOT_FOUND; 244 } 245 } 246 247 int 248 _nss_mdns_querybyname(mdns_backend_ptr_t be, char *qname, 249 int af, struct mdns_querydata *data) 250 { 251 int rrtype; 252 int rrclass; 253 int srchidx = 0; 254 int rc; 255 char hname[MAXDNAME]; 256 char *name; 257 char *sname; 258 259 rrclass = kDNSServiceClass_IN; 260 if (af == AF_INET6) 261 rrtype = kDNSServiceType_ANY; 262 else if (af == AF_INET) 263 rrtype = kDNSServiceType_A; 264 else 265 return (NSS_NOTFOUND); 266 267 name = strdup(qname); 268 if (name == NULL) 269 return (NSS_UNAVAIL); 270 271 while ((srchidx = searchdomain(be, name, srchidx, &sname)) != -1) { 272 if (sname != NULL) 273 (void) snprintf(hname, sizeof (hname), "%s.%s", 274 name, sname); 275 else 276 (void) strlcpy(hname, name, sizeof (hname)); 277 #ifdef DEBUG 278 syslog(LOG_DEBUG, "nss_mdns: querybyname called" \ 279 " srchidx:%d af:%d hname:%s", srchidx, af, qname); 280 #endif 281 rc = _nss_mdns_queryrecord(hname, rrclass, rrtype, 282 _nss_mdns_querynamereply, data); 283 if ((rc == NSS_UNAVAIL) || (rc == NSS_SUCCESS)) { 284 free(name); 285 return (rc); 286 } 287 } 288 free(name); 289 return (NSS_NOTFOUND); 290 } 291 292 static void 293 /* LINTED E_FUNC_ARG_UNUSED */ 294 _nss_mdns_queryaddrreply(DNSServiceRef sdRef, const DNSServiceFlags flags, 295 /* LINTED E_FUNC_ARG_UNUSED */ 296 uint32_t ifIndex, DNSServiceErrorType errorCode, 297 /* LINTED E_FUNC_ARG_UNUSED */ 298 const char *fullname, uint16_t rrtype, uint16_t rrclass, 299 uint16_t rdlen, const void *rdata, uint32_t ttl, 300 void *context) 301 { 302 struct mdns_querydata *qdata; 303 nss_XbyY_args_t *argp; 304 char hostname[NI_MAXHOST]; 305 int firstent = 0; 306 char *buffer; 307 int len; 308 int remlen; 309 310 qdata = (struct mdns_querydata *)context; 311 argp = qdata->argp; 312 313 if (errorCode != kDNSServiceErr_NoError) { 314 qdata->qrydone = B_TRUE; 315 return; 316 } 317 if ((flags & kDNSServiceFlagsMoreComing)) 318 qdata->qrydone = B_FALSE; 319 else 320 qdata->qrydone = B_TRUE; 321 if (!(flags & kDNSServiceFlagsAdd)) 322 return; 323 if (rrclass != kDNSServiceClass_IN) 324 return; 325 if (rrtype != kDNSServiceType_PTR) 326 return; 327 328 if (qdata->buffer == NULL) { 329 remlen = qdata->buflen = argp->buf.buflen; 330 if (argp->buf.result != NULL) { 331 buffer = qdata->buffer = calloc(1, remlen); 332 } else { 333 /* Return in file format */ 334 (void) memset(argp->buf.buffer, 0, remlen); 335 buffer = qdata->buffer = argp->buf.buffer; 336 } 337 firstent = 1; 338 } else { 339 buffer = qdata->buffer + strlen(qdata->buffer); 340 remlen = qdata->buflen - strlen(qdata->buffer); 341 } 342 343 if (RDataToName((char *)rdata, hostname, rdlen, NI_MAXHOST) == NULL) { 344 qdata->status = NSS_NOTFOUND; 345 qdata->argp->h_errno = HOST_NOT_FOUND; 346 return; 347 } 348 349 #ifdef DEBUG 350 syslog(LOG_DEBUG, "nss_mdns: querynamereply remlen:%d", remlen); 351 #endif 352 if (firstent) 353 len = snprintf(buffer, remlen, "%s %s", 354 qdata->paddrbuf, hostname); 355 else 356 len = snprintf(buffer, remlen, "\n%s %s", 357 qdata->paddrbuf, hostname); 358 if (len >= remlen || len < 0) { 359 qdata->status = NSS_NOTFOUND; 360 qdata->argp->erange = 1; 361 qdata->argp->h_errno = HOST_NOT_FOUND; 362 return; 363 } 364 qdata->status = NSS_SUCCESS; 365 qdata->ttl = ttl; 366 } 367 368 int 369 /* LINTED E_FUNC_ARG_UNUSED */ 370 _nss_mdns_querybyaddr(mdns_backend_ptr_t be, char *name, int af, 371 struct mdns_querydata *data) 372 { 373 int rrtype; 374 int rrclass; 375 376 #ifdef DEBUG 377 syslog(LOG_DEBUG, "nss_mdns: querybyaddr called" \ 378 " af:%d addr:%s", af, name); 379 #endif 380 rrclass = kDNSServiceClass_IN; 381 rrtype = kDNSServiceType_PTR; 382 383 if (validdomain(be, name, 0) == B_FALSE) { 384 data->status = NSS_NOTFOUND; 385 return (NSS_NOTFOUND); 386 } 387 return (_nss_mdns_queryrecord(name, rrclass, rrtype, 388 _nss_mdns_queryaddrreply, data)); 389 } 390 391 /* 392 * Converts the encoded name in RData returned 393 * by mDNS query to name in file format 394 */ 395 static char * 396 RDataToName(char *data, char *buffer, int datalen, int buflen) 397 { 398 char *src = data; 399 char *srcend = data + datalen; 400 char *ptr = buffer; 401 char *end; 402 char *bend = buffer + buflen - 1; /* terminal '\0' */ 403 int domainlen = 0; 404 405 while ((src < srcend) && (*src != 0)) { 406 407 /* first byte is len */ 408 domainlen = *src++; 409 end = src + domainlen; 410 411 while ((src < end) && (ptr < bend)) { 412 uint8_t ch = *src++; 413 if (ch == '.' || ch == '\\') { 414 *ptr++ = '\\'; 415 } 416 *ptr++ = ch; 417 } 418 419 /* 420 * Check if we copied entire domain str. and 421 * if space is still remaining for '.' seperator 422 */ 423 if ((src != end) || (ptr == bend)) 424 return (NULL); 425 *ptr++ = '.'; 426 } 427 *ptr = '\0'; 428 return (ptr); 429 } 430 431 nss_backend_t * 432 _nss_mdns_constr(mdns_backend_op_t ops[], int n_ops) 433 { 434 mdns_backend_ptr_t be; 435 436 if ((be = (mdns_backend_ptr_t)calloc(1, sizeof (*be))) == NULL) 437 return (NULL); 438 be->ops = ops; 439 be->n_ops = n_ops; 440 _nss_mdns_updatecfg(be); 441 return ((nss_backend_t *)be); 442 } 443 444 void 445 _nss_mdns_destr(mdns_backend_ptr_t be) 446 { 447 if (be != NULL) { 448 _nss_mdns_freesmfcfg(be); 449 free(be); 450 } 451 } 452 453 static int 454 searchdomain(mdns_backend_ptr_t be, char *name, int srchidx, char **sname) 455 { 456 int trailing_dot = 0; 457 char *ch; 458 *sname = NULL; 459 460 ch = name + strlen(name) - 1; 461 if ((*ch) == '.') 462 trailing_dot++; 463 464 if (trailing_dot && srchidx > 0) 465 /* 466 * If there is a trailing dot in the query 467 * name, do not perform any additional queries 468 * with search domains. 469 */ 470 return (-1); 471 472 if (srchidx == 0) { 473 /* 474 * If there is a trailing dot in the query 475 * or atleast one dot in the query name then 476 * perform a query as-is once first. 477 */ 478 ++srchidx; 479 if ((trailing_dot || (strchr(name, '.') != NULL))) { 480 if (validdomain(be, name, 1) == B_TRUE) 481 return (srchidx); 482 else if (trailing_dot) 483 return (-1); 484 } 485 } 486 487 if ((srchidx > NSSMDNS_MAXSRCHDMNS) || 488 (be->dmnsrchlist[srchidx-1] == NULL)) 489 return (-1); 490 491 *sname = be->dmnsrchlist[srchidx-1]; 492 return (++srchidx); 493 } 494 495 /* 496 * This function determines if the domain name in the query 497 * matches any of the valid & search domains in the nss_mdns 498 * configuration. 499 */ 500 static boolean_t 501 validdomain(mdns_backend_ptr_t be, char *name, int chksrchdmns) 502 { 503 char *nameptr; 504 505 /* Remove any trailing and leading dots in the name */ 506 nameptr = name + strlen(name) - 1; 507 while (*nameptr && (nameptr != name) && (*nameptr == '.')) 508 nameptr--; 509 *(++nameptr) = '\0'; 510 nameptr = name; 511 while (*nameptr && (*nameptr == '.')) 512 nameptr++; 513 if (*nameptr == '\0') 514 return (B_FALSE); 515 516 /* Compare with search domains */ 517 if (chksrchdmns && (cmpdmn(nameptr, be->dmnsrchlist, 518 NSSMDNS_MAXSRCHDMNS) == B_TRUE)) 519 return (B_TRUE); 520 521 /* Compare with valid domains */ 522 return (cmpdmn(nameptr, be->validdmnlist, NSSMDNS_MAXVALIDDMNS)); 523 } 524 525 static boolean_t 526 cmpdmn(char *name, char **dmnlist, int maxdmns) 527 { 528 char *vptr; 529 int vdlen; 530 char *cptr; 531 int nlen; 532 int i; 533 534 nlen = strlen(name); 535 for (i = 0; (i < maxdmns) && 536 ((vptr = dmnlist[i]) != NULL); i++) { 537 vdlen = strlen(vptr); 538 if (vdlen > nlen) 539 continue; 540 cptr = name + nlen - vdlen; 541 if (strncasecmp(cptr, vptr, vdlen) == 0) 542 return (B_TRUE); 543 } 544 return (B_FALSE); 545 } 546 547 static void 548 _nss_mdns_get_svcstatetimestamp(struct timeval *ptv) 549 { 550 scf_handle_t *h; 551 scf_simple_prop_t *sprop; 552 int32_t nsec; 553 554 (void) memset(ptv, 0, sizeof (struct timeval)); 555 556 h = scf_handle_create(SCF_VERSION); 557 if (h == NULL) 558 return; 559 560 if (scf_handle_bind(h) == -1) { 561 scf_handle_destroy(h); 562 return; 563 } 564 565 if ((sprop = scf_simple_prop_get(h, SMF_MDNS_FMRI, 566 SCF_PG_RESTARTER, SCF_PROPERTY_STATE_TIMESTAMP)) != NULL) { 567 ptv->tv_sec = *(time_t *)(scf_simple_prop_next_time(sprop, 568 &nsec)); 569 ptv->tv_usec = nsec / 1000; 570 scf_simple_prop_free(sprop); 571 } 572 573 if (h != NULL) 574 scf_handle_destroy(h); 575 } 576 577 void 578 _nss_mdns_updatecfg(mdns_backend_ptr_t be) 579 { 580 struct timeval statetimestamp; 581 582 /* 583 * Update configuration if current svc state timestamp 584 * is different from last known svc state timestamp 585 */ 586 _nss_mdns_get_svcstatetimestamp(&statetimestamp); 587 if ((statetimestamp.tv_sec == 0) && (statetimestamp.tv_usec == 0)) { 588 syslog(LOG_ERR, "nss_mdns: error checking " \ 589 "svc:/network/dns/multicast:default" \ 590 " service timestamp"); 591 } else if ((be->conftimestamp.tv_sec == statetimestamp.tv_sec) && 592 (be->conftimestamp.tv_usec == statetimestamp.tv_usec)) { 593 return; 594 } 595 596 _nss_mdns_freesmfcfg(be); 597 _nss_mdns_loadsmfcfg(be); 598 be->conftimestamp.tv_sec = statetimestamp.tv_sec; 599 be->conftimestamp.tv_usec = statetimestamp.tv_usec; 600 } 601 602 static void 603 load_mdns_domaincfg(scf_handle_t *h, char **storelist, 604 const char *scfprop, int maxprops) 605 { 606 scf_simple_prop_t *sprop; 607 char *tchr; 608 char *pchr; 609 int tlen; 610 int cnt = 0; 611 612 if ((sprop = scf_simple_prop_get(h, SMF_MDNS_FMRI, 613 SMF_NSSMDNSCFG_PROPGRP, scfprop)) == NULL) 614 return; 615 616 while ((cnt < maxprops) && 617 (tchr = scf_simple_prop_next_astring(sprop)) != NULL) { 618 619 /* Remove beginning & trailing '.' chars */ 620 while (*tchr && (*tchr == '.')) 621 tchr++; 622 623 if (*tchr && ((tlen = strlen(tchr)) < MAXDNAME)) { 624 pchr = &tchr[tlen-1]; 625 while ((pchr != tchr) && (*pchr == '.')) 626 pchr--; 627 *(++pchr) = '\0'; 628 storelist[cnt] = strdup(tchr); 629 cnt++; 630 } 631 } 632 scf_simple_prop_free(sprop); 633 } 634 635 static void 636 _nss_mdns_loadsmfcfg(mdns_backend_ptr_t be) 637 { 638 scf_handle_t *h; 639 640 h = scf_handle_create(SCF_VERSION); 641 if (h == NULL) 642 return; 643 644 if (scf_handle_bind(h) == -1) { 645 scf_handle_destroy(h); 646 return; 647 } 648 649 load_mdns_domaincfg(h, &(be->dmnsrchlist[0]), 650 SMF_NSSMDNSCFG_SRCHPROP, NSSMDNS_MAXSRCHDMNS); 651 652 load_mdns_domaincfg(h, &(be->validdmnlist[0]), 653 SMF_NSSMDNSCFG_DMNPROP, NSSMDNS_MAXVALIDDMNS); 654 655 if (h != NULL) 656 scf_handle_destroy(h); 657 } 658 659 static void 660 _nss_mdns_freesmfcfg(mdns_backend_ptr_t be) 661 { 662 int idx; 663 if (be == NULL) 664 return; 665 for (idx = 0; idx < NSSMDNS_MAXSRCHDMNS; idx++) { 666 if (be->dmnsrchlist[idx] != NULL) { 667 free(be->dmnsrchlist[idx]); 668 be->dmnsrchlist[idx] = NULL; 669 } 670 } 671 for (idx = 0; idx < NSSMDNS_MAXVALIDDMNS; idx++) { 672 if (be->validdmnlist[idx] != NULL) { 673 free(be->validdmnlist[idx]); 674 be->validdmnlist[idx] = NULL; 675 } 676 } 677 } 678 679 /* 680 * Performs lookup for IP address by hostname via mDNS and returns 681 * results along with the TTL value from the mDNS resource records. 682 * Called by nscd wth a ptr to packed bufer and packed buffer size. 683 */ 684 nss_status_t 685 _nss_mdns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 686 { 687 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 688 nss_XbyY_args_t arg; 689 int dbop; 690 int af; 691 int len; 692 int blen; 693 char *dbname; 694 nss_status_t sret; 695 char *hname; 696 struct mdns_querydata qdata; 697 nssuint_t *pttl; 698 mdns_backend_ptr_t be = NULL; 699 700 (void) memset(&qdata, 0, sizeof (struct mdns_querydata)); 701 702 qdata.argp = &arg; 703 704 /* 705 * Retrieve withttl buffer and size from the passed packed buffer. 706 * Results are returned along with ttl in this buffer. 707 */ 708 qdata.withttlbsize = pbuf->data_len - sizeof (nssuint_t); 709 qdata.withttlbuffer = (char *)buffer + pbuf->data_off; 710 711 sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg); 712 if (sret != NSS_SUCCESS) 713 return (NSS_ERROR); 714 715 if (ipnode) { 716 if (arg.key.ipnode.flags != 0) 717 return (NSS_ERROR); 718 hname = (char *)arg.key.ipnode.name; 719 af = arg.key.ipnode.af_family; 720 } else { 721 af = AF_INET; 722 hname = (char *)arg.key.name; 723 } 724 725 if ((be = (mdns_backend_ptr_t)calloc(1, sizeof (*be))) == NULL) 726 return (NSS_ERROR); 727 _nss_mdns_updatecfg(be); 728 729 /* Zero out the withttl buffer prior to use */ 730 (void) memset(qdata.withttlbuffer, 0, qdata.withttlbsize); 731 732 #ifdef DEBUG 733 syslog(LOG_DEBUG, "nss_mdns: querybyname withttl called" \ 734 " af:%d hname:%s", af, hname); 735 #endif 736 if (_nss_mdns_querybyname(be, hname, af, &qdata) == NSS_SUCCESS) { 737 blen = strlen(qdata.buffer); 738 len = ROUND_UP(blen, sizeof (nssuint_t)); 739 740 if (len + sizeof (nssuint_t) > pbuf->data_len) { 741 _nss_mdns_freesmfcfg(be); 742 free(be); 743 return (NSS_ERROR); 744 } 745 746 pbuf->ext_off = pbuf->data_off + len; 747 pbuf->ext_len = sizeof (nssuint_t); 748 pbuf->data_len = blen; 749 750 /* Return ttl in the packed buffer at ext_off */ 751 pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off)); 752 *pttl = qdata.ttl; 753 754 _nss_mdns_freesmfcfg(be); 755 free(be); 756 return (NSS_SUCCESS); 757 } 758 _nss_mdns_freesmfcfg(be); 759 free(be); 760 return (NSS_ERROR); 761 } 762