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