/*
- * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
- *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
/*
* Modification History
*
+ * January 15, 2004 Allan Nathanson <ajn@apple.com>
+ * - limit location changes to "root" (uid==0), users who are
+ * a member of group "admin", and processses which have access
+ * to a local graphics console.
+ *
* June 1, 2001 Allan Nathanson <ajn@apple.com>
* - public API conversion
*
#include <getopt.h>
#include <unistd.h>
#include <sysexits.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <grp.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
+#if !TARGET_OS_IPHONE
+#include <Security/AuthSession.h>
+#endif /* !TARGET_OS_IPHONE */
+
-Boolean apply = TRUE;
+static Boolean apply = TRUE;
-static struct option longopts[] = {
+static const struct option longopts[] = {
// { "debug", no_argument, 0, 'd' },
// { "verbose", no_argument, 0, 'v' },
// { "do-not-apply", no_argument, 0, 'n' },
};
-void
+static void
usage(const char *command)
{
SCPrint(TRUE, stderr, CFSTR("usage: %s [-n] new-set-name\n"), command);
}
+static Boolean
+isAdmin()
+{
+ gid_t groups[NGROUPS_MAX];
+ int ngroups;
+
+ if (getuid() == 0) {
+ return TRUE; // if "root"
+ }
+
+ ngroups = getgroups(NGROUPS_MAX, groups);
+ if(ngroups > 0) {
+ struct group *adminGroup;
+
+ adminGroup = getgrnam("admin");
+ if (adminGroup != NULL) {
+ gid_t adminGid = adminGroup->gr_gid;
+ int i;
+
+ for (i = 0; i < ngroups; i++) {
+ if (groups[i] == adminGid) {
+ return TRUE; // if a member of group "admin"
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+#if !TARGET_OS_IPHONE
+static void *
+__loadSecurity(void) {
+ static void *image = NULL;
+ if (NULL == image) {
+ const char *framework = "/System/Library/Frameworks/Security.framework/Versions/A/Security";
+ struct stat statbuf;
+ const char *suffix = getenv("DYLD_IMAGE_SUFFIX");
+ char path[MAXPATHLEN];
+
+ strlcpy(path, framework, sizeof(path));
+ if (suffix) strlcat(path, suffix, sizeof(path));
+ if (0 <= stat(path, &statbuf)) {
+ image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
+ } else {
+ image = dlopen(framework, RTLD_LAZY | RTLD_LOCAL);
+ }
+ }
+ return (void *)image;
+}
+
+
+static OSStatus
+_SessionGetInfo(SecuritySessionId session, SecuritySessionId *sessionId, SessionAttributeBits *attributes)
+{
+ #undef SessionGetInfo
+ static typeof (SessionGetInfo) *dyfunc = NULL;
+ if (!dyfunc) {
+ void *image = __loadSecurity();
+ if (image) dyfunc = dlsym(image, "SessionGetInfo");
+ }
+ return dyfunc ? dyfunc(session, sessionId, attributes) : -1;
+}
+#define SessionGetInfo _SessionGetInfo
+#endif /* !TARGET_OS_IPHONE */
+
+static Boolean
+hasLocalConsoleAccess()
+{
+#if !TARGET_OS_IPHONE
+ OSStatus error;
+ SecuritySessionId sessionID = 0;
+ SessionAttributeBits attributeBits = 0;
+
+ error = SessionGetInfo(callerSecuritySession, &sessionID, &attributeBits);
+ if (error != noErr) {
+ /* Security check failed, must not permit access */
+ return FALSE;
+ }
+
+ return (attributeBits & (sessionHasGraphicAccess|sessionIsRemote)) == sessionHasGraphicAccess;
+#else /* !TARGET_OS_IPHONE */
+ return TRUE;
+#endif /* !TARGET_OS_IPHONE */
+}
+
+
int
main(int argc, char **argv)
{
CFStringRef newSet = NULL; /* set key */
CFStringRef newSetUDN = NULL; /* user defined name */
CFStringRef prefix;
- SCPreferencesRef session;
+ SCPreferencesRef prefs;
CFDictionaryRef sets;
CFIndex nSets;
const void **setKeys = NULL;
newSet = (argc == 1)
? CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman)
- : CFSTR("");
+ : CFRetain(CFSTR(""));
- session = SCPreferencesCreate(NULL, CFSTR("Select Set Command"), NULL);
- if (!session) {
+ prefs = SCPreferencesCreate(NULL, CFSTR("Select Set Command"), NULL);
+ if (prefs == NULL) {
SCPrint(TRUE, stderr, CFSTR("SCPreferencesCreate() failed\n"));
exit (1);
}
newSet = str;
}
- sets = SCPreferencesGetValue(session, kSCPrefSets);
- if (!sets) {
- SCPrint(TRUE, stderr, CFSTR("SCPreferencesGetValue(...,%s,...) failed\n"));
+ sets = SCPreferencesGetValue(prefs, kSCPrefSets);
+ if (sets == NULL) {
+ SCPrint(TRUE, stderr, CFSTR("No network sets defined.\n"));
exit (1);
}
- current = SCPreferencesGetValue(session, kSCPrefCurrentSet);
- if (current) {
+ current = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
+ if (current != NULL) {
if (CFStringHasPrefix(current, prefix)) {
CFMutableStringRef tmp;
CFStringDelete(tmp, CFRangeMake(0, CFStringGetLength(prefix)));
current = tmp;
} else {
+ CFRetain(current);
currentMatched = -1; /* not prefixed */
}
} else {
- current = CFSTR("");
+ current = CFRetain(CFSTR(""));
currentMatched = -2; /* not defined */
}
if (CFEqual(newSet, key)) {
newSetUDN = CFDictionaryGetValue(dict, kSCPropUserDefinedName);
- if (newSetUDN) CFRetain(newSetUDN);
- current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet);
+ if (newSetUDN != NULL) CFRetain(newSetUDN);
goto found;
}
}
CFRelease(newSet);
newSet = CFRetain(key);
CFRetain(newSetUDN);
- current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet);
goto found;
}
}
found :
- if (!SCPreferencesSetValue(session, kSCPrefCurrentSet, current)) {
+ if (!(isAdmin() || hasLocalConsoleAccess())) {
+ SCPrint(TRUE, stderr,
+ CFSTR("Only local console users and administrators can change locations\n"));
+ exit (EX_NOPERM);
+ }
+
+ CFRelease(current);
+ current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet);
+
+ if (!SCPreferencesSetValue(prefs, kSCPrefCurrentSet, current)) {
SCPrint(TRUE, stderr,
CFSTR("SCPreferencesSetValue(...,%@,%@) failed\n"),
kSCPrefCurrentSet,
exit (1);
}
- if (!SCPreferencesCommitChanges(session)) {
+ if (!SCPreferencesCommitChanges(prefs)) {
SCPrint(TRUE, stderr, CFSTR("SCPreferencesCommitChanges() failed\n"));
exit (1);
}
if (apply) {
- if (!SCPreferencesApplyChanges(session)) {
+ if (!SCPreferencesApplyChanges(prefs)) {
SCPrint(TRUE, stderr, CFSTR("SCPreferencesApplyChanges() failed\n"));
exit (1);
}
}
- CFRelease(session);
-
SCPrint(TRUE, stdout,
CFSTR("%@ updated to %@ (%@)\n"),
kSCPrefCurrentSet,
newSet,
newSetUDN ? newSetUDN : CFSTR(""));
+ CFRelease(current);
+ CFRelease(newSet);
+ if (newSetUDN != NULL) CFRelease(newSetUDN);
+ CFRelease(prefix);
+ CFRelease(prefs);
+
exit (0);
return 0;
}