1 /*
2    Unix SMB/CIFS implementation.
3    DNS-SD browse client
4    Copyright (C) Rishi Srivatsavai 2007
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "includes.h"
21 #include "client/client_proto.h"
22 
23 #ifdef WITH_DNSSD_SUPPORT
24 
25 #include <dns_sd.h>
26 #include "system/select.h"
27 
28 /* Holds service instances found during DNS browse */
29 struct mdns_smbsrv_result
30 {
31 	char *serviceName;
32 	char *regType;
33 	char *domain;
34 	uint32_t ifIndex;
35 	struct mdns_smbsrv_result *nextResult;
36 };
37 
38 /* Maintains state during DNS browse */
39 struct mdns_browse_state
40 {
41 	struct mdns_smbsrv_result *listhead; /* Browse result list head */
42 	TALLOC_CTX * ctx;
43 	int browseDone;
44 
45 };
46 
47 
48 static void
do_smb_resolve_reply(DNSServiceRef sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceErrorType errorCode,const char * fullname,const char * hosttarget,uint16_t port,uint16_t txtLen,const unsigned char * txtRecord,void * context)49 do_smb_resolve_reply (DNSServiceRef sdRef, DNSServiceFlags flags,
50 		uint32_t interfaceIndex, DNSServiceErrorType errorCode,
51 		const char *fullname, const char *hosttarget, uint16_t port,
52 		uint16_t txtLen, const unsigned char *txtRecord, void *context)
53 {
54 	printf("SMB service available on %s port %u\n",
55 		hosttarget, ntohs(port));
56 }
57 
58 
do_smb_resolve(struct mdns_smbsrv_result * browsesrv)59 static void do_smb_resolve(struct mdns_smbsrv_result *browsesrv)
60 {
61 	DNSServiceRef mdns_conn_sdref = NULL;
62 	int mdnsfd;
63 	int fdsetsz;
64 	int ret;
65 	struct timeval tv;
66 	DNSServiceErrorType err;
67 
68 	TALLOC_CTX * ctx = talloc_new(NULL);
69 
70 	err = DNSServiceResolve(&mdns_conn_sdref, 0 /* flags */,
71 		browsesrv->ifIndex,
72 		browsesrv->serviceName, browsesrv->regType, browsesrv->domain,
73 		do_smb_resolve_reply, NULL);
74 
75 	if (err != kDNSServiceErr_NoError) {
76 		return;
77 	}
78 
79 	mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
80 	for (;;)  {
81 		int revents;
82 
83 		ret = poll_one_fd(mdnsfd, POLLIN|POLLHUP, 1000, &revents);
84 		if (ret <= 0 && errno != EINTR) {
85 			break;
86 		}
87 
88 		if (revents & (POLLIN|POLLHUP|POLLERR)) {
89 			/* Invoke callback function */
90 			DNSServiceProcessResult(mdns_conn_sdref);
91 			break;
92 		}
93 	}
94 
95 	TALLOC_FREE(ctx);
96 	DNSServiceRefDeallocate(mdns_conn_sdref);
97 }
98 
99 
100 static void
do_smb_browse_reply(DNSServiceRef sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceErrorType errorCode,const char * serviceName,const char * regtype,const char * replyDomain,void * context)101 do_smb_browse_reply(DNSServiceRef sdRef, DNSServiceFlags flags,
102         uint32_t interfaceIndex, DNSServiceErrorType errorCode,
103         const char  *serviceName, const char *regtype,
104         const char  *replyDomain, void  *context)
105 {
106 	struct mdns_browse_state *bstatep = (struct mdns_browse_state *)context;
107 	struct mdns_smbsrv_result *bresult;
108 
109 	if (bstatep == NULL) {
110 		return;
111 	}
112 
113 	if (errorCode != kDNSServiceErr_NoError) {
114 		bstatep->browseDone = 1;
115 		return;
116 	}
117 
118 	if (flags & kDNSServiceFlagsMoreComing) {
119 		bstatep->browseDone = 0;
120 	} else {
121 		bstatep->browseDone = 1;
122 	}
123 
124 	if (!(flags & kDNSServiceFlagsAdd)) {
125 		return;
126 	}
127 
128 	bresult = talloc_array(bstatep->ctx, struct mdns_smbsrv_result, 1);
129 	if (bresult == NULL) {
130 		return;
131 	}
132 
133 	bresult->nextResult = NULL;
134 	if (bstatep->listhead != NULL) {
135 		bresult->nextResult = bstatep->listhead;
136 	}
137 
138 	bresult->serviceName = talloc_strdup(bstatep->ctx, serviceName);
139 	bresult->regType = talloc_strdup(bstatep->ctx, regtype);
140 	bresult->domain = talloc_strdup(bstatep->ctx, replyDomain);
141 	bresult->ifIndex = interfaceIndex;
142 	bstatep->listhead = bresult;
143 }
144 
do_smb_browse(void)145 int do_smb_browse(void)
146 {
147 	int mdnsfd;
148 	int fdsetsz;
149 	int ret;
150 	struct mdns_browse_state bstate;
151 	struct mdns_smbsrv_result *resptr;
152 	struct timeval tv;
153 	DNSServiceRef mdns_conn_sdref = NULL;
154 	DNSServiceErrorType err;
155 
156 	TALLOC_CTX * ctx = talloc_new(NULL);
157 
158 	ZERO_STRUCT(bstate);
159 
160 	bstate.ctx = ctx;
161 	bstate.listhead = NULL;
162 
163 	err = DNSServiceBrowse(&mdns_conn_sdref, 0, 0, "_smb._tcp", "",
164 			do_smb_browse_reply, &bstate);
165 
166 	if (err != kDNSServiceErr_NoError) {
167 		d_printf("Error connecting to the Multicast DNS daemon\n");
168 		TALLOC_FREE(ctx);
169 		return 1;
170 	}
171 
172 	mdnsfd = DNSServiceRefSockFD(mdns_conn_sdref);
173 	for (;;)  {
174 		int revents;
175 
176 		ret = poll_one_fd(mdnsfd, POLLIN|POLLHUP, 1000, &revents);
177 		if (ret <= 0 && errno != EINTR) {
178 			break;
179 		}
180 
181 		if (revents & (POLLIN|POLLHUP|POLLERR)) {
182 			/* Invoke callback function */
183 			if (DNSServiceProcessResult(mdns_conn_sdref)) {
184 				break;
185 			}
186 			if (bstate.browseDone) {
187 				break;
188 			}
189 		}
190 	}
191 
192 	DNSServiceRefDeallocate(mdns_conn_sdref);
193 
194 	if (bstate.listhead != NULL) {
195 		resptr = bstate.listhead;
196 		while (resptr != NULL) {
197 			struct mdns_smbsrv_result *oldresptr;
198 			oldresptr = resptr;
199 
200 			/* Resolve smb service instance */
201 			do_smb_resolve(resptr);
202 
203 			resptr = resptr->nextResult;
204 		}
205 	}
206 
207 	TALLOC_FREE(ctx);
208 	return 0;
209 }
210 
211 #else /* WITH_DNSSD_SUPPORT */
212 
do_smb_browse(void)213 int do_smb_browse(void)
214 {
215     d_printf("DNS-SD browsing is not supported on this platform\n");
216     return 1;
217 }
218 
219 #endif /* WITH_DNSSD_SUPPORT */
220 
221 
222