2 * Copyright (c) 2000-2006 Apple Computer, 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>
51 #include <Security/Security.h>
52 #include <Security/AuthSession.h>
55 static Boolean apply
= TRUE
;
58 static const struct option longopts
[] = {
59 // { "debug", no_argument, 0, 'd' },
60 // { "verbose", no_argument, 0, 'v' },
61 // { "do-not-apply", no_argument, 0, 'n' },
62 { "help", no_argument
, 0, '?' },
68 usage(const char *command
)
70 SCPrint(TRUE
, stderr
, CFSTR("usage: %s [-n] new-set-name\n"), command
);
78 gid_t groups
[NGROUPS_MAX
];
82 return TRUE
; // if "root"
85 ngroups
= getgroups(NGROUPS_MAX
, groups
);
87 struct group
*adminGroup
;
89 adminGroup
= getgrnam("admin");
90 if (adminGroup
!= NULL
) {
91 gid_t adminGid
= adminGroup
->gr_gid
;
94 for (i
= 0; i
< ngroups
; i
++) {
95 if (groups
[i
] == adminGid
) {
96 return TRUE
; // if a member of group "admin"
107 __loadSecurity(void) {
108 static void *image
= NULL
;
110 const char *framework
= "/System/Library/Frameworks/Security.framework/Versions/A/Security";
112 const char *suffix
= getenv("DYLD_IMAGE_SUFFIX");
113 char path
[MAXPATHLEN
];
115 strlcpy(path
, framework
, sizeof(path
));
116 if (suffix
) strlcat(path
, suffix
, sizeof(path
));
117 if (0 <= stat(path
, &statbuf
)) {
118 image
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
120 image
= dlopen(framework
, RTLD_LAZY
| RTLD_LOCAL
);
123 return (void *)image
;
128 _SessionGetInfo(SecuritySessionId session
, SecuritySessionId
*sessionId
, SessionAttributeBits
*attributes
)
130 #undef SessionGetInfo
131 static typeof (SessionGetInfo
) *dyfunc
= NULL
;
133 void *image
= __loadSecurity();
134 if (image
) dyfunc
= dlsym(image
, "SessionGetInfo");
136 return dyfunc
? dyfunc(session
, sessionId
, attributes
) : -1;
138 #define SessionGetInfo _SessionGetInfo
142 hasLocalConsoleAccess()
145 SecuritySessionId sessionID
= 0;
146 SessionAttributeBits attributeBits
= 0;
148 error
= SessionGetInfo(callerSecuritySession
, &sessionID
, &attributeBits
);
149 if (error
!= noErr
) {
150 /* Security check failed, must not permit access */
154 return (attributeBits
& (sessionHasGraphicAccess
|sessionIsRemote
)) == sessionHasGraphicAccess
;
159 main(int argc
, char **argv
)
161 const char *command
= argv
[0];
164 CFStringRef current
= NULL
;
165 int currentMatched
= 0;
166 CFStringRef newSet
= NULL
; /* set key */
167 CFStringRef newSetUDN
= NULL
; /* user defined name */
169 SCPreferencesRef prefs
;
170 CFDictionaryRef sets
;
172 const void **setKeys
= NULL
;
173 const void **setVals
= NULL
;
176 /* process any arguments */
178 while ((opt
= getopt_long(argc
, argv
, "dvn", longopts
, NULL
)) != -1)
182 _sc_log
= FALSE
; /* enable framework logging */
197 prefix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("/%@/"), kSCPrefSets
);
200 ? CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingMacRoman
)
203 prefs
= SCPreferencesCreate(NULL
, CFSTR("Select Set Command"), NULL
);
205 SCPrint(TRUE
, stderr
, CFSTR("SCPreferencesCreate() failed\n"));
209 /* check if a full path to the new "set" was specified */
210 if ((CFStringGetLength(newSet
) > 0) && CFStringHasPrefix(newSet
, prefix
)) {
212 CFMutableStringRef str
;
214 str
= CFStringCreateMutableCopy(NULL
, 0, newSet
);
215 CFStringDelete(str
, CFRangeMake(0, CFStringGetLength(prefix
)));
217 range
= CFStringFind(str
, CFSTR("/"), 0);
218 if (range
.location
!= kCFNotFound
) {
219 SCPrint(TRUE
, stderr
, CFSTR("Set \"%@\" not available\n."), newSet
);
227 sets
= SCPreferencesGetValue(prefs
, kSCPrefSets
);
229 SCPrint(TRUE
, stderr
, CFSTR("No network sets defined.\n"));
233 current
= SCPreferencesGetValue(prefs
, kSCPrefCurrentSet
);
234 if (current
!= NULL
) {
235 if (CFStringHasPrefix(current
, prefix
)) {
236 CFMutableStringRef tmp
;
238 tmp
= CFStringCreateMutableCopy(NULL
, 0, current
);
239 CFStringDelete(tmp
, CFRangeMake(0, CFStringGetLength(prefix
)));
242 currentMatched
= -1; /* not prefixed */
246 currentMatched
= -2; /* not defined */
249 nSets
= CFDictionaryGetCount(sets
);
251 setKeys
= CFAllocatorAllocate(NULL
, nSets
* sizeof(CFStringRef
), 0);
252 setVals
= CFAllocatorAllocate(NULL
, nSets
* sizeof(CFDictionaryRef
), 0);
253 CFDictionaryGetKeysAndValues(sets
, setKeys
, setVals
);
256 /* check for set with matching name */
257 for (i
= 0; i
< nSets
; i
++) {
258 CFStringRef key
= (CFStringRef
) setKeys
[i
];
259 CFDictionaryRef dict
= (CFDictionaryRef
)setVals
[i
];
261 if ((currentMatched
>= 0) && CFEqual(key
, current
)) {
265 if (CFEqual(newSet
, key
)) {
266 newSetUDN
= CFDictionaryGetValue(dict
, kSCPropUserDefinedName
);
267 if (newSetUDN
!= NULL
) CFRetain(newSetUDN
);
268 current
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"), prefix
, newSet
);
273 /* check for set with matching user-defined name */
274 for (i
= 0; i
< nSets
; i
++) {
275 CFStringRef key
= (CFStringRef
) setKeys
[i
];
276 CFDictionaryRef dict
= (CFDictionaryRef
)setVals
[i
];
278 newSetUDN
= CFDictionaryGetValue(dict
, kSCPropUserDefinedName
);
279 if ((newSetUDN
!= NULL
) && CFEqual(newSet
, newSetUDN
)) {
281 newSet
= CFRetain(key
);
283 current
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"), prefix
, newSet
);
289 SCPrint(TRUE
, stderr
, CFSTR("Set \"%@\" not available.\n\n"), newSet
);
292 SCPrint(TRUE
, stderr
,
293 CFSTR("Defined sets include:%s\n"),
294 (currentMatched
> 0) ? " (* == current set)" : "");
296 for (i
= 0; i
< nSets
; i
++) {
297 CFStringRef key
= (CFStringRef
) setKeys
[i
];
298 CFDictionaryRef dict
= (CFDictionaryRef
)setVals
[i
];
299 CFStringRef udn
= CFDictionaryGetValue(dict
, kSCPropUserDefinedName
);
301 SCPrint(TRUE
, stderr
,
302 CFSTR(" %s %@\t(%@)\n"),
303 ((currentMatched
> 0) && CFEqual(key
, current
)) ? "*" : " ",
305 udn
? udn
: CFSTR(""));
308 switch (currentMatched
) {
310 SCPrint(TRUE
, stderr
, CFSTR("\nCurrentSet not defined.\n"));
313 SCPrint(TRUE
, stderr
, CFSTR("\nCurrentSet \"%@\" may not be valid\n"), current
);
316 SCPrint(TRUE
, stderr
, CFSTR("\nCurrentSet \"%@\" not valid\n"), current
);
326 if (!(isAdmin() || hasLocalConsoleAccess())) {
327 SCPrint(TRUE
, stderr
,
328 CFSTR("Only local console users and administrators can change locations\n"));
332 if (!SCPreferencesSetValue(prefs
, kSCPrefCurrentSet
, current
)) {
333 SCPrint(TRUE
, stderr
,
334 CFSTR("SCPreferencesSetValue(...,%@,%@) failed\n"),
340 if (!SCPreferencesCommitChanges(prefs
)) {
341 SCPrint(TRUE
, stderr
, CFSTR("SCPreferencesCommitChanges() failed\n"));
346 if (!SCPreferencesApplyChanges(prefs
)) {
347 SCPrint(TRUE
, stderr
, CFSTR("SCPreferencesApplyChanges() failed\n"));
354 SCPrint(TRUE
, stdout
,
355 CFSTR("%@ updated to %@ (%@)\n"),
358 newSetUDN
? newSetUDN
: CFSTR(""));