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