1/* 2 * Copyright (c) 2000-2009, 2011, 2012 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 56static Boolean apply = TRUE; 57 58 59static 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 68static void 69usage(const char *command) 70{ 71 SCPrint(TRUE, stderr, CFSTR("usage: %s [-n] new-set-name\n"), command); 72 exit (EX_USAGE); 73} 74 75 76int 77main(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 = FALSE; /* 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, newSet); 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 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 if (!SCPreferencesSetValue(prefs, kSCPrefCurrentSet, current)) { 286 SCPrint(TRUE, stderr, 287 CFSTR("SCPreferencesSetValue(...,%@,%@) failed: %s\n"), 288 kSCPrefCurrentSet, 289 current, 290 SCErrorString(SCError())); 291 exit (1); 292 } 293 294 if (!SCPreferencesCommitChanges(prefs)) { 295 int sc_status = SCError(); 296 297 if (sc_status == kSCStatusAccessError) { 298 SCPrint(TRUE, stderr, 299 CFSTR("Only local console users and administrators can change locations\n")); 300 exit (EX_NOPERM); 301 } else { 302 SCPrint(TRUE, stderr, 303 CFSTR("SCPreferencesCommitChanges() failed: %s\n"), 304 SCErrorString(sc_status)); 305 exit (1); 306 } 307 } 308 309 if (apply) { 310 if (!SCPreferencesApplyChanges(prefs)) { 311 SCPrint(TRUE, stderr, 312 CFSTR("SCPreferencesApplyChanges() failed %s\n"), 313 SCErrorString(SCError())); 314 exit (1); 315 } 316 } 317 318 SCPrint(TRUE, stdout, 319 CFSTR("%@ updated to %@ (%@)\n"), 320 kSCPrefCurrentSet, 321 newSet, 322 newSetUDN ? newSetUDN : CFSTR("")); 323 324 CFRelease(current); 325 CFRelease(newSet); 326 if (newSetUDN != NULL) CFRelease(newSetUDN); 327 CFRelease(prefix); 328 CFRelease(prefs); 329 330#if !TARGET_OS_IPHONE 331 AuthorizationFree(authorization, kAuthorizationFlagDefaults); 332// AuthorizationFree(authorization, kAuthorizationFlagDestroyRights); 333#endif /* !TARGET_OS_IPHONE */ 334 335 exit (0); 336 return 0; 337} 338