2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
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.
32 * June 1, 2001 Allan Nathanson <ajn@apple.com>
33 * - public API conversion
35 * January 1, 2001 Allan Nathanson <ajn@apple.com>
42 #include <sys/param.h>
43 #include <sys/types.h>
48 #include <SystemConfiguration/SystemConfiguration.h>
49 #include <SystemConfiguration/SCPrivate.h>
52 #include <Security/AuthSession.h>
53 #endif /* !TARGET_OS_IPHONE */
56 static Boolean apply
= TRUE
;
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, '?' },
69 usage(const char *command
)
71 SCPrint(TRUE
, stderr
, CFSTR("usage: %s [-n] new-set-name\n"), command
);
79 gid_t groups
[NGROUPS_MAX
];
83 return TRUE
; // if "root"
86 ngroups
= getgroups(NGROUPS_MAX
, groups
);
88 struct group
*adminGroup
;
90 adminGroup
= getgrnam("admin");
91 if (adminGroup
!= NULL
) {
92 gid_t adminGid
= adminGroup
->gr_gid
;
95 for (i
= 0; i
< ngroups
; i
++) {
96 if (groups
[i
] == adminGid
) {
97 return TRUE
; // if a member of group "admin"
107 #if !TARGET_OS_IPHONE
109 __loadSecurity(void) {
110 static void *image
= NULL
;
112 const char *framework
= "/System/Library/Frameworks/Security.framework/Versions/A/Security";
114 const char *suffix
= getenv("DYLD_IMAGE_SUFFIX");
115 char path
[MAXPATHLEN
];
117 strlcpy(path
, framework
, sizeof(path
));
118 if (suffix
) strlcat(path
, suffix
, sizeof(path
));
119 if (0 <= stat(path
, &statbuf
)) {
120 image
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
122 image
= dlopen(framework
, RTLD_LAZY
| RTLD_LOCAL
);
125 return (void *)image
;
130 _SessionGetInfo(SecuritySessionId session
, SecuritySessionId
*sessionId
, SessionAttributeBits
*attributes
)
132 #undef SessionGetInfo
133 static typeof (SessionGetInfo
) *dyfunc
= NULL
;
135 void *image
= __loadSecurity();
136 if (image
) dyfunc
= dlsym(image
, "SessionGetInfo");
138 return dyfunc
? dyfunc(session
, sessionId
, attributes
) : -1;
140 #define SessionGetInfo _SessionGetInfo
141 #endif /* !TARGET_OS_IPHONE */
144 hasLocalConsoleAccess()
146 #if !TARGET_OS_IPHONE
148 SecuritySessionId sessionID
= 0;
149 SessionAttributeBits attributeBits
= 0;
151 error
= SessionGetInfo(callerSecuritySession
, &sessionID
, &attributeBits
);
152 if (error
!= noErr
) {
153 /* Security check failed, must not permit access */
157 return (attributeBits
& (sessionHasGraphicAccess
|sessionIsRemote
)) == sessionHasGraphicAccess
;
158 #else /* !TARGET_OS_IPHONE */
160 #endif /* !TARGET_OS_IPHONE */
165 main(int argc
, char **argv
)
167 const char *command
= argv
[0];
170 CFStringRef current
= NULL
;
171 int currentMatched
= 0;
172 CFStringRef newSet
= NULL
; /* set key */
173 CFStringRef newSetUDN
= NULL
; /* user defined name */
175 SCPreferencesRef prefs
;
176 CFDictionaryRef sets
;
178 const void **setKeys
= NULL
;
179 const void **setVals
= NULL
;
182 /* process any arguments */
184 while ((opt
= getopt_long(argc
, argv
, "dvn", longopts
, NULL
)) != -1)
188 _sc_log
= FALSE
; /* enable framework logging */
203 prefix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("/%@/"), kSCPrefSets
);
206 ? CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingMacRoman
)
207 : CFRetain(CFSTR(""));
209 prefs
= SCPreferencesCreate(NULL
, CFSTR("Select Set Command"), NULL
);
211 SCPrint(TRUE
, stderr
, CFSTR("SCPreferencesCreate() failed\n"));
215 /* check if a full path to the new "set" was specified */
216 if ((CFStringGetLength(newSet
) > 0) && CFStringHasPrefix(newSet
, prefix
)) {
218 CFMutableStringRef str
;
220 str
= CFStringCreateMutableCopy(NULL
, 0, newSet
);
221 CFStringDelete(str
, CFRangeMake(0, CFStringGetLength(prefix
)));
223 range
= CFStringFind(str
, CFSTR("/"), 0);
224 if (range
.location
!= kCFNotFound
) {
225 SCPrint(TRUE
, stderr
, CFSTR("Set \"%@\" not available\n."), newSet
);
233 sets
= SCPreferencesGetValue(prefs
, kSCPrefSets
);
235 SCPrint(TRUE
, stderr
, CFSTR("No network sets defined.\n"));
239 current
= SCPreferencesGetValue(prefs
, kSCPrefCurrentSet
);
240 if (current
!= NULL
) {
241 if (CFStringHasPrefix(current
, prefix
)) {
242 CFMutableStringRef tmp
;
244 tmp
= CFStringCreateMutableCopy(NULL
, 0, current
);
245 CFStringDelete(tmp
, CFRangeMake(0, CFStringGetLength(prefix
)));
249 currentMatched
= -1; /* not prefixed */
252 current
= CFRetain(CFSTR(""));
253 currentMatched
= -2; /* not defined */
256 nSets
= CFDictionaryGetCount(sets
);
258 setKeys
= CFAllocatorAllocate(NULL
, nSets
* sizeof(CFStringRef
), 0);
259 setVals
= CFAllocatorAllocate(NULL
, nSets
* sizeof(CFDictionaryRef
), 0);
260 CFDictionaryGetKeysAndValues(sets
, setKeys
, setVals
);
263 /* check for set with matching name */
264 for (i
= 0; i
< nSets
; i
++) {
265 CFStringRef key
= (CFStringRef
) setKeys
[i
];
266 CFDictionaryRef dict
= (CFDictionaryRef
)setVals
[i
];
268 if ((currentMatched
>= 0) && CFEqual(key
, current
)) {
272 if (CFEqual(newSet
, key
)) {
273 newSetUDN
= CFDictionaryGetValue(dict
, kSCPropUserDefinedName
);
274 if (newSetUDN
!= NULL
) CFRetain(newSetUDN
);
279 /* check for set with matching user-defined name */
280 for (i
= 0; i
< nSets
; i
++) {
281 CFStringRef key
= (CFStringRef
) setKeys
[i
];
282 CFDictionaryRef dict
= (CFDictionaryRef
)setVals
[i
];
284 newSetUDN
= CFDictionaryGetValue(dict
, kSCPropUserDefinedName
);
285 if ((newSetUDN
!= NULL
) && CFEqual(newSet
, newSetUDN
)) {
287 newSet
= CFRetain(key
);
294 SCPrint(TRUE
, stderr
, CFSTR("Set \"%@\" not available.\n"), newSet
);
298 SCPrint(TRUE
, stdout
,
299 CFSTR("Defined sets include:%s\n"),
300 (currentMatched
> 0) ? " (* == current set)" : "");
302 for (i
= 0; i
< nSets
; i
++) {
303 CFStringRef key
= (CFStringRef
) setKeys
[i
];
304 CFDictionaryRef dict
= (CFDictionaryRef
)setVals
[i
];
305 CFStringRef udn
= CFDictionaryGetValue(dict
, kSCPropUserDefinedName
);
307 SCPrint(TRUE
, stdout
,
308 CFSTR(" %s %@\t(%@)\n"),
309 ((currentMatched
> 0) && CFEqual(key
, current
)) ? "*" : " ",
311 udn
? udn
: CFSTR(""));
314 switch (currentMatched
) {
316 SCPrint(TRUE
, stdout
, CFSTR("\nCurrent set not defined.\n"));
319 SCPrint(TRUE
, stdout
, CFSTR("\nCurrent set \"%@\" may not be valid\n"), current
);
322 SCPrint(TRUE
, stdout
, CFSTR("\nCurrent set \"%@\" not valid\n"), current
);
332 if (!(isAdmin() || hasLocalConsoleAccess())) {
333 SCPrint(TRUE
, stderr
,
334 CFSTR("Only local console users and administrators can change locations\n"));
339 current
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"), prefix
, newSet
);
341 if (!SCPreferencesSetValue(prefs
, kSCPrefCurrentSet
, current
)) {
342 SCPrint(TRUE
, stderr
,
343 CFSTR("SCPreferencesSetValue(...,%@,%@) failed\n"),
349 if (!SCPreferencesCommitChanges(prefs
)) {
350 SCPrint(TRUE
, stderr
, CFSTR("SCPreferencesCommitChanges() failed\n"));
355 if (!SCPreferencesApplyChanges(prefs
)) {
356 SCPrint(TRUE
, stderr
, CFSTR("SCPreferencesApplyChanges() failed\n"));
361 SCPrint(TRUE
, stdout
,
362 CFSTR("%@ updated to %@ (%@)\n"),
365 newSetUDN
? newSetUDN
: CFSTR(""));
369 if (newSetUDN
!= NULL
) CFRelease(newSetUDN
);