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