1 /*
   2  * Copyright (c) 2004, 2010, 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 <windows.h>
  27 #include "jni.h"
  28 #include "jni_util.h"
  29 #include "jvm.h"
  30 #include "jlong.h"
  31 #include "sun_net_spi_DefaultProxySelector.h"
  32 
  33 /**
  34  * These functions are used by the sun.net.spi.DefaultProxySelector class
  35  * to access some platform specific settings.
  36  * This is the Windows code using the registry settings.
  37  */
  38 
  39 static jclass proxy_class;
  40 static jclass isaddr_class;
  41 static jclass ptype_class;
  42 static jmethodID isaddr_createUnresolvedID;
  43 static jmethodID proxy_ctrID;
  44 static jfieldID pr_no_proxyID;
  45 static jfieldID ptype_httpID;
  46 static jfieldID ptype_socksID;
  47 
  48 /*
  49  * Class:     sun_net_spi_DefaultProxySelector
  50  * Method:    init
  51  * Signature: ()Z
  52  */
  53 JNIEXPORT jboolean JNICALL
  54 Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
  55   HKEY hKey;
  56   LONG ret;
  57   jclass cls;
  58 
  59   /**
  60    * Get all the method & field IDs for later use.
  61    */
  62   cls = (*env)->FindClass(env,"java/net/Proxy");
  63   CHECK_NULL_RETURN(cls, JNI_FALSE);
  64   proxy_class = (*env)->NewGlobalRef(env, cls);
  65   CHECK_NULL_RETURN(proxy_class, JNI_FALSE);
  66   cls = (*env)->FindClass(env,"java/net/Proxy$Type");
  67   CHECK_NULL_RETURN(cls, JNI_FALSE);
  68   ptype_class = (*env)->NewGlobalRef(env, cls);
  69   CHECK_NULL_RETURN(ptype_class, JNI_FALSE);
  70   cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
  71   CHECK_NULL_RETURN(cls, JNI_FALSE);
  72   isaddr_class = (*env)->NewGlobalRef(env, cls);
  73   CHECK_NULL_RETURN(isaddr_class, JNI_FALSE);
  74   proxy_ctrID = (*env)->GetMethodID(env, proxy_class, "<init>",
  75                                     "(Ljava/net/Proxy$Type;Ljava/net/SocketAddress;)V");
  76   CHECK_NULL_RETURN(proxy_ctrID, JNI_FALSE);
  77   pr_no_proxyID = (*env)->GetStaticFieldID(env, proxy_class, "NO_PROXY", "Ljava/net/Proxy;");
  78   CHECK_NULL_RETURN(pr_no_proxyID, JNI_FALSE);
  79   ptype_httpID = (*env)->GetStaticFieldID(env, ptype_class, "HTTP", "Ljava/net/Proxy$Type;");
  80   CHECK_NULL_RETURN(ptype_httpID, JNI_FALSE);
  81   ptype_socksID = (*env)->GetStaticFieldID(env, ptype_class, "SOCKS", "Ljava/net/Proxy$Type;");
  82   CHECK_NULL_RETURN(ptype_socksID, JNI_FALSE);
  83   isaddr_createUnresolvedID = (*env)->GetStaticMethodID(env, isaddr_class, "createUnresolved",
  84                                                         "(Ljava/lang/String;I)Ljava/net/InetSocketAddress;");
  85   CHECK_NULL_RETURN(isaddr_createUnresolvedID, JNI_FALSE);
  86 
  87   /**
  88    * Let's see if we can find the proper Registry entry.
  89    */
  90   ret = RegOpenKeyEx(HKEY_CURRENT_USER,
  91                      "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
  92                      0, KEY_READ, (PHKEY)&hKey);
  93   if (ret == ERROR_SUCCESS) {
  94     RegCloseKey(hKey);
  95     /**
  96      * It worked, we can probably rely on it then.
  97      */
  98     return JNI_TRUE;
  99   }
 100 
 101   return JNI_FALSE;
 102 }
 103 
 104 #define MAX_STR_LEN 1024
 105 
 106 /*
 107  * Class:     sun_net_spi_DefaultProxySelector
 108  * Method:    getSystemProxy
 109  * Signature: ([Ljava/lang/String;Ljava/lang/String;)Ljava/net/Proxy;
 110  */
 111 JNIEXPORT jobject JNICALL
 112 Java_sun_net_spi_DefaultProxySelector_getSystemProxy(JNIEnv *env,
 113                                                      jobject this,
 114                                                      jstring proto,
 115                                                      jstring host)
 116 {
 117   jobject isa = NULL;
 118   jobject proxy = NULL;
 119   jobject type_proxy = NULL;
 120   jobject no_proxy = NULL;
 121   jboolean isCopy;
 122   HKEY hKey;
 123   LONG ret;
 124   const char* cproto;
 125   const char* urlhost;
 126   char pproto[MAX_STR_LEN];
 127   char regserver[MAX_STR_LEN];
 128   char override[MAX_STR_LEN];
 129   char *s, *s2;
 130   char *ctx = NULL;
 131   int pport = 0;
 132   int defport = 0;
 133   char *phost;
 134 
 135   /**
 136    * Let's open the Registry entry. We'll check a few values in it:
 137    *
 138    * - ProxyEnable: 0 means no proxy, 1 means use the proxy
 139    * - ProxyServer: a string that can take 2 forms:
 140    *    "server[:port]"
 141    *    or
 142    *    "protocol1=server[:port][;protocol2=server[:port]]..."
 143    * - ProxyOverride: a string containing a list of prefixes for hostnames.
 144    *   e.g.: hoth;localhost;<local>
 145    */
 146   ret = RegOpenKeyEx(HKEY_CURRENT_USER,
 147                      "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
 148                      0, KEY_READ, (PHKEY)&hKey);
 149   if (ret == ERROR_SUCCESS) {
 150     DWORD dwLen;
 151     DWORD dwProxyEnabled;
 152     ULONG ulType;
 153     dwLen = sizeof(dwProxyEnabled);
 154 
 155     /**
 156      * Let's see if the proxy settings are to be used.
 157      */
 158     ret = RegQueryValueEx(hKey, "ProxyEnable",  NULL, &ulType,
 159                           (LPBYTE)&dwProxyEnabled, &dwLen);
 160     if ((ret == ERROR_SUCCESS) && (dwProxyEnabled > 0)) {
 161       /*
 162        * Yes, ProxyEnable == 1
 163        */
 164       dwLen = sizeof(override);
 165       override[0] = 0;
 166       ret = RegQueryValueEx(hKey, "ProxyOverride", NULL, &ulType,
 167                             (LPBYTE)&override, &dwLen);
 168       dwLen = sizeof(regserver);
 169       regserver[0] = 0;
 170       ret = RegQueryValueEx(hKey, "ProxyServer",  NULL, &ulType,
 171                             (LPBYTE)&regserver, &dwLen);
 172       RegCloseKey(hKey);
 173       if (ret == ERROR_SUCCESS) {
 174         if (strlen(override) > 0) {
 175           /**
 176            * we did get ProxyServer and may have an override.
 177            * So let's check the override list first, by walking down the list
 178            * The semicolons (;) separated entries have to be matched with the
 179            * the beginning of the hostname.
 180            */
 181           s = strtok_s(override, "; ", &ctx);
 182           urlhost = (*env)->GetStringUTFChars(env, host, &isCopy);
 183           if (urlhost == NULL) {
 184             if (!(*env)->ExceptionCheck(env))
 185               JNU_ThrowOutOfMemoryError(env, NULL);
 186             return NULL;
 187           }
 188           while (s != NULL) {
 189             if (strncmp(s, urlhost, strlen(s)) == 0) {
 190               /**
 191                * the URL host name matches with one of the prefixes,
 192                * therefore we have to use a direct connection.
 193                */
 194               if (isCopy == JNI_TRUE)
 195                 (*env)->ReleaseStringUTFChars(env, host, urlhost);
 196               goto noproxy;
 197             }
 198             s = strtok_s(NULL, "; ", &ctx);
 199           }
 200           if (isCopy == JNI_TRUE)
 201             (*env)->ReleaseStringUTFChars(env, host, urlhost);
 202         }
 203 
 204         cproto = (*env)->GetStringUTFChars(env, proto, &isCopy);
 205         if (cproto == NULL) {
 206           if (!(*env)->ExceptionCheck(env))
 207             JNU_ThrowOutOfMemoryError(env, NULL);
 208           return NULL;
 209         }
 210 
 211         /*
 212          * Set default port value & proxy type from protocol.
 213          */
 214         if ((strcmp(cproto, "http") == 0) ||
 215             (strcmp(cproto, "ftp") == 0) ||
 216             (strcmp(cproto, "gopher") == 0))
 217           defport = 80;
 218         if (strcmp(cproto, "https") == 0)
 219           defport = 443;
 220         if (strcmp(cproto, "socks") == 0) {
 221           defport = 1080;
 222           type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_socksID);
 223         } else {
 224           type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);
 225         }
 226 
 227         sprintf(pproto,"%s=", cproto);
 228         if (isCopy == JNI_TRUE)
 229           (*env)->ReleaseStringUTFChars(env, proto, cproto);
 230         /**
 231          * Let's check the protocol specific form first.
 232          */
 233         if ((s = strstr(regserver, pproto)) != NULL) {
 234           s += strlen(pproto);
 235         } else {
 236           /**
 237            * If we couldn't find *this* protocol but the string is in the
 238            * protocol specific format, then don't use proxy
 239            */
 240           if (strchr(regserver, '=') != NULL)
 241             goto noproxy;
 242           s = regserver;
 243         }
 244         s2 = strchr(s, ';');
 245         if (s2 != NULL)
 246           *s2 = 0;
 247 
 248         /**
 249          * Is there a port specified?
 250          */
 251         s2 = strchr(s, ':');
 252         if (s2 != NULL) {
 253           *s2 = 0;
 254           s2++;
 255           sscanf(s2, "%d", &pport);
 256         }
 257         phost = s;
 258 
 259         if (phost != NULL) {
 260           /**
 261            * Let's create the appropriate Proxy object then.
 262            */
 263           jstring jhost;
 264           if (pport == 0)
 265             pport = defport;
 266           jhost = (*env)->NewStringUTF(env, phost);
 267           CHECK_NULL_RETURN(jhost, NULL);
 268           isa = (*env)->CallStaticObjectMethod(env, isaddr_class, isaddr_createUnresolvedID, jhost, pport);
 269           CHECK_NULL_RETURN(isa, NULL);
 270           proxy = (*env)->NewObject(env, proxy_class, proxy_ctrID, type_proxy, isa);
 271           return proxy;
 272         }
 273       }
 274     } else {
 275       /* ProxyEnable == 0 or Query failed      */
 276       /* close the handle to the registry key  */
 277       RegCloseKey(hKey);
 278     }
 279   }
 280 
 281 noproxy:
 282   no_proxy = (*env)->GetStaticObjectField(env, proxy_class, pr_no_proxyID);
 283   return no_proxy;
 284 }