]> git.saurik.com Git - apple/configd.git/blobdiff - scselect.tproj/scselect.c
configd-289.2.tar.gz
[apple/configd.git] / scselect.tproj / scselect.c
index 2e29fe20ea9f3e0410390f7ac9c59d89be8bb5fe..5c42fb3780f65fd6608598e634f86e0a5c4b3e21 100644 (file)
@@ -1,10 +1,8 @@
 /*
- * 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' },
@@ -53,7 +65,7 @@ static struct option longopts[] = {
 };
 
 
-void
+static void
 usage(const char *command)
 {
        SCPrint(TRUE, stderr, CFSTR("usage: %s [-n] new-set-name\n"), command);
@@ -61,6 +73,94 @@ usage(const char *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)
 {
@@ -72,7 +172,7 @@ 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;
@@ -104,10 +204,10 @@ main(int argc, char **argv)
 
        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);
        }
@@ -130,14 +230,14 @@ main(int argc, char **argv)
                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;
 
@@ -145,10 +245,11 @@ main(int argc, char **argv)
                        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 */
        }
 
@@ -170,8 +271,7 @@ main(int argc, char **argv)
 
                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;
                }
        }
@@ -186,7 +286,6 @@ main(int argc, char **argv)
                        CFRelease(newSet);
                        newSet = CFRetain(key);
                        CFRetain(newSetUDN);
-                       current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet);
                        goto found;
                }
        }
@@ -229,7 +328,16 @@ main(int argc, char **argv)
 
     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,
@@ -237,26 +345,30 @@ main(int argc, char **argv)
                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;
 }