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
_nss_mdns_queryrecord(const char * rrname,int rrclass,int rrtype,DNSServiceQueryRecordReply callback,struct mdns_querydata * data)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 */
_nss_mdns_querynamereply(DNSServiceRef sdRef,const DNSServiceFlags flags,uint32_t ifIndex,DNSServiceErrorType errorCode,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,void * context)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
_nss_mdns_querybyname(mdns_backend_ptr_t be,char * qname,int af,struct mdns_querydata * data)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 */
_nss_mdns_queryaddrreply(DNSServiceRef sdRef,const DNSServiceFlags flags,uint32_t ifIndex,DNSServiceErrorType errorCode,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,void * context)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 */
_nss_mdns_querybyaddr(mdns_backend_ptr_t be,char * name,int af,struct mdns_querydata * data)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 *
RDataToName(char * data,char * buffer,int datalen,int buflen)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 *
_nss_mdns_constr(mdns_backend_op_t ops[],int n_ops)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
_nss_mdns_destr(mdns_backend_ptr_t be)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
searchdomain(mdns_backend_ptr_t be,char * name,int srchidx,char ** sname)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
validdomain(mdns_backend_ptr_t be,char * name,int chksrchdmns)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
cmpdmn(char * name,char ** dmnlist,int maxdmns)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
_nss_mdns_get_svcstatetimestamp(struct timeval * ptv)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
_nss_mdns_updatecfg(mdns_backend_ptr_t be)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
load_mdns_domaincfg(scf_handle_t * h,char ** storelist,const char * scfprop,int maxprops)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
_nss_mdns_loadsmfcfg(mdns_backend_ptr_t be)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
_nss_mdns_freesmfcfg(mdns_backend_ptr_t be)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
_nss_mdns_gethost_withttl(void * buffer,size_t bufsize,int ipnode)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