]> git.saurik.com Git - apple/configd.git/blob - scselect.tproj/scselect.c
configd-1109.60.2.tar.gz
[apple/configd.git] / scselect.tproj / scselect.c
1 /*
2 * Copyright (c) 2000-2009, 2011, 2012, 2014, 2015, 2018, 2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * January 15, 2004 Allan Nathanson <ajn@apple.com>
28 * - limit location changes to "root" (uid==0), users who are
29 * a member of group "admin", and processses which have access
30 * to a local graphics console.
31 *
32 * June 1, 2001 Allan Nathanson <ajn@apple.com>
33 * - public API conversion
34 *
35 * January 1, 2001 Allan Nathanson <ajn@apple.com>
36 * - initial revision
37 */
38
39 #include <getopt.h>
40 #include <unistd.h>
41 #include <sysexits.h>
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <dlfcn.h>
46 #include <grp.h>
47
48 #include <SystemConfiguration/SystemConfiguration.h>
49 #include <SystemConfiguration/SCPrivate.h>
50
51 #if !TARGET_OS_IPHONE
52 #include <Security/Authorization.h>
53 #endif /* !TARGET_OS_IPHONE */
54
55
56 static Boolean apply = TRUE;
57
58
59 static const struct option longopts[] = {
60 // { "debug", no_argument, 0, 'd' },
61 // { "verbose", no_argument, 0, 'v' },
62 // { "do-not-apply", no_argument, 0, 'n' },
63 { "help", no_argument, 0, '?' },
64 { 0, 0, 0, 0 }
65 };
66
67
68 static void
69 usage(const char *command)
70 {
71 SCPrint(TRUE, stderr, CFSTR("usage: %s [-n] new-set-name\n"), command);
72 exit (EX_USAGE);
73 }
74
75
76 int
77 main(int argc, char **argv)
78 {
79 const char *command = argv[0];
80 extern int optind;
81 int opt;
82 CFStringRef current = NULL;
83 int currentMatched = 0;
84 CFStringRef newSet = NULL; /* set key */
85 CFStringRef newSetUDN = NULL; /* user defined name */
86 CFStringRef prefix;
87 SCPreferencesRef prefs;
88 CFDictionaryRef sets;
89 CFIndex nSets;
90 const void **setKeys = NULL;
91 const void **setVals = NULL;
92 CFIndex i;
93
94 #if !TARGET_OS_IPHONE
95 AuthorizationRef authorization = NULL;
96 AuthorizationFlags flags = kAuthorizationFlagDefaults;
97 CFMutableDictionaryRef options;
98 OSStatus status;
99 #endif // !TARGET_OS_IPHONE
100
101 /* process any arguments */
102
103 while ((opt = getopt_long(argc, argv, "dvn", longopts, NULL)) != -1) {
104 switch(opt) {
105 case 'd':
106 _sc_debug = TRUE;
107 _sc_log = kSCLogDestinationFile; /* enable framework logging */
108 break;
109 case 'v':
110 _sc_verbose = TRUE;
111 break;
112 case 'n':
113 apply = FALSE;
114 break;
115 case '?':
116 default :
117 usage(command);
118 }
119 }
120 argc -= optind;
121 argv += optind;
122
123 prefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("/%@/"), kSCPrefSets);
124
125 if (argc == 1) {
126 newSet = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
127
128 /* check if a full path to the new "set" was specified */
129 if ((CFStringGetLength(newSet) > 0) && CFStringHasPrefix(newSet, prefix)) {
130 CFRange range;
131 CFMutableStringRef str;
132
133 str = CFStringCreateMutableCopy(NULL, 0, newSet);
134 CFRelease(newSet);
135
136 CFStringDelete(str, CFRangeMake(0, CFStringGetLength(prefix)));
137 newSet = CFStringCreateCopy(NULL, str);
138 CFRelease(str);
139
140 range = CFStringFind(newSet, CFSTR("/"), 0);
141 if (range.location != kCFNotFound) {
142 SCPrint(TRUE, stderr, CFSTR("Set \"%@\" not available\n"), newSet);
143 exit (1);
144 }
145 }
146 } else {
147 newSet = CFRetain(CFSTR(""));
148 }
149
150 #if !TARGET_OS_IPHONE
151 status = AuthorizationCreate(NULL,
152 kAuthorizationEmptyEnvironment,
153 flags,
154 &authorization);
155 if (status != errAuthorizationSuccess) {
156 SCPrint(TRUE,
157 stderr,
158 CFSTR("AuthorizationCreate() failed: status = %d\n"),
159 (int)status);
160 exit (1);
161 }
162
163 options = CFDictionaryCreateMutable(NULL,
164 0,
165 &kCFTypeDictionaryKeyCallBacks,
166 &kCFTypeDictionaryValueCallBacks);
167 CFDictionarySetValue(options, kSCPreferencesOptionChangeNetworkSet, kCFBooleanTrue);
168 prefs = SCPreferencesCreateWithOptions(NULL, CFSTR("scselect"), NULL, authorization, options);
169 CFRelease(options);
170 if (prefs == NULL) {
171 SCPrint(TRUE, stderr, CFSTR("SCPreferencesCreate() failed\n"));
172 exit (1);
173 }
174 #else // !TARGET_OS_IPHONE
175 prefs = SCPreferencesCreate(NULL, CFSTR("scselect"), NULL);
176 if (prefs == NULL) {
177 SCPrint(TRUE, stderr, CFSTR("SCPreferencesCreate() failed\n"));
178 exit (1);
179 }
180 #endif // !TARGET_OS_IPHONE
181
182 sets = SCPreferencesGetValue(prefs, kSCPrefSets);
183 if (sets == NULL) {
184 SCPrint(TRUE, stderr, CFSTR("No network sets defined.\n"));
185 exit (1);
186 }
187
188 current = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
189 if (current != NULL) {
190 if (CFStringHasPrefix(current, prefix)) {
191 CFMutableStringRef tmp;
192
193 tmp = CFStringCreateMutableCopy(NULL, 0, current);
194 CFStringDelete(tmp, CFRangeMake(0, CFStringGetLength(prefix)));
195 current = tmp;
196 } else {
197 CFRetain(current);
198 currentMatched = -1; /* not prefixed */
199 }
200 } else {
201 current = CFRetain(CFSTR(""));
202 currentMatched = -2; /* not defined */
203 }
204
205 nSets = CFDictionaryGetCount(sets);
206 if (nSets > 0) {
207 setKeys = CFAllocatorAllocate(NULL, nSets * sizeof(CFStringRef), 0);
208 setVals = CFAllocatorAllocate(NULL, nSets * sizeof(CFDictionaryRef), 0);
209 CFDictionaryGetKeysAndValues(sets, setKeys, setVals);
210 }
211
212 /* check for set with matching name */
213 for (i = 0; i < nSets; i++) {
214 CFStringRef key = (CFStringRef) setKeys[i];
215 CFDictionaryRef dict = (CFDictionaryRef)setVals[i];
216
217 if ((currentMatched >= 0) && CFEqual(key, current)) {
218 currentMatched++;
219 }
220
221 if (CFEqual(newSet, key)) {
222 newSetUDN = CFDictionaryGetValue(dict, kSCPropUserDefinedName);
223 if (newSetUDN != NULL) CFRetain(newSetUDN);
224 goto found;
225 }
226 }
227
228 /* check for set with matching user-defined name */
229 for (i = 0; i < nSets; i++) {
230 CFStringRef key = (CFStringRef) setKeys[i];
231 CFDictionaryRef dict = (CFDictionaryRef)setVals[i];
232
233 newSetUDN = CFDictionaryGetValue(dict, kSCPropUserDefinedName);
234 if ((newSetUDN != NULL) && CFEqual(newSet, newSetUDN)) {
235 CFRelease(newSet);
236 newSet = CFRetain(key);
237 CFRetain(newSetUDN);
238 goto found;
239 }
240 }
241
242 if (argc == 1) {
243 SCPrint(TRUE, stderr, CFSTR("Set \"%@\" not available.\n"), newSet);
244 exit(1);
245 }
246
247 SCPrint(TRUE, stdout,
248 CFSTR("Defined sets include:%s\n"),
249 (currentMatched > 0) ? " (* == current set)" : "");
250
251 for (i = 0; i < nSets; i++) {
252 CFStringRef key = (CFStringRef) setKeys[i];
253 CFDictionaryRef dict = (CFDictionaryRef)setVals[i];
254 CFStringRef udn = CFDictionaryGetValue(dict, kSCPropUserDefinedName);
255
256 SCPrint(TRUE, stdout,
257 CFSTR(" %s %@\t(%@)\n"),
258 ((currentMatched > 0) && CFEqual(key, current)) ? "*" : " ",
259 key,
260 udn ? udn : CFSTR(""));
261 }
262
263 switch (currentMatched) {
264 case -2 :
265 SCPrint(TRUE, stdout, CFSTR("\nCurrent set not defined.\n"));
266 break;
267 case -1 :
268 SCPrint(TRUE, stdout, CFSTR("\nCurrent set \"%@\" may not be valid\n"), current);
269 break;
270 case 0 :
271 SCPrint(TRUE, stdout, CFSTR("\nCurrent set \"%@\" not valid\n"), current);
272 break;
273 default :
274 break;
275 }
276
277 CFRelease(prefix);
278 exit (0);
279
280 found :
281
282 CFRelease(current);
283 current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet);
284
285 SCPreferencesSetValue(prefs, kSCPrefCurrentSet, current);
286
287 if (!SCPreferencesCommitChanges(prefs)) {
288 int sc_status = SCError();
289
290 if (sc_status == kSCStatusAccessError) {
291 SCPrint(TRUE, stderr,
292 CFSTR("Only local console users and administrators can change locations\n"));
293 exit (EX_NOPERM);
294 } else {
295 SCPrint(TRUE, stderr,
296 CFSTR("SCPreferencesCommitChanges() failed: %s\n"),
297 SCErrorString(sc_status));
298 exit (1);
299 }
300 }
301
302 if (apply) {
303 if (!SCPreferencesApplyChanges(prefs)) {
304 SCPrint(TRUE, stderr,
305 CFSTR("SCPreferencesApplyChanges() failed %s\n"),
306 SCErrorString(SCError()));
307 exit (1);
308 }
309 }
310
311 SCPrint(TRUE, stdout,
312 CFSTR("%@ updated to %@ (%@)\n"),
313 kSCPrefCurrentSet,
314 newSet,
315 newSetUDN ? newSetUDN : CFSTR(""));
316
317 CFRelease(current);
318 CFRelease(newSet);
319 if (newSetUDN != NULL) CFRelease(newSetUDN);
320 CFRelease(prefix);
321 CFRelease(prefs);
322
323 #if !TARGET_OS_IPHONE
324 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
325 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
326 #endif /* !TARGET_OS_IPHONE */
327
328 exit (0);
329 return 0;
330 }