jdk/src/java.base/unix/native/libjava/java_props_macosx.c
changeset 28699 06e2c7a14944
parent 28698 f9e5640d832e
parent 28692 cf8fe951ca93
child 28703 4adaea63f465
equal deleted inserted replaced
28698:f9e5640d832e 28699:06e2c7a14944
     1 /*
       
     2  * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 #include <dlfcn.h>
       
    27 #include <sys/socket.h>
       
    28 #include <netinet/in.h>
       
    29 #include <arpa/inet.h>
       
    30 
       
    31 #include <Security/AuthSession.h>
       
    32 #include <CoreFoundation/CoreFoundation.h>
       
    33 #include <SystemConfiguration/SystemConfiguration.h>
       
    34 #include <Foundation/Foundation.h>
       
    35 
       
    36 #include "java_props_macosx.h"
       
    37 
       
    38 
       
    39 // need dlopen/dlsym trick to avoid pulling in JavaRuntimeSupport before libjava.dylib is loaded
       
    40 static void *getJRSFramework() {
       
    41     static void *jrsFwk = NULL;
       
    42     if (jrsFwk == NULL) {
       
    43        jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL);
       
    44     }
       
    45     return jrsFwk;
       
    46 }
       
    47 
       
    48 char *getPosixLocale(int cat) {
       
    49     char *lc = setlocale(cat, NULL);
       
    50     if ((lc == NULL) || (strcmp(lc, "C") == 0)) {
       
    51         lc = getenv("LANG");
       
    52     }
       
    53     if (lc == NULL) return NULL;
       
    54     return strdup(lc);
       
    55 }
       
    56 
       
    57 #define LOCALEIDLENGTH  128
       
    58 char *getMacOSXLocale(int cat) {
       
    59     switch (cat) {
       
    60     case LC_MESSAGES:
       
    61         {
       
    62             void *jrsFwk = getJRSFramework();
       
    63             if (jrsFwk == NULL) return NULL;
       
    64 
       
    65             char *(*JRSCopyPrimaryLanguage)() = dlsym(jrsFwk, "JRSCopyPrimaryLanguage");
       
    66             char *primaryLanguage = JRSCopyPrimaryLanguage ? JRSCopyPrimaryLanguage() : NULL;
       
    67             if (primaryLanguage == NULL) return NULL;
       
    68 
       
    69             char *(*JRSCopyCanonicalLanguageForPrimaryLanguage)(char *) = dlsym(jrsFwk, "JRSCopyCanonicalLanguageForPrimaryLanguage");
       
    70             char *canonicalLanguage = JRSCopyCanonicalLanguageForPrimaryLanguage ?  JRSCopyCanonicalLanguageForPrimaryLanguage(primaryLanguage) : NULL;
       
    71             free (primaryLanguage);
       
    72 
       
    73             return canonicalLanguage;
       
    74         }
       
    75         break;
       
    76     default:
       
    77         {
       
    78             char localeString[LOCALEIDLENGTH];
       
    79             if (CFStringGetCString(CFLocaleGetIdentifier(CFLocaleCopyCurrent()),
       
    80                                    localeString, LOCALEIDLENGTH, CFStringGetSystemEncoding())) {
       
    81                 return strdup(localeString);
       
    82             }
       
    83         }
       
    84         break;
       
    85     }
       
    86 
       
    87     return NULL;
       
    88 }
       
    89 
       
    90 char *setupMacOSXLocale(int cat) {
       
    91     char * ret = getMacOSXLocale(cat);
       
    92 
       
    93     if (cat == LC_MESSAGES && ret != NULL) {
       
    94         void *jrsFwk = getJRSFramework();
       
    95         if (jrsFwk != NULL) {
       
    96             void (*JRSSetDefaultLocalization)(char *) = dlsym(jrsFwk, "JRSSetDefaultLocalization");
       
    97             if (JRSSetDefaultLocalization) JRSSetDefaultLocalization(ret);
       
    98         }
       
    99     }
       
   100 
       
   101     if (ret == NULL) {
       
   102         return getPosixLocale(cat);
       
   103     } else {
       
   104         return ret;
       
   105     }
       
   106 }
       
   107 
       
   108 int isInAquaSession() {
       
   109     // environment variable to bypass the aqua session check
       
   110     char *ev = getenv("AWT_FORCE_HEADFUL");
       
   111     if (ev && (strncasecmp(ev, "true", 4) == 0)) {
       
   112         // if "true" then tell the caller we're in an Aqua session without actually checking
       
   113         return 1;
       
   114     }
       
   115     // Is the WindowServer available?
       
   116     SecuritySessionId session_id;
       
   117     SessionAttributeBits session_info;
       
   118     OSStatus status = SessionGetInfo(callerSecuritySession, &session_id, &session_info);
       
   119     if (status == noErr) {
       
   120         if (session_info & sessionHasGraphicAccess) {
       
   121             return 1;
       
   122         }
       
   123     }
       
   124     return 0;
       
   125 }
       
   126 
       
   127 void setOSNameAndVersion(java_props_t *sprops) {
       
   128     /* Don't rely on JRSCopyOSName because there's no guarantee the value will
       
   129      * remain the same, or even if the JRS functions will continue to be part of
       
   130      * Mac OS X.  So hardcode os_name, and fill in os_version if we can.
       
   131      */
       
   132     sprops->os_name = strdup("Mac OS X");
       
   133 
       
   134     void *jrsFwk = getJRSFramework();
       
   135     if (jrsFwk != NULL) {
       
   136         char *(*copyOSVersion)() = dlsym(jrsFwk, "JRSCopyOSVersion");
       
   137         if (copyOSVersion != NULL) {
       
   138             sprops->os_version = copyOSVersion();
       
   139             return;
       
   140         }
       
   141     }
       
   142     sprops->os_version = strdup("Unknown");
       
   143 }
       
   144 
       
   145 
       
   146 static Boolean getProxyInfoForProtocol(CFDictionaryRef inDict, CFStringRef inEnabledKey, CFStringRef inHostKey, CFStringRef inPortKey, CFStringRef *outProxyHost, int *ioProxyPort) {
       
   147     /* See if the proxy is enabled. */
       
   148     CFNumberRef cf_enabled = CFDictionaryGetValue(inDict, inEnabledKey);
       
   149     if (cf_enabled == NULL) {
       
   150         return false;
       
   151     }
       
   152 
       
   153     int isEnabled = false;
       
   154     if (!CFNumberGetValue(cf_enabled, kCFNumberIntType, &isEnabled)) {
       
   155         return isEnabled;
       
   156     }
       
   157 
       
   158     if (!isEnabled) return false;
       
   159     *outProxyHost = CFDictionaryGetValue(inDict, inHostKey);
       
   160 
       
   161     // If cf_host is null, that means the checkbox is set,
       
   162     //   but no host was entered. We'll treat that as NOT ENABLED.
       
   163     // If cf_port is null or cf_port isn't a number, that means
       
   164     //   no port number was entered. Treat this as ENABLED with the
       
   165     //   protocol's default port.
       
   166     if (*outProxyHost == NULL) {
       
   167         return false;
       
   168     }
       
   169 
       
   170     if (CFStringGetLength(*outProxyHost) == 0) {
       
   171         return false;
       
   172     }
       
   173 
       
   174     int newPort = 0;
       
   175     CFNumberRef cf_port = NULL;
       
   176     if ((cf_port = CFDictionaryGetValue(inDict, inPortKey)) != NULL &&
       
   177         CFNumberGetValue(cf_port, kCFNumberIntType, &newPort) &&
       
   178         newPort > 0) {
       
   179         *ioProxyPort = newPort;
       
   180     } else {
       
   181         // bad port or no port - leave *ioProxyPort unchanged
       
   182     }
       
   183 
       
   184     return true;
       
   185 }
       
   186 
       
   187 static char *createUTF8CString(const CFStringRef theString) {
       
   188     if (theString == NULL) return NULL;
       
   189 
       
   190     const CFIndex stringLength = CFStringGetLength(theString);
       
   191     const CFIndex bufSize = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 1;
       
   192     char *returnVal = (char *)malloc(bufSize);
       
   193 
       
   194     if (CFStringGetCString(theString, returnVal, bufSize, kCFStringEncodingUTF8)) {
       
   195         return returnVal;
       
   196     }
       
   197 
       
   198     free(returnVal);
       
   199     return NULL;
       
   200 }
       
   201 
       
   202 // Return TRUE if str is a syntactically valid IP address.
       
   203 // Using inet_pton() instead of inet_aton() for IPv6 support.
       
   204 // len is only a hint; cstr must still be nul-terminated
       
   205 static int looksLikeIPAddress(char *cstr, size_t len) {
       
   206     if (len == 0  ||  (len == 1 && cstr[0] == '.')) return FALSE;
       
   207 
       
   208     char dst[16]; // big enough for INET6
       
   209     return (1 == inet_pton(AF_INET, cstr, dst)  ||
       
   210             1 == inet_pton(AF_INET6, cstr, dst));
       
   211 }
       
   212 
       
   213 
       
   214 
       
   215 // Convert Mac OS X proxy exception entry to Java syntax.
       
   216 // See Radar #3441134 for details.
       
   217 // Returns NULL if this exception should be ignored by Java.
       
   218 // May generate a string with multiple exceptions separated by '|'.
       
   219 static char * createConvertedException(CFStringRef cf_original) {
       
   220     // This is done with char* instead of CFString because inet_pton()
       
   221     // needs a C string.
       
   222     char *c_exception = createUTF8CString(cf_original);
       
   223     if (!c_exception) return NULL;
       
   224 
       
   225     int c_len = strlen(c_exception);
       
   226 
       
   227     // 1. sanitize exception prefix
       
   228     if (c_len >= 1  &&  0 == strncmp(c_exception, ".", 1)) {
       
   229         memmove(c_exception, c_exception+1, c_len);
       
   230         c_len -= 1;
       
   231     } else if (c_len >= 2  &&  0 == strncmp(c_exception, "*.", 2)) {
       
   232         memmove(c_exception, c_exception+2, c_len-1);
       
   233         c_len -= 2;
       
   234     }
       
   235 
       
   236     // 2. pre-reject other exception wildcards
       
   237     if (strchr(c_exception, '*')) {
       
   238         free(c_exception);
       
   239         return NULL;
       
   240     }
       
   241 
       
   242     // 3. no IP wildcarding
       
   243     if (looksLikeIPAddress(c_exception, c_len)) {
       
   244         return c_exception;
       
   245     }
       
   246 
       
   247     // 4. allow domain suffixes
       
   248     // c_exception is now "str\0" - change to "str|*.str\0"
       
   249     c_exception = reallocf(c_exception, c_len+3+c_len+1);
       
   250     if (!c_exception) return NULL;
       
   251 
       
   252     strncpy(c_exception+c_len, "|*.", 3);
       
   253     strncpy(c_exception+c_len+3, c_exception, c_len);
       
   254     c_exception[c_len+3+c_len] = '\0';
       
   255     return c_exception;
       
   256 }
       
   257 
       
   258 /*
       
   259  * Method for fetching the user.home path and storing it in the property list.
       
   260  * For signed .apps running in the Mac App Sandbox, user.home is set to the
       
   261  * app's sandbox container.
       
   262  */
       
   263 void setUserHome(java_props_t *sprops) {
       
   264     if (sprops == NULL) { return; }
       
   265     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
       
   266     sprops->user_home = createUTF8CString((CFStringRef)NSHomeDirectory());
       
   267     [pool drain];
       
   268 }
       
   269 
       
   270 /*
       
   271  * Method for fetching proxy info and storing it in the property list.
       
   272  */
       
   273 void setProxyProperties(java_props_t *sProps) {
       
   274     if (sProps == NULL) return;
       
   275 
       
   276     char buf[16];    /* Used for %d of an int - 16 is plenty */
       
   277     CFStringRef
       
   278     cf_httpHost = NULL,
       
   279     cf_httpsHost = NULL,
       
   280     cf_ftpHost = NULL,
       
   281     cf_socksHost = NULL,
       
   282     cf_gopherHost = NULL;
       
   283     int
       
   284     httpPort = 80, // Default proxy port values
       
   285     httpsPort = 443,
       
   286     ftpPort = 21,
       
   287     socksPort = 1080,
       
   288     gopherPort = 70;
       
   289 
       
   290     CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
       
   291     if (dict == NULL) return;
       
   292 
       
   293     /* Read the proxy exceptions list */
       
   294     CFArrayRef cf_list = CFDictionaryGetValue(dict, kSCPropNetProxiesExceptionsList);
       
   295 
       
   296     CFMutableStringRef cf_exceptionList = NULL;
       
   297     if (cf_list != NULL) {
       
   298         CFIndex len = CFArrayGetCount(cf_list), idx;
       
   299 
       
   300         cf_exceptionList = CFStringCreateMutable(NULL, 0);
       
   301         for (idx = (CFIndex)0; idx < len; idx++) {
       
   302             CFStringRef cf_ehost;
       
   303             if ((cf_ehost = CFArrayGetValueAtIndex(cf_list, idx))) {
       
   304                 /* Convert this exception from Mac OS X syntax to Java syntax.
       
   305                  See Radar #3441134 for details. This may generate a string
       
   306                  with multiple Java exceptions separated by '|'. */
       
   307                 char *c_exception = createConvertedException(cf_ehost);
       
   308                 if (c_exception) {
       
   309                     /* Append the host to the list of exclusions. */
       
   310                     if (CFStringGetLength(cf_exceptionList) > 0) {
       
   311                         CFStringAppendCString(cf_exceptionList, "|", kCFStringEncodingMacRoman);
       
   312                     }
       
   313                     CFStringAppendCString(cf_exceptionList, c_exception, kCFStringEncodingMacRoman);
       
   314                     free(c_exception);
       
   315                 }
       
   316             }
       
   317         }
       
   318     }
       
   319 
       
   320     if (cf_exceptionList != NULL) {
       
   321         if (CFStringGetLength(cf_exceptionList) > 0) {
       
   322             sProps->exceptionList = createUTF8CString(cf_exceptionList);
       
   323         }
       
   324         CFRelease(cf_exceptionList);
       
   325     }
       
   326 
       
   327 #define CHECK_PROXY(protocol, PROTOCOL)                                     \
       
   328     sProps->protocol##ProxyEnabled =                                        \
       
   329     getProxyInfoForProtocol(dict, kSCPropNetProxies##PROTOCOL##Enable,      \
       
   330     kSCPropNetProxies##PROTOCOL##Proxy,         \
       
   331     kSCPropNetProxies##PROTOCOL##Port,          \
       
   332     &cf_##protocol##Host, &protocol##Port);     \
       
   333     if (sProps->protocol##ProxyEnabled) {                                   \
       
   334         sProps->protocol##Host = createUTF8CString(cf_##protocol##Host);    \
       
   335         snprintf(buf, sizeof(buf), "%d", protocol##Port);                   \
       
   336         sProps->protocol##Port = malloc(strlen(buf) + 1);                   \
       
   337         strcpy(sProps->protocol##Port, buf);                                \
       
   338     }
       
   339 
       
   340     CHECK_PROXY(http, HTTP);
       
   341     CHECK_PROXY(https, HTTPS);
       
   342     CHECK_PROXY(ftp, FTP);
       
   343     CHECK_PROXY(socks, SOCKS);
       
   344     CHECK_PROXY(gopher, Gopher);
       
   345 
       
   346 #undef CHECK_PROXY
       
   347 
       
   348     CFRelease(dict);
       
   349 }