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