1 /*
   2  * Copyright (c) 2009, 2020, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test
  26  * @bug 6449574
  27  * @summary Invalid ldap filter is accepted and processed
  28  */
  29 
  30 import java.io.*;
  31 import javax.naming.*;
  32 import javax.naming.directory.*;
  33 import java.util.Properties;
  34 import java.util.Hashtable;
  35 
  36 import java.net.Socket;
  37 import java.net.ServerSocket;
  38 
  39 public class BalancedParentheses {
  40     // Should we run the client or server in a separate thread?
  41     //
  42     // Both sides can throw exceptions, but do you have a preference
  43     // as to which side should be the main thread.
  44     static boolean separateServerThread = true;
  45 
  46     // use any free port by default
  47     volatile int serverPort = 0;
  48 
  49     // Is the server ready to serve?
  50     volatile static boolean serverReady = false;
  51 
  52     // Define the server side of the test.
  53     //
  54     // If the server prematurely exits, serverReady will be set to true
  55     // to avoid infinite hangs.
  56     void doServerSide() throws Exception {
  57         ServerSocket serverSock = new ServerSocket(serverPort);
  58 
  59         // signal client, it's ready to accecpt connection
  60         serverPort = serverSock.getLocalPort();
  61         serverReady = true;
  62 
  63         // accept a connection
  64         Socket socket = serverSock.accept();
  65         System.out.println("Server: Connection accepted");
  66 
  67         InputStream is = socket.getInputStream();
  68         OutputStream os = socket.getOutputStream();
  69 
  70         // read the bindRequest
  71         while (is.read() != -1) {
  72             // ignore
  73             is.skip(is.available());
  74             break;
  75         }
  76 
  77         byte[] bindResponse = {0x30, 0x0C, 0x02, 0x01, 0x01, 0x61, 0x07, 0x0A,
  78                                0x01, 0x00, 0x04, 0x00, 0x04, 0x00};
  79         // write bindResponse
  80         os.write(bindResponse);
  81         os.flush();
  82 
  83         // ignore any more request.
  84         while (is.read() != -1) {
  85             // ignore
  86             is.skip(is.available());
  87         }
  88 
  89         is.close();
  90         os.close();
  91         socket.close();
  92         serverSock.close();
  93     }
  94 
  95     //  Define the client side of the test.
  96     //
  97     // If the server prematurely exits, serverReady will be set to true
  98     // to avoid infinite hangs.
  99     void doClientSide() throws Exception {
 100         // Wait for server to get started.
 101         while (!serverReady) {
 102             Thread.sleep(50);
 103         }
 104 
 105         // set up the environment for creating the initial context
 106         Hashtable<Object, Object> env = new Hashtable<>();
 107         env.put(Context.INITIAL_CONTEXT_FACTORY,
 108                                 "com.sun.jndi.ldap.LdapCtxFactory");
 109         env.put(Context.PROVIDER_URL, "ldap://localhost:" + serverPort);
 110         env.put("com.sun.jndi.ldap.read.timeout", "1000");
 111 
 112         // env.put(Context.SECURITY_AUTHENTICATION, "simple");
 113         // env.put(Context.SECURITY_PRINCIPAL,"cn=root");
 114         // env.put(Context.SECURITY_CREDENTIALS,"root");
 115 
 116         // create initial context
 117         DirContext context = new InitialDirContext(env);
 118 
 119         // searching
 120         SearchControls scs = new SearchControls();
 121         scs.setSearchScope(SearchControls.SUBTREE_SCOPE);
 122 
 123         try {
 124             NamingEnumeration<?> answer = context.search(
 125                                         "o=sun,c=us", "(&(cn=Bob)))", scs);
 126         } catch (InvalidSearchFilterException isfe) {
 127             // ignore, it is the expected filter exception.
 128             System.out.println("Expected exception: " + isfe.getMessage());
 129         } catch (NamingException ne) {
 130             // maybe a read timeout exception, as the server does not response.
 131             throw new Exception("Expect a InvalidSearchFilterException", ne);
 132         }
 133 
 134         try {
 135             NamingEnumeration<?> answer = context.search(
 136                                         "o=sun,c=us", ")(&(cn=Bob)", scs);
 137         } catch (InvalidSearchFilterException isfe) {
 138             // ignore, it is the expected filter exception.
 139             System.out.println("Expected exception: " + isfe.getMessage());
 140         } catch (NamingException ne) {
 141             // maybe a read timeout exception, as the server does not response.
 142             throw new Exception("Expect a InvalidSearchFilterException", ne);
 143         }
 144 
 145         try {
 146             NamingEnumeration<?> answer = context.search(
 147                                         "o=sun,c=us", "(&(cn=Bob))", scs);
 148         } catch (InvalidSearchFilterException isfe) {
 149             // ignore, it is the expected filter exception.
 150             throw new Exception("Unexpected ISFE", isfe);
 151         } catch (NamingException ne) {
 152             // maybe a read timeout exception, as the server does not response.
 153             System.out.println("Expected exception: " + ne.getMessage());
 154         }
 155 
 156         context.close();
 157     }
 158 
 159     /*
 160      * ============================================================
 161      * The remainder is just support stuff
 162      */
 163 
 164     // client and server thread
 165     Thread clientThread = null;
 166     Thread serverThread = null;
 167 
 168     // client and server exceptions
 169     volatile Exception serverException = null;
 170     volatile Exception clientException = null;
 171 
 172     void startServer(boolean newThread) throws Exception {
 173         if (newThread) {
 174             serverThread = new Thread() {
 175                 public void run() {
 176                     try {
 177                         doServerSide();
 178                     } catch (Exception e) {
 179                         /*
 180                          * Our server thread just died.
 181                          *
 182                          * Release the client, if not active already...
 183                          */
 184                         System.err.println("Server died...");
 185                         System.err.println(e);
 186                         serverReady = true;
 187                         serverException = e;
 188                     }
 189                 }
 190             };
 191             serverThread.start();
 192         } else {
 193             doServerSide();
 194         }
 195     }
 196 
 197     void startClient(boolean newThread) throws Exception {
 198         if (newThread) {
 199             clientThread = new Thread() {
 200                 public void run() {
 201                     try {
 202                         doClientSide();
 203                     } catch (Exception e) {
 204                         /*
 205                          * Our client thread just died.
 206                          */
 207                         System.err.println("Client died...");
 208                         clientException = e;
 209                     }
 210                 }
 211             };
 212             clientThread.start();
 213         } else {
 214             doClientSide();
 215         }
 216     }
 217 
 218     // Primary constructor, used to drive remainder of the test.
 219     BalancedParentheses() throws Exception {
 220         if (separateServerThread) {
 221             startServer(true);
 222             startClient(false);
 223         } else {
 224             startClient(true);
 225             startServer(false);
 226         }
 227 
 228         /*
 229          * Wait for other side to close down.
 230          */
 231         if (separateServerThread) {
 232             serverThread.join();
 233         } else {
 234             clientThread.join();
 235         }
 236 
 237         /*
 238          * When we get here, the test is pretty much over.
 239          *
 240          * If the main thread excepted, that propagates back
 241          * immediately.  If the other thread threw an exception, we
 242          * should report back.
 243          */
 244         if (serverException != null) {
 245             System.out.print("Server Exception:");
 246             throw serverException;
 247         }
 248         if (clientException != null) {
 249             System.out.print("Client Exception:");
 250             throw clientException;
 251         }
 252     }
 253 
 254     public static void main(String[] args) throws Exception {
 255         // start the test
 256         new BalancedParentheses();
 257     }
 258 
 259 }