]>
Commit | Line | Data |
---|---|---|
45dcf4df MW |
1 | /* |
2 | * Copyright (C) 2013 Martin Willi | |
3 | * Copyright (C) 2013 revosec AG | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the | |
7 | * Free Software Foundation; either version 2 of the License, or (at your | |
8 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | * for more details. | |
14 | */ | |
15 | ||
16 | #include "osx_attr_handler.h" | |
17 | ||
18 | #include <networking/host.h> | |
19 | #include <utils/debug.h> | |
20 | ||
21 | #include <SystemConfiguration/SCDynamicStore.h> | |
22 | ||
23 | typedef struct private_osx_attr_handler_t private_osx_attr_handler_t; | |
24 | ||
25 | /** | |
26 | * Private data of an osx_attr_handler_t object. | |
27 | */ | |
28 | struct private_osx_attr_handler_t { | |
29 | ||
30 | /** | |
31 | * Public interface | |
32 | */ | |
33 | osx_attr_handler_t public; | |
61d6cdb9 MW |
34 | |
35 | /** | |
36 | * Backup of original DNS servers, before we mess with it | |
37 | */ | |
38 | CFMutableArrayRef original; | |
39 | ||
40 | /** | |
41 | * Append DNS servers to existing entries, instead of replacing | |
42 | */ | |
43 | bool append; | |
45dcf4df MW |
44 | }; |
45 | ||
46 | /** | |
47 | * Create a path to the DNS configuration of the Primary IPv4 Service | |
48 | */ | |
49 | static CFStringRef create_dns_path(SCDynamicStoreRef store) | |
50 | { | |
51 | CFStringRef service, path = NULL; | |
52 | CFDictionaryRef dict; | |
53 | ||
54 | /* get primary service */ | |
55 | dict = SCDynamicStoreCopyValue(store, CFSTR("State:/Network/Global/IPv4")); | |
56 | if (dict) | |
57 | { | |
58 | service = CFDictionaryGetValue(dict, CFSTR("PrimaryService")); | |
59 | if (service) | |
60 | { | |
61 | path = CFStringCreateWithFormat(NULL, NULL, | |
62 | CFSTR("State:/Network/Service/%@/DNS"), service); | |
63 | } | |
64 | else | |
65 | { | |
66 | DBG1(DBG_CFG, "SystemConfiguration PrimaryService not known"); | |
67 | } | |
68 | CFRelease(dict); | |
69 | } | |
70 | else | |
71 | { | |
72 | DBG1(DBG_CFG, "getting global IPv4 SystemConfiguration failed"); | |
73 | } | |
74 | return path; | |
75 | } | |
76 | ||
77 | /** | |
78 | * Create a mutable dictionary from path, a new one if not found | |
79 | */ | |
80 | static CFMutableDictionaryRef get_dictionary(SCDynamicStoreRef store, | |
81 | CFStringRef path) | |
82 | { | |
83 | CFDictionaryRef dict; | |
84 | CFMutableDictionaryRef mut = NULL; | |
85 | ||
86 | dict = SCDynamicStoreCopyValue(store, path); | |
87 | if (dict) | |
88 | { | |
89 | if (CFGetTypeID(dict) == CFDictionaryGetTypeID()) | |
90 | { | |
91 | mut = CFDictionaryCreateMutableCopy(NULL, 0, dict); | |
92 | } | |
93 | CFRelease(dict); | |
94 | } | |
95 | if (!mut) | |
96 | { | |
97 | mut = CFDictionaryCreateMutable(NULL, 0, | |
98 | &kCFTypeDictionaryKeyCallBacks, | |
99 | &kCFTypeDictionaryValueCallBacks); | |
100 | } | |
101 | return mut; | |
102 | } | |
103 | ||
104 | /** | |
105 | * Create a mutable array from dictionary path, a new one if not found | |
106 | */ | |
107 | static CFMutableArrayRef get_array_from_dict(CFDictionaryRef dict, | |
108 | CFStringRef name) | |
109 | { | |
110 | CFArrayRef arr; | |
111 | ||
112 | arr = CFDictionaryGetValue(dict, name); | |
113 | if (arr && CFGetTypeID(arr) == CFArrayGetTypeID()) | |
114 | { | |
115 | return CFArrayCreateMutableCopy(NULL, 0, arr); | |
116 | } | |
117 | return CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
118 | } | |
119 | ||
120 | /** | |
121 | * Add/Remove a DNS server to the configuration | |
122 | */ | |
61d6cdb9 MW |
123 | static bool manage_dns(private_osx_attr_handler_t *this, |
124 | int family, chunk_t data, bool add) | |
45dcf4df MW |
125 | { |
126 | SCDynamicStoreRef store; | |
127 | CFStringRef path, dns; | |
128 | CFMutableArrayRef arr; | |
129 | CFMutableDictionaryRef dict; | |
130 | CFIndex i; | |
131 | host_t *server; | |
132 | char buf[64]; | |
133 | bool success = FALSE; | |
134 | ||
135 | server = host_create_from_chunk(family, data, 0); | |
136 | if (!server) | |
137 | { | |
138 | return FALSE; | |
139 | } | |
140 | snprintf(buf, sizeof(buf), "%H", server); | |
141 | server->destroy(server); | |
142 | ||
143 | store = SCDynamicStoreCreate(NULL, CFSTR("osx-attr"), NULL, NULL); | |
144 | path = create_dns_path(store); | |
145 | if (path) | |
146 | { | |
147 | dict = get_dictionary(store, path); | |
148 | arr = get_array_from_dict(dict, CFSTR("ServerAddresses")); | |
149 | dns = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8); | |
150 | if (add) | |
151 | { | |
61d6cdb9 | 152 | if (!this->append && !this->original) |
2db6d5b8 | 153 | { /* backup original config, start with empty set */ |
61d6cdb9 MW |
154 | this->original = arr; |
155 | arr = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
156 | } | |
45dcf4df MW |
157 | DBG1(DBG_CFG, "installing %s as DNS server", buf); |
158 | CFArrayInsertValueAtIndex(arr, 0, dns); | |
159 | } | |
160 | else | |
161 | { | |
162 | i = CFArrayGetFirstIndexOfValue(arr, | |
163 | CFRangeMake(0, CFArrayGetCount(arr)), dns); | |
164 | if (i >= 0) | |
165 | { | |
166 | DBG1(DBG_CFG, "removing %s from DNS servers (%d)", buf, i); | |
167 | CFArrayRemoveValueAtIndex(arr, i); | |
168 | } | |
61d6cdb9 MW |
169 | if (!this->append && this->original && CFArrayGetCount(arr) == 0) |
170 | { /* restore original config */ | |
171 | CFRelease(arr); | |
172 | arr = this->original; | |
173 | this->original = NULL; | |
174 | } | |
45dcf4df MW |
175 | } |
176 | CFRelease(dns); | |
177 | CFDictionarySetValue(dict, CFSTR("ServerAddresses"), arr); | |
178 | CFRelease(arr); | |
179 | ||
180 | success = SCDynamicStoreSetValue(store, path, dict); | |
181 | CFRelease(dict); | |
182 | CFRelease(path); | |
183 | } | |
184 | CFRelease(store); | |
185 | ||
186 | if (!success) | |
187 | { | |
188 | DBG1(DBG_CFG, "adding DNS server to SystemConfiguration failed"); | |
189 | } | |
190 | return success; | |
191 | } | |
192 | ||
193 | METHOD(attribute_handler_t, handle, bool, | |
b9be25ea | 194 | private_osx_attr_handler_t *this, ike_sa_t *ike_sa, |
45dcf4df MW |
195 | configuration_attribute_type_t type, chunk_t data) |
196 | { | |
197 | switch (type) | |
198 | { | |
199 | case INTERNAL_IP4_DNS: | |
61d6cdb9 | 200 | return manage_dns(this, AF_INET, data, TRUE); |
45dcf4df MW |
201 | default: |
202 | return FALSE; | |
203 | } | |
204 | } | |
205 | ||
206 | METHOD(attribute_handler_t, release, void, | |
b9be25ea | 207 | private_osx_attr_handler_t *this, ike_sa_t *ike_sa, |
45dcf4df MW |
208 | configuration_attribute_type_t type, chunk_t data) |
209 | { | |
210 | switch (type) | |
211 | { | |
212 | case INTERNAL_IP4_DNS: | |
61d6cdb9 | 213 | manage_dns(this, AF_INET, data, FALSE); |
45dcf4df MW |
214 | break; |
215 | default: | |
216 | break; | |
217 | } | |
218 | } | |
219 | ||
220 | METHOD(enumerator_t, enumerate_dns, bool, | |
95a63bf2 | 221 | enumerator_t *this, va_list args) |
45dcf4df | 222 | { |
95a63bf2 TB |
223 | configuration_attribute_type_t *type; |
224 | chunk_t *data; | |
225 | ||
226 | VA_ARGS_VGET(args, type, data); | |
45dcf4df MW |
227 | *type = INTERNAL_IP4_DNS; |
228 | *data = chunk_empty; | |
95a63bf2 | 229 | this->venumerate = (void*)return_false; |
45dcf4df MW |
230 | return TRUE; |
231 | } | |
232 | ||
233 | METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *, | |
b9be25ea | 234 | private_osx_attr_handler_t *this, ike_sa_t *ike_sa, |
45dcf4df MW |
235 | linked_list_t *vips) |
236 | { | |
237 | enumerator_t *enumerator; | |
238 | ||
239 | INIT(enumerator, | |
95a63bf2 TB |
240 | .enumerate = enumerator_enumerate_default, |
241 | .venumerate = _enumerate_dns, | |
45dcf4df MW |
242 | .destroy = (void*)free, |
243 | ); | |
244 | return enumerator; | |
245 | } | |
246 | ||
247 | METHOD(osx_attr_handler_t, destroy, void, | |
248 | private_osx_attr_handler_t *this) | |
249 | { | |
250 | free(this); | |
251 | } | |
252 | ||
253 | /** | |
254 | * See header | |
255 | */ | |
256 | osx_attr_handler_t *osx_attr_handler_create() | |
257 | { | |
258 | private_osx_attr_handler_t *this; | |
259 | ||
260 | INIT(this, | |
261 | .public = { | |
262 | .handler = { | |
263 | .handle = _handle, | |
264 | .release = _release, | |
265 | .create_attribute_enumerator = _create_attribute_enumerator, | |
266 | }, | |
267 | .destroy = _destroy, | |
268 | }, | |
61d6cdb9 MW |
269 | .append = lib->settings->get_bool(lib->settings, |
270 | "%s.plugins.osx-attr.append", TRUE, lib->ns), | |
45dcf4df MW |
271 | ); |
272 | ||
273 | return &this->public; | |
274 | } |