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