xref: /minix3/crypto/external/bsd/heimdal/dist/kdc/announce.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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