1*ae771770SStanislav Sedov /*
2*ae771770SStanislav Sedov * Copyright (c) 2008 Apple Inc. All Rights Reserved.
3*ae771770SStanislav Sedov *
4*ae771770SStanislav Sedov * Export of this software from the United States of America may require
5*ae771770SStanislav Sedov * a specific license from the United States Government. It is the
6*ae771770SStanislav Sedov * responsibility of any person or organization contemplating export to
7*ae771770SStanislav Sedov * obtain such a license before exporting.
8*ae771770SStanislav Sedov *
9*ae771770SStanislav Sedov * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
10*ae771770SStanislav Sedov * distribute this software and its documentation for any purpose and
11*ae771770SStanislav Sedov * without fee is hereby granted, provided that the above copyright
12*ae771770SStanislav Sedov * notice appear in all copies and that both that copyright notice and
13*ae771770SStanislav Sedov * this permission notice appear in supporting documentation, and that
14*ae771770SStanislav Sedov * the name of Apple Inc. not be used in advertising or publicity pertaining
15*ae771770SStanislav Sedov * to distribution of the software without specific, written prior
16*ae771770SStanislav Sedov * permission. Apple Inc. makes no representations about the suitability of
17*ae771770SStanislav Sedov * this software for any purpose. It is provided "as is" without express
18*ae771770SStanislav Sedov * or implied warranty.
19*ae771770SStanislav Sedov *
20*ae771770SStanislav Sedov * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
21*ae771770SStanislav Sedov * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
22*ae771770SStanislav Sedov * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23*ae771770SStanislav Sedov *
24*ae771770SStanislav Sedov */
25*ae771770SStanislav Sedov
26*ae771770SStanislav Sedov #include "kdc_locl.h"
27*ae771770SStanislav Sedov
28*ae771770SStanislav Sedov #if defined(__APPLE__) && defined(HAVE_GCD)
29*ae771770SStanislav Sedov
30*ae771770SStanislav Sedov #include <CoreFoundation/CoreFoundation.h>
31*ae771770SStanislav Sedov #include <SystemConfiguration/SCDynamicStore.h>
32*ae771770SStanislav Sedov #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
33*ae771770SStanislav Sedov #include <SystemConfiguration/SCDynamicStoreKey.h>
34*ae771770SStanislav Sedov
35*ae771770SStanislav Sedov #include <dispatch/dispatch.h>
36*ae771770SStanislav Sedov
37*ae771770SStanislav Sedov #include <asl.h>
38*ae771770SStanislav Sedov #include <resolv.h>
39*ae771770SStanislav Sedov
40*ae771770SStanislav Sedov #include <dns_sd.h>
41*ae771770SStanislav Sedov #include <err.h>
42*ae771770SStanislav Sedov
43*ae771770SStanislav Sedov static krb5_kdc_configuration *announce_config;
44*ae771770SStanislav Sedov static krb5_context announce_context;
45*ae771770SStanislav Sedov
46*ae771770SStanislav Sedov struct entry {
47*ae771770SStanislav Sedov DNSRecordRef recordRef;
48*ae771770SStanislav Sedov char *domain;
49*ae771770SStanislav Sedov char *realm;
50*ae771770SStanislav Sedov #define F_EXISTS 1
51*ae771770SStanislav Sedov #define F_PUSH 2
52*ae771770SStanislav Sedov int flags;
53*ae771770SStanislav Sedov struct entry *next;
54*ae771770SStanislav Sedov };
55*ae771770SStanislav Sedov
56*ae771770SStanislav Sedov /* #define REGISTER_SRV_RR */
57*ae771770SStanislav Sedov
58*ae771770SStanislav Sedov static struct entry *g_entries = NULL;
59*ae771770SStanislav Sedov static CFStringRef g_hostname = NULL;
60*ae771770SStanislav Sedov static DNSServiceRef g_dnsRef = NULL;
61*ae771770SStanislav Sedov static SCDynamicStoreRef g_store = NULL;
62*ae771770SStanislav Sedov static dispatch_queue_t g_queue = NULL;
63*ae771770SStanislav Sedov
64*ae771770SStanislav Sedov #define LOG(...) asl_log(NULL, NULL, ASL_LEVEL_INFO, __VA_ARGS__)
65*ae771770SStanislav Sedov
66*ae771770SStanislav Sedov static void create_dns_sd(void);
67*ae771770SStanislav Sedov static void destroy_dns_sd(void);
68*ae771770SStanislav Sedov static void update_all(SCDynamicStoreRef, CFArrayRef, void *);
69*ae771770SStanislav Sedov
70*ae771770SStanislav Sedov
71*ae771770SStanislav Sedov /* parameters */
72*ae771770SStanislav Sedov static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
73*ae771770SStanislav Sedov
74*ae771770SStanislav Sedov
75*ae771770SStanislav Sedov static char *
CFString2utf8(CFStringRef string)76*ae771770SStanislav Sedov CFString2utf8(CFStringRef string)
77*ae771770SStanislav Sedov {
78*ae771770SStanislav Sedov size_t size;
79*ae771770SStanislav Sedov char *str;
80*ae771770SStanislav Sedov
81*ae771770SStanislav Sedov size = 1 + CFStringGetMaximumSizeForEncoding(CFStringGetLength(string), kCFStringEncodingUTF8);
82*ae771770SStanislav Sedov str = malloc(size);
83*ae771770SStanislav Sedov if (str == NULL)
84*ae771770SStanislav Sedov return NULL;
85*ae771770SStanislav Sedov
86*ae771770SStanislav Sedov if (CFStringGetCString(string, str, size, kCFStringEncodingUTF8) == false) {
87*ae771770SStanislav Sedov free(str);
88*ae771770SStanislav Sedov return NULL;
89*ae771770SStanislav Sedov }
90*ae771770SStanislav Sedov return str;
91*ae771770SStanislav Sedov }
92*ae771770SStanislav Sedov
93*ae771770SStanislav Sedov /*
94*ae771770SStanislav Sedov *
95*ae771770SStanislav Sedov */
96*ae771770SStanislav Sedov
97*ae771770SStanislav Sedov static void
retry_timer(void)98*ae771770SStanislav Sedov retry_timer(void)
99*ae771770SStanislav Sedov {
100*ae771770SStanislav Sedov dispatch_source_t s;
101*ae771770SStanislav Sedov dispatch_time_t t;
102*ae771770SStanislav Sedov
103*ae771770SStanislav Sedov s = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
104*ae771770SStanislav Sedov 0, 0, g_queue);
105*ae771770SStanislav Sedov t = dispatch_time(DISPATCH_TIME_NOW, 5ull * NSEC_PER_SEC);
106*ae771770SStanislav Sedov dispatch_source_set_timer(s, t, 0, NSEC_PER_SEC);
107*ae771770SStanislav Sedov dispatch_source_set_event_handler(s, ^{
108*ae771770SStanislav Sedov create_dns_sd();
109*ae771770SStanislav Sedov dispatch_release(s);
110*ae771770SStanislav Sedov });
111*ae771770SStanislav Sedov dispatch_resume(s);
112*ae771770SStanislav Sedov }
113*ae771770SStanislav Sedov
114*ae771770SStanislav Sedov /*
115*ae771770SStanislav Sedov *
116*ae771770SStanislav Sedov */
117*ae771770SStanislav Sedov
118*ae771770SStanislav Sedov static void
create_dns_sd(void)119*ae771770SStanislav Sedov create_dns_sd(void)
120*ae771770SStanislav Sedov {
121*ae771770SStanislav Sedov DNSServiceErrorType error;
122*ae771770SStanislav Sedov dispatch_source_t s;
123*ae771770SStanislav Sedov
124*ae771770SStanislav Sedov error = DNSServiceCreateConnection(&g_dnsRef);
125*ae771770SStanislav Sedov if (error) {
126*ae771770SStanislav Sedov retry_timer();
127*ae771770SStanislav Sedov return;
128*ae771770SStanislav Sedov }
129*ae771770SStanislav Sedov
130*ae771770SStanislav Sedov dispatch_suspend(g_queue);
131*ae771770SStanislav Sedov
132*ae771770SStanislav Sedov s = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
133*ae771770SStanislav Sedov DNSServiceRefSockFD(g_dnsRef),
134*ae771770SStanislav Sedov 0, g_queue);
135*ae771770SStanislav Sedov
136*ae771770SStanislav Sedov dispatch_source_set_event_handler(s, ^{
137*ae771770SStanislav Sedov DNSServiceErrorType ret = DNSServiceProcessResult(g_dnsRef);
138*ae771770SStanislav Sedov /* on error tear down and set timer to recreate */
139*ae771770SStanislav Sedov if (ret != kDNSServiceErr_NoError && ret != kDNSServiceErr_Transient) {
140*ae771770SStanislav Sedov dispatch_source_cancel(s);
141*ae771770SStanislav Sedov }
142*ae771770SStanislav Sedov });
143*ae771770SStanislav Sedov
144*ae771770SStanislav Sedov dispatch_source_set_cancel_handler(s, ^{
145*ae771770SStanislav Sedov destroy_dns_sd();
146*ae771770SStanislav Sedov retry_timer();
147*ae771770SStanislav Sedov dispatch_release(s);
148*ae771770SStanislav Sedov });
149*ae771770SStanislav Sedov
150*ae771770SStanislav Sedov dispatch_resume(s);
151*ae771770SStanislav Sedov
152*ae771770SStanislav Sedov /* Do the first update ourself */
153*ae771770SStanislav Sedov update_all(g_store, NULL, NULL);
154*ae771770SStanislav Sedov dispatch_resume(g_queue);
155*ae771770SStanislav Sedov }
156*ae771770SStanislav Sedov
157*ae771770SStanislav Sedov static void
domain_add(const char * domain,const char * realm,int flag)158*ae771770SStanislav Sedov domain_add(const char *domain, const char *realm, int flag)
159*ae771770SStanislav Sedov {
160*ae771770SStanislav Sedov struct entry *e;
161*ae771770SStanislav Sedov
162*ae771770SStanislav Sedov for (e = g_entries; e != NULL; e = e->next) {
163*ae771770SStanislav Sedov if (strcmp(domain, e->domain) == 0 && strcmp(realm, e->realm) == 0) {
164*ae771770SStanislav Sedov e->flags |= flag;
165*ae771770SStanislav Sedov return;
166*ae771770SStanislav Sedov }
167*ae771770SStanislav Sedov }
168*ae771770SStanislav Sedov
169*ae771770SStanislav Sedov LOG("Adding realm %s to domain %s", realm, domain);
170*ae771770SStanislav Sedov
171*ae771770SStanislav Sedov e = calloc(1, sizeof(*e));
172*ae771770SStanislav Sedov if (e == NULL)
173*ae771770SStanislav Sedov return;
174*ae771770SStanislav Sedov e->domain = strdup(domain);
175*ae771770SStanislav Sedov e->realm = strdup(realm);
176*ae771770SStanislav Sedov if (e->domain == NULL || e->realm == NULL) {
177*ae771770SStanislav Sedov free(e->domain);
178*ae771770SStanislav Sedov free(e->realm);
179*ae771770SStanislav Sedov free(e);
180*ae771770SStanislav Sedov return;
181*ae771770SStanislav Sedov }
182*ae771770SStanislav Sedov e->flags = flag | F_PUSH; /* if we allocate, we push */
183*ae771770SStanislav Sedov e->next = g_entries;
184*ae771770SStanislav Sedov g_entries = e;
185*ae771770SStanislav Sedov }
186*ae771770SStanislav Sedov
187*ae771770SStanislav Sedov struct addctx {
188*ae771770SStanislav Sedov int flags;
189*ae771770SStanislav Sedov const char *realm;
190*ae771770SStanislav Sedov };
191*ae771770SStanislav Sedov
192*ae771770SStanislav Sedov static void
domains_add(const void * key,const void * value,void * context)193*ae771770SStanislav Sedov domains_add(const void *key, const void *value, void *context)
194*ae771770SStanislav Sedov {
195*ae771770SStanislav Sedov char *str = CFString2utf8((CFStringRef)value);
196*ae771770SStanislav Sedov struct addctx *ctx = context;
197*ae771770SStanislav Sedov
198*ae771770SStanislav Sedov if (str == NULL)
199*ae771770SStanislav Sedov return;
200*ae771770SStanislav Sedov if (str[0] != '\0')
201*ae771770SStanislav Sedov domain_add(str, ctx->realm, F_EXISTS | ctx->flags);
202*ae771770SStanislav Sedov free(str);
203*ae771770SStanislav Sedov }
204*ae771770SStanislav Sedov
205*ae771770SStanislav Sedov
206*ae771770SStanislav Sedov static void
dnsCallback(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags,DNSServiceErrorType errorCode,void * context)207*ae771770SStanislav Sedov dnsCallback(DNSServiceRef sdRef __attribute__((unused)),
208*ae771770SStanislav Sedov DNSRecordRef RecordRef __attribute__((unused)),
209*ae771770SStanislav Sedov DNSServiceFlags flags __attribute__((unused)),
210*ae771770SStanislav Sedov DNSServiceErrorType errorCode __attribute__((unused)),
211*ae771770SStanislav Sedov void *context __attribute__((unused)))
212*ae771770SStanislav Sedov {
213*ae771770SStanislav Sedov }
214*ae771770SStanislav Sedov
215*ae771770SStanislav Sedov #ifdef REGISTER_SRV_RR
216*ae771770SStanislav Sedov
217*ae771770SStanislav Sedov /*
218*ae771770SStanislav Sedov * Register DNS SRV rr for the realm.
219*ae771770SStanislav Sedov */
220*ae771770SStanislav Sedov
221*ae771770SStanislav Sedov static const char *register_names[2] = {
222*ae771770SStanislav Sedov "_kerberos._tcp",
223*ae771770SStanislav Sedov "_kerberos._udp"
224*ae771770SStanislav Sedov };
225*ae771770SStanislav Sedov
226*ae771770SStanislav Sedov static struct {
227*ae771770SStanislav Sedov DNSRecordRef *val;
228*ae771770SStanislav Sedov size_t len;
229*ae771770SStanislav Sedov } srvRefs = { NULL, 0 };
230*ae771770SStanislav Sedov
231*ae771770SStanislav Sedov static void
register_srv(const char * realm,const char * hostname,int port)232*ae771770SStanislav Sedov register_srv(const char *realm, const char *hostname, int port)
233*ae771770SStanislav Sedov {
234*ae771770SStanislav Sedov unsigned char target[1024];
235*ae771770SStanislav Sedov int i;
236*ae771770SStanislav Sedov int size;
237*ae771770SStanislav Sedov
238*ae771770SStanislav Sedov /* skip registering LKDC realms */
239*ae771770SStanislav Sedov if (strncmp(realm, "LKDC:", 5) == 0)
240*ae771770SStanislav Sedov return;
241*ae771770SStanislav Sedov
242*ae771770SStanislav Sedov /* encode SRV-RR */
243*ae771770SStanislav Sedov target[0] = 0; /* priority */
244*ae771770SStanislav Sedov target[1] = 0; /* priority */
245*ae771770SStanislav Sedov target[2] = 0; /* weight */
246*ae771770SStanislav Sedov target[3] = 0; /* weigth */
247*ae771770SStanislav Sedov target[4] = (port >> 8) & 0xff; /* port */
248*ae771770SStanislav Sedov target[5] = (port >> 0) & 0xff; /* port */
249*ae771770SStanislav Sedov
250*ae771770SStanislav Sedov size = dn_comp(hostname, target + 6, sizeof(target) - 6, NULL, NULL);
251*ae771770SStanislav Sedov if (size < 0)
252*ae771770SStanislav Sedov return;
253*ae771770SStanislav Sedov
254*ae771770SStanislav Sedov size += 6;
255*ae771770SStanislav Sedov
256*ae771770SStanislav Sedov LOG("register SRV rr for realm %s hostname %s:%d", realm, hostname, port);
257*ae771770SStanislav Sedov
258*ae771770SStanislav Sedov for (i = 0; i < sizeof(register_names)/sizeof(register_names[0]); i++) {
259*ae771770SStanislav Sedov char name[kDNSServiceMaxDomainName];
260*ae771770SStanislav Sedov DNSServiceErrorType error;
261*ae771770SStanislav Sedov void *ptr;
262*ae771770SStanislav Sedov
263*ae771770SStanislav Sedov ptr = realloc(srvRefs.val, sizeof(srvRefs.val[0]) * (srvRefs.len + 1));
264*ae771770SStanislav Sedov if (ptr == NULL)
265*ae771770SStanislav Sedov errx(1, "malloc: out of memory");
266*ae771770SStanislav Sedov srvRefs.val = ptr;
267*ae771770SStanislav Sedov
268*ae771770SStanislav Sedov DNSServiceConstructFullName(name, NULL, register_names[i], realm);
269*ae771770SStanislav Sedov
270*ae771770SStanislav Sedov error = DNSServiceRegisterRecord(g_dnsRef,
271*ae771770SStanislav Sedov &srvRefs.val[srvRefs.len],
272*ae771770SStanislav Sedov kDNSServiceFlagsUnique | kDNSServiceFlagsShareConnection,
273*ae771770SStanislav Sedov 0,
274*ae771770SStanislav Sedov name,
275*ae771770SStanislav Sedov kDNSServiceType_SRV,
276*ae771770SStanislav Sedov kDNSServiceClass_IN,
277*ae771770SStanislav Sedov size,
278*ae771770SStanislav Sedov target,
279*ae771770SStanislav Sedov 0,
280*ae771770SStanislav Sedov dnsCallback,
281*ae771770SStanislav Sedov NULL);
282*ae771770SStanislav Sedov if (error) {
283*ae771770SStanislav Sedov LOG("Failed to register SRV rr for realm %s: %d", realm, error);
284*ae771770SStanislav Sedov } else
285*ae771770SStanislav Sedov srvRefs.len++;
286*ae771770SStanislav Sedov }
287*ae771770SStanislav Sedov }
288*ae771770SStanislav Sedov
289*ae771770SStanislav Sedov static void
unregister_srv_realms(void)290*ae771770SStanislav Sedov unregister_srv_realms(void)
291*ae771770SStanislav Sedov {
292*ae771770SStanislav Sedov if (g_dnsRef) {
293*ae771770SStanislav Sedov for (i = 0; i < srvRefs.len; i++)
294*ae771770SStanislav Sedov DNSServiceRemoveRecord(g_dnsRef, srvRefs.val[i], 0);
295*ae771770SStanislav Sedov }
296*ae771770SStanislav Sedov free(srvRefs.val);
297*ae771770SStanislav Sedov srvRefs.len = 0;
298*ae771770SStanislav Sedov srvRefs.val = NULL;
299*ae771770SStanislav Sedov }
300*ae771770SStanislav Sedov
301*ae771770SStanislav Sedov static void
register_srv_realms(CFStringRef host)302*ae771770SStanislav Sedov register_srv_realms(CFStringRef host)
303*ae771770SStanislav Sedov {
304*ae771770SStanislav Sedov krb5_error_code ret;
305*ae771770SStanislav Sedov char *hostname;
306*ae771770SStanislav Sedov size_t i;
307*ae771770SStanislav Sedov
308*ae771770SStanislav Sedov /* first unregister old names */
309*ae771770SStanislav Sedov
310*ae771770SStanislav Sedov hostname = CFString2utf8(host);
311*ae771770SStanislav Sedov if (hostname == NULL)
312*ae771770SStanislav Sedov return;
313*ae771770SStanislav Sedov
314*ae771770SStanislav Sedov for(i = 0; i < announce_config->num_db; i++) {
315*ae771770SStanislav Sedov char **realms, **r;
316*ae771770SStanislav Sedov
317*ae771770SStanislav Sedov if (announce_config->db[i]->hdb_get_realms == NULL)
318*ae771770SStanislav Sedov continue;
319*ae771770SStanislav Sedov
320*ae771770SStanislav Sedov ret = (announce_config->db[i]->hdb_get_realms)(announce_context, &realms);
321*ae771770SStanislav Sedov if (ret == 0) {
322*ae771770SStanislav Sedov for (r = realms; r && *r; r++)
323*ae771770SStanislav Sedov register_srv(*r, hostname, 88);
324*ae771770SStanislav Sedov krb5_free_host_realm(announce_context, realms);
325*ae771770SStanislav Sedov }
326*ae771770SStanislav Sedov }
327*ae771770SStanislav Sedov
328*ae771770SStanislav Sedov free(hostname);
329*ae771770SStanislav Sedov }
330*ae771770SStanislav Sedov #endif /* REGISTER_SRV_RR */
331*ae771770SStanislav Sedov
332*ae771770SStanislav Sedov static void
update_dns(void)333*ae771770SStanislav Sedov update_dns(void)
334*ae771770SStanislav Sedov {
335*ae771770SStanislav Sedov DNSServiceErrorType error;
336*ae771770SStanislav Sedov struct entry **e = &g_entries;
337*ae771770SStanislav Sedov char *hostname;
338*ae771770SStanislav Sedov
339*ae771770SStanislav Sedov hostname = CFString2utf8(g_hostname);
340*ae771770SStanislav Sedov if (hostname == NULL)
341*ae771770SStanislav Sedov return;
342*ae771770SStanislav Sedov
343*ae771770SStanislav Sedov while (*e != NULL) {
344*ae771770SStanislav Sedov /* remove if this wasn't updated */
345*ae771770SStanislav Sedov if (((*e)->flags & F_EXISTS) == 0) {
346*ae771770SStanislav Sedov struct entry *drop = *e;
347*ae771770SStanislav Sedov *e = (*e)->next;
348*ae771770SStanislav Sedov
349*ae771770SStanislav Sedov LOG("Deleting realm %s from domain %s",
350*ae771770SStanislav Sedov drop->realm, drop->domain);
351*ae771770SStanislav Sedov
352*ae771770SStanislav Sedov if (drop->recordRef && g_dnsRef)
353*ae771770SStanislav Sedov DNSServiceRemoveRecord(g_dnsRef, drop->recordRef, 0);
354*ae771770SStanislav Sedov free(drop->domain);
355*ae771770SStanislav Sedov free(drop->realm);
356*ae771770SStanislav Sedov free(drop);
357*ae771770SStanislav Sedov continue;
358*ae771770SStanislav Sedov }
359*ae771770SStanislav Sedov if ((*e)->flags & F_PUSH) {
360*ae771770SStanislav Sedov struct entry *update = *e;
361*ae771770SStanislav Sedov char *dnsdata, *name;
362*ae771770SStanislav Sedov size_t len;
363*ae771770SStanislav Sedov
364*ae771770SStanislav Sedov len = strlen(update->realm);
365*ae771770SStanislav Sedov asprintf(&dnsdata, "%c%s", (int)len, update->realm);
366*ae771770SStanislav Sedov if (dnsdata == NULL)
367*ae771770SStanislav Sedov errx(1, "malloc");
368*ae771770SStanislav Sedov
369*ae771770SStanislav Sedov asprintf(&name, "_kerberos.%s.%s", hostname, update->domain);
370*ae771770SStanislav Sedov if (name == NULL)
371*ae771770SStanislav Sedov errx(1, "malloc");
372*ae771770SStanislav Sedov
373*ae771770SStanislav Sedov if (update->recordRef)
374*ae771770SStanislav Sedov DNSServiceRemoveRecord(g_dnsRef, update->recordRef, 0);
375*ae771770SStanislav Sedov
376*ae771770SStanislav Sedov error = DNSServiceRegisterRecord(g_dnsRef,
377*ae771770SStanislav Sedov &update->recordRef,
378*ae771770SStanislav Sedov kDNSServiceFlagsShared | kDNSServiceFlagsAllowRemoteQuery,
379*ae771770SStanislav Sedov 0,
380*ae771770SStanislav Sedov name,
381*ae771770SStanislav Sedov kDNSServiceType_TXT,
382*ae771770SStanislav Sedov kDNSServiceClass_IN,
383*ae771770SStanislav Sedov len+1,
384*ae771770SStanislav Sedov dnsdata,
385*ae771770SStanislav Sedov 0,
386*ae771770SStanislav Sedov dnsCallback,
387*ae771770SStanislav Sedov NULL);
388*ae771770SStanislav Sedov free(name);
389*ae771770SStanislav Sedov free(dnsdata);
390*ae771770SStanislav Sedov if (error)
391*ae771770SStanislav Sedov errx(1, "failure to update entry for %s/%s",
392*ae771770SStanislav Sedov update->domain, update->realm);
393*ae771770SStanislav Sedov }
394*ae771770SStanislav Sedov e = &(*e)->next;
395*ae771770SStanislav Sedov }
396*ae771770SStanislav Sedov free(hostname);
397*ae771770SStanislav Sedov }
398*ae771770SStanislav Sedov
399*ae771770SStanislav Sedov static void
update_entries(SCDynamicStoreRef store,const char * realm,int flags)400*ae771770SStanislav Sedov update_entries(SCDynamicStoreRef store, const char *realm, int flags)
401*ae771770SStanislav Sedov {
402*ae771770SStanislav Sedov CFDictionaryRef btmm;
403*ae771770SStanislav Sedov
404*ae771770SStanislav Sedov /* we always announce in the local domain */
405*ae771770SStanislav Sedov domain_add("local", realm, F_EXISTS | flags);
406*ae771770SStanislav Sedov
407*ae771770SStanislav Sedov /* announce btmm */
408*ae771770SStanislav Sedov btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
409*ae771770SStanislav Sedov if (btmm) {
410*ae771770SStanislav Sedov struct addctx addctx;
411*ae771770SStanislav Sedov
412*ae771770SStanislav Sedov addctx.flags = flags;
413*ae771770SStanislav Sedov addctx.realm = realm;
414*ae771770SStanislav Sedov
415*ae771770SStanislav Sedov CFDictionaryApplyFunction(btmm, domains_add, &addctx);
416*ae771770SStanislav Sedov CFRelease(btmm);
417*ae771770SStanislav Sedov }
418*ae771770SStanislav Sedov }
419*ae771770SStanislav Sedov
420*ae771770SStanislav Sedov static void
update_all(SCDynamicStoreRef store,CFArrayRef changedKeys,void * info)421*ae771770SStanislav Sedov update_all(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
422*ae771770SStanislav Sedov {
423*ae771770SStanislav Sedov struct entry *e;
424*ae771770SStanislav Sedov CFStringRef host;
425*ae771770SStanislav Sedov int i, flags = 0;
426*ae771770SStanislav Sedov
427*ae771770SStanislav Sedov LOG("something changed, running update");
428*ae771770SStanislav Sedov
429*ae771770SStanislav Sedov host = SCDynamicStoreCopyLocalHostName(store);
430*ae771770SStanislav Sedov if (host == NULL)
431*ae771770SStanislav Sedov return;
432*ae771770SStanislav Sedov
433*ae771770SStanislav Sedov if (g_hostname == NULL || CFStringCompare(host, g_hostname, 0) != kCFCompareEqualTo) {
434*ae771770SStanislav Sedov if (g_hostname)
435*ae771770SStanislav Sedov CFRelease(g_hostname);
436*ae771770SStanislav Sedov g_hostname = CFRetain(host);
437*ae771770SStanislav Sedov flags = F_PUSH; /* if hostname has changed, force push */
438*ae771770SStanislav Sedov
439*ae771770SStanislav Sedov #ifdef REGISTER_SRV_RR
440*ae771770SStanislav Sedov register_srv_realms(g_hostname);
441*ae771770SStanislav Sedov #endif
442*ae771770SStanislav Sedov }
443*ae771770SStanislav Sedov
444*ae771770SStanislav Sedov for (e = g_entries; e != NULL; e = e->next)
445*ae771770SStanislav Sedov e->flags &= ~(F_EXISTS|F_PUSH);
446*ae771770SStanislav Sedov
447*ae771770SStanislav Sedov for(i = 0; i < announce_config->num_db; i++) {
448*ae771770SStanislav Sedov krb5_error_code ret;
449*ae771770SStanislav Sedov char **realms, **r;
450*ae771770SStanislav Sedov
451*ae771770SStanislav Sedov if (announce_config->db[i]->hdb_get_realms == NULL)
452*ae771770SStanislav Sedov continue;
453*ae771770SStanislav Sedov
454*ae771770SStanislav Sedov ret = (announce_config->db[i]->hdb_get_realms)(announce_context, announce_config->db[i], &realms);
455*ae771770SStanislav Sedov if (ret == 0) {
456*ae771770SStanislav Sedov for (r = realms; r && *r; r++)
457*ae771770SStanislav Sedov update_entries(store, *r, flags);
458*ae771770SStanislav Sedov krb5_free_host_realm(announce_context, realms);
459*ae771770SStanislav Sedov }
460*ae771770SStanislav Sedov }
461*ae771770SStanislav Sedov
462*ae771770SStanislav Sedov update_dns();
463*ae771770SStanislav Sedov
464*ae771770SStanislav Sedov CFRelease(host);
465*ae771770SStanislav Sedov }
466*ae771770SStanislav Sedov
467*ae771770SStanislav Sedov static void
delete_all(void)468*ae771770SStanislav Sedov delete_all(void)
469*ae771770SStanislav Sedov {
470*ae771770SStanislav Sedov struct entry *e;
471*ae771770SStanislav Sedov
472*ae771770SStanislav Sedov for (e = g_entries; e != NULL; e = e->next)
473*ae771770SStanislav Sedov e->flags &= ~(F_EXISTS|F_PUSH);
474*ae771770SStanislav Sedov
475*ae771770SStanislav Sedov update_dns();
476*ae771770SStanislav Sedov if (g_entries != NULL)
477*ae771770SStanislav Sedov errx(1, "Failed to remove all bonjour entries");
478*ae771770SStanislav Sedov }
479*ae771770SStanislav Sedov
480*ae771770SStanislav Sedov static void
destroy_dns_sd(void)481*ae771770SStanislav Sedov destroy_dns_sd(void)
482*ae771770SStanislav Sedov {
483*ae771770SStanislav Sedov if (g_dnsRef == NULL)
484*ae771770SStanislav Sedov return;
485*ae771770SStanislav Sedov
486*ae771770SStanislav Sedov delete_all();
487*ae771770SStanislav Sedov #ifdef REGISTER_SRV_RR
488*ae771770SStanislav Sedov unregister_srv_realms();
489*ae771770SStanislav Sedov #endif
490*ae771770SStanislav Sedov
491*ae771770SStanislav Sedov DNSServiceRefDeallocate(g_dnsRef);
492*ae771770SStanislav Sedov g_dnsRef = NULL;
493*ae771770SStanislav Sedov }
494*ae771770SStanislav Sedov
495*ae771770SStanislav Sedov
496*ae771770SStanislav Sedov static SCDynamicStoreRef
register_notification(void)497*ae771770SStanislav Sedov register_notification(void)
498*ae771770SStanislav Sedov {
499*ae771770SStanislav Sedov SCDynamicStoreRef store;
500*ae771770SStanislav Sedov CFStringRef computerNameKey;
501*ae771770SStanislav Sedov CFMutableArrayRef keys;
502*ae771770SStanislav Sedov
503*ae771770SStanislav Sedov computerNameKey = SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault);
504*ae771770SStanislav Sedov
505*ae771770SStanislav Sedov store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("Network watcher"),
506*ae771770SStanislav Sedov update_all, NULL);
507*ae771770SStanislav Sedov if (store == NULL)
508*ae771770SStanislav Sedov errx(1, "SCDynamicStoreCreate");
509*ae771770SStanislav Sedov
510*ae771770SStanislav Sedov keys = CFArrayCreateMutable(kCFAllocatorDefault, 2, &kCFTypeArrayCallBacks);
511*ae771770SStanislav Sedov if (keys == NULL)
512*ae771770SStanislav Sedov errx(1, "CFArrayCreateMutable");
513*ae771770SStanislav Sedov
514*ae771770SStanislav Sedov CFArrayAppendValue(keys, computerNameKey);
515*ae771770SStanislav Sedov CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
516*ae771770SStanislav Sedov
517*ae771770SStanislav Sedov if (SCDynamicStoreSetNotificationKeys(store, keys, NULL) == false)
518*ae771770SStanislav Sedov errx(1, "SCDynamicStoreSetNotificationKeys");
519*ae771770SStanislav Sedov
520*ae771770SStanislav Sedov CFRelease(computerNameKey);
521*ae771770SStanislav Sedov CFRelease(keys);
522*ae771770SStanislav Sedov
523*ae771770SStanislav Sedov if (!SCDynamicStoreSetDispatchQueue(store, g_queue))
524*ae771770SStanislav Sedov errx(1, "SCDynamicStoreSetDispatchQueue");
525*ae771770SStanislav Sedov
526*ae771770SStanislav Sedov return store;
527*ae771770SStanislav Sedov }
528*ae771770SStanislav Sedov #endif
529*ae771770SStanislav Sedov
530*ae771770SStanislav Sedov void
bonjour_announce(krb5_context context,krb5_kdc_configuration * config)531*ae771770SStanislav Sedov bonjour_announce(krb5_context context, krb5_kdc_configuration *config)
532*ae771770SStanislav Sedov {
533*ae771770SStanislav Sedov #if defined(__APPLE__) && defined(HAVE_GCD)
534*ae771770SStanislav Sedov g_queue = dispatch_queue_create("com.apple.kdc_announce", NULL);
535*ae771770SStanislav Sedov if (!g_queue)
536*ae771770SStanislav Sedov errx(1, "dispatch_queue_create");
537*ae771770SStanislav Sedov
538*ae771770SStanislav Sedov g_store = register_notification();
539*ae771770SStanislav Sedov announce_config = config;
540*ae771770SStanislav Sedov announce_context = context;
541*ae771770SStanislav Sedov
542*ae771770SStanislav Sedov create_dns_sd();
543*ae771770SStanislav Sedov #endif
544*ae771770SStanislav Sedov }
545