alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.vcs.profiles.cvsprofiles.commands.passwd;

/**
 * CVS password file .cvspass maintainer.
 * @author  mkleint
 */

import java.io.*;
import java.net.*;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Iterator;
import java.util.List;
import org.netbeans.api.vcs.commands.Command;
import org.netbeans.api.vcs.commands.CommandTask;
import org.netbeans.lib.cvsclient.CVSRoot;

import org.openide.filesystems.*;
import org.openide.*;
import org.openide.util.*;

import org.netbeans.modules.vcscore.util.*;
import org.netbeans.modules.vcscore.commands.*;

import org.netbeans.modules.vcscore.VcsFileSystem;
import org.netbeans.spi.vcs.commands.CommandSupport;
import org.openide.DialogDisplayer;
import org.openide.ErrorManager;

/** The purpose of this class is to handle everything around pserver authentication 
 * and the .cvspass file stuff. It finds, reads and writes to the file. If the configuration is not found in the file,
 * it can connect to the server and check it. Then adds the item to the .cvspass file
 */
public class CVSPasswd extends Object {
    
    private static final byte[] scramblingTableAZ = {57, 83, 43, 46, 102, 40, 89, 38, 103, 45, 50,
            42, 123, 91, 35, 125, 55, 54, 66, 124, 126, 59,
            47, 92, 71, 115 };
    private static final byte[] scramblingTableaz = {121, 117, 104, 101, 100, 69, 73, 99, 63, 94, 93,
            39, 37, 61, 48, 58, 113, 32, 90, 44, 98, 60, 51,
            33, 97, 62};
    private static final byte[] scramblingTableKeys = {(byte) '!', (byte) '"', (byte) '%', (byte) '&', (byte) '\'', (byte) '(', (byte) ')', (byte) '*', (byte) '+', (byte) ',', (byte) '-', (byte) '.', (byte) '/', 
        (byte) '_', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) ':', (byte) ';', (byte) '<', (byte) '=', (byte) '>', (byte) '?'};
    private static final byte[] scramblingTableValues = {120, 53, 109, 72, 108, 70, 64, 76, 67, 116, 74, 68, 87, 56, 111, 52, 75, 119, 49,34,82,81,95,65, 112, 86, 118, 110, 122, 105 };


    private static final String BEGIN_AUTH_REQUEST = "BEGIN AUTH REQUEST";
    private static final String END_AUTH_REQUEST = "END AUTH REQUEST";
    private static final String AUTH_SUCCESSFULL = "I LOVE YOU\n";
    
    public static final int STANDARD_PSERVER_PORT = 2401;
                                                                                                                                                                  
    /** The standard name of the file, where CVS stores passwords and cvs root directories
     * (for pserver type of connection only)
     */
    public static final String STD_FILE = ".cvspass";
    private LinkedList entries = new LinkedList();
    /** The list of unrecognized lines, which are written back when .cvspass file is saved */
    private List unrecognizedLines = new ArrayList();
    
    private File passFile = null;
    
    /** Creates new CVSPasswd */
    public CVSPasswd(String dir, String fileName) {
      String sep = File.separator;  
      if (File.separatorChar == '\\') {
         sep = "\\\\";
      } else {
      }           
      passFile = new File(dir + sep + fileName);
      //System.out.println("NOT USED: passFile = "+passFile);
      loadPassFile();
    }

    /* Not ever used:
    public CVSPasswd(String dirAndFile) {
      this(new File(dirAndFile));
    }
    */
    
    /** This is the preffered constuctor. Since it tries to do the standard cvs way
     * of finding the .cvspass file. For  Windoze we need to add some backslashes. 
     * @args cygwinPath for Windoze95/98 we need CygWin to work
     */
    public CVSPasswd(String cygwinPath) {
      String dir = getHome();
      String sep = File.separator;  
      if (File.separatorChar == '\\') {
         sep = "\\\\";
//         D("win!");
      } else {
      }           
      passFile = new File(dir + sep + STD_FILE);
 //     D("HOME=" +dir + sep + STD_FILE);
      //System.out.println("passFile = "+passFile);
      loadPassFile();
        
    }
    
    /** Get the home directory for .cvspass and possibly other cvs configuration files.
     * Looks for HOME env variable, on Windows for HOMEDRIVE + HOMEPATH.
     * If it can not be retrieved from environmental variables, return the user.home at least.
     * @return the home directory
     */
    public String getHome() {
        String home = System.getProperty("Env-HOME");
        if (home == null && Utilities.isWindows()) {
            String homePath = System.getProperty("env-homepath");
            String homeDrive = System.getProperty("env-homedrive");
            if (homePath != null && homeDrive != null) {
                home = homeDrive + homePath;
            }
        }
        if (home == null) home = System.getProperty("user.home");
        return home;
    }
    
    /** Reads the .cvspass file.
     */ 
    
    public boolean loadPassFile() {
      //System.out.println("loadPassFile("+passFile+")");
      entries = new LinkedList();
      unrecognizedLines = new ArrayList();
      BufferedReader bf = null;
      try {
        bf = new BufferedReader(new FileReader(passFile.getAbsolutePath()));
        String line;
        do {
          line = bf.readLine();
          if (line != null) {
            PasswdEntry entr = new PasswdEntry();
            boolean ok = entr.setEntry(line);
            if (!ok) {
              unrecognizedLines.add(line);
              continue;
            } else {
              entries.add(entr);
            }
          }  
        } while (line != null); 
        bf.close();
      } catch (IOException exc) {
         if (bf != null) {
             try {
                bf.close();
             } catch (IOException ioex) {}
         }    
         return false;
      }
      return true;
    }
    
    /** Writes the current passwd database to the .cvspass file.
     */
    public boolean savePassFile() {
        //System.out.println("savePassFile("+passFile+")");
      PrintWriter bf = null;
      try {
//        if (!passFile.canWrite()) return false;
        bf = new PrintWriter(new BufferedWriter(new FileWriter(passFile.getAbsolutePath(), false)));
        ListIterator lit = entries.listIterator();
        while (lit.hasNext()) {
          PasswdEntry ent = (PasswdEntry) lit.next();
          bf.println(ent.getEntry());
        }
        for (Iterator it = unrecognizedLines.iterator(); it.hasNext(); ) {
            bf.println((String) it.next());
        }
        bf.close();
        
      } catch (IOException exc) {
        javax.swing.SwingUtilities.invokeLater(new Runnable () {
           public void run () {
              DialogDisplayer.getDefault ().notify (new NotifyDescriptor.Message(org.openide.util.NbBundle.getBundle(CVSPasswd.class).getString("CVSPasswd.errorWritingPass")));
           }
         });
         if (bf != null) {
            bf.close();
         }                               
         return false;
      }
      return true;
    }

    /** Adds a new entry into the dtabase. Will be written to the file after savePassFile is run.
     * @param entry - entry supplied by the Customizer
     * @param port - a port number. If non-zero, it will be added into the entry.
     * @param passwd unscrambled password for the account
     * @return the added PasswdEntry. if not added, then null.
     */
    public PasswdEntry add(String entry, int port, String passwd) {
      PasswdEntry psw = new PasswdEntry();
      String scrambled = StandardScrambler.getInstance().scramble(passwd);
      //String scrambled = scramble(passwd);
      boolean ok = psw.setEntry(entry + " " + scrambled);
      if (ok) {
        if (port != 0) psw.getCVSRoot().setPort(port);
        entries.add(psw); 
        return psw;
      }
      return null;
    }
    
    /**
     * Remove the entry from the current set of entries.
     */
    public void remove(String entry, int port) throws IllegalArgumentException {
        PasswdEntry ent = find(entry, port);
        if (ent != null) {
            entries.remove(ent);
        }
    }
    
    /*
    public PasswdEntry add(String type, String user, String server, String root, String passwd) {
      String ent = ":" + type + ":" + user + "@" + server + ":" + root;
      return add(ent, passwd); 
    }
     */
    
   
/** Looks for the  current setting (:pserver:username@server:/rootdir) in the database.
 * @return the found PasswdEntry, or if not found null.
 * @param current The current cvs root directory
 */
    public PasswdEntry find(String current, int port) throws IllegalArgumentException {
      CVSRoot currentRootWithPort = CVSRoot.parse(current);
      if (port > 0) currentRootWithPort.setPort(port);
      if (currentRootWithPort.getPort() == 0) currentRootWithPort.setPort(STANDARD_PSERVER_PORT);
      //CVSRoot currentRootWithPort;
      CVSRoot currentRootWithoutPort; // We'll also check entry that does not have the port associated
      if (currentRootWithPort.getPort() == STANDARD_PSERVER_PORT) {
          currentRootWithoutPort = CVSRoot.parse(current);
          currentRootWithoutPort.setPort(0);
      } else {
          currentRootWithoutPort = null;
      }
      ListIterator it = entries.listIterator();
      PasswdEntry ent = null; 
      String toReturn = null;
      while (it.hasNext()) {
        ent = (PasswdEntry) it.next();
        CVSRoot cvsroot = ent.getCVSRoot();
        int compat = cvsroot.getCompatibilityLevel(currentRootWithPort);
        if (compat == 0 || compat == 1) {
            return ent;
        }
        if (currentRootWithoutPort != null) {
            compat = cvsroot.getCompatibilityLevel(currentRootWithoutPort);
            if (compat == 0 || compat == 1) {
                return ent;
            }
        }
      }
      return null;
    }
    

/* The method does the CVS pserver-style scramling of the password. 
 * See CVS client/server specificaion for details.
 * (It's definitely not secure encryption.)
 * @return The encrypted password
 * @param str the string to encrypt.
 *
  USE StandardScrambler instead !!
 
    public static final String scramble(String str) {
        String astr = new String("A"+str);
        byte[] bytes = astr.getBytes();
        for(int i = 1; i < bytes.length; i++) {
            if (bytes[i] >= 'a' && bytes[i] <= 'z') {
                bytes[i] = scramblingTableaz[bytes[i] - 'a'];
            } else if (bytes[i] >= 'A' && bytes[i] <= 'Z') {
                bytes[i] = scramblingTableAZ[bytes[i] - 'A'];
            } else {
                int j = 0;
                while(j < scramblingTableKeys.length && scramblingTableKeys[j] != bytes[i]) j++;
                if (j < scramblingTableKeys.length) bytes[i] = scramblingTableValues[j];
            }
        }
        return new String(bytes);
    }
 */
  

    /**
     * Check the login by running a command which will succeed when the right password is entered.
     * @return true if authentification succeed, othewise false.
     * @param fs the CVS filesystem to take the command from
     * @param message returns the error message
     * @return true when the login was successfull, false otherways
     */
   // public static boolean checkLogin(VcsFileSystem fs, StringBuffer message) throws UnknownHostException, IOException {
    public static boolean checkLogin(CommandExecutionContext context, StringBuffer message) throws UnknownHostException, IOException {
        CommandSupport support = context.getCommandSupport("LOGIN_CHECK");
         if (support == null) return true;
        Command cmd = support.createCommand();
        // I have no way to check the login => believe that it is O.K.
        //final ExecuteCommand es = new ExecuteCommand(fs, cmd, fs.getVariablesAsHashtable());
        TextOutputCommand txtCmd = (TextOutputCommand) cmd; 
        final StringBuffer loginCommandOutput = new StringBuffer();
        txtCmd.addTextErrorListener(new CommandOutputListener() {
            public void outputLine(String element) {
                if (element != null) {
                    loginCommandOutput.delete(0, loginCommandOutput.length());
                    loginCommandOutput.append(element+"\n");
                }
            }
        });
        txtCmd.addTextOutputListener(new CommandOutputListener() {
            public void outputLine(String element) {
                if (element != null) {
                    loginCommandOutput.delete(0, loginCommandOutput.length());
                    loginCommandOutput.append(element+"\n");
                }
            }
        });
    /*    VcsCommandExecutor vce = fs.getVcsFactory().getCommandExecutor(cmd, fs.getVariablesAsHashtable());
        final StringBuffer loginCommandOutput = new StringBuffer();
        vce.addErrorOutputListener(new CommandOutputListener() {
            public void outputLine(String element) {
                if (element != null) {
                    loginCommandOutput.delete(0, loginCommandOutput.length());
                    loginCommandOutput.append(element+"\n");
                }
            }
        });
        vce.addOutputListener(new CommandOutputListener() {
            public void outputLine(String element) {
                if (element != null) {
                    loginCommandOutput.delete(0, loginCommandOutput.length());
                    loginCommandOutput.append(element+"\n");
                }
            }
        });*/
        
        CommandTask task = cmd.execute();
        try {
            task.waitFinished(0);
        } catch (InterruptedException iexc) {
            task.stop();
            message.delete(0, message.length());
            message.append(iexc.getLocalizedMessage());
            return false;
        }
        if (task.getExitStatus() == CommandTask.STATUS_SUCCEEDED) return true;
        String output = loginCommandOutput.toString().trim();
        message.delete(0, message.length());
        message.append(output);
        //System.out.println("Exit Status = "+es.getExitStatus()+", output = "+output);
        if (output.indexOf("No route to host") >= 0) {
            throw new UnknownHostException(output);
        }/* else if (output.indexOf("fail")) {
            throw new IOException(output);
        }*/
        return false;
    }
    
//--------------------------------------------------------------------------------------
// ------------------------- server check ----------------------------------------------
 
    /** The method connects to the server specified in the PasswdEntry parameter.
     * After opening, it does the authentification (See CVS cleint/server protocol).
     * Then it disconnects.
     * @return true if authentification succeed, othewise false.
     * @param toCheck The info about the Cvs root. (server + repository + user and password)
 */
    public static boolean checkServer(PasswdEntry toCheck) throws UnknownHostException, IOException {
        OutputStreamWriter outStreamWriter = null;
        InputStreamReader inStreamReader = null;
        OutputStream outStream = null;
        InputStream inStream = null;
        Socket socket;
        boolean ok = false;
        CVSRoot cvsroot = toCheck.getCVSRoot();
        int port = cvsroot.getPort();
        if (port == 0) {
            port = STANDARD_PSERVER_PORT;
        }
        //try { 
            socket = new Socket(cvsroot.getHostName(), port);
            /*
        } catch (UnknownHostException e) {
            javax.swing.SwingUtilities.invokeLater(new Runnable () {
               public void run () {
                TopManager.getDefault ().notify (new NotifyDescriptor.Message(org.openide.util.NbBundle.getBundle(CVSPasswd.class).getString("CVSPasswd.unknownHost")));
               }
             });
            D("Exception: "+e);
            return false;
        } catch (IOException e) {
            javax.swing.SwingUtilities.invokeLater(new Runnable () {
               public void run () {
                TopManager.getDefault ().notify (new NotifyDescriptor.Message(org.openide.util.NbBundle.getBundle(CVSPasswd.class).getString("CVSPasswd.connectionIOError")));
               }
             });
            D("Exception when connecting: "+e);
            return false;
        }
             */
        try {
            outStream = socket.getOutputStream();
            outStreamWriter = new OutputStreamWriter(outStream);
            inStream = socket.getInputStream();
            inStreamReader = new InputStreamReader(inStream);
            String req = BEGIN_AUTH_REQUEST+"\n" + toCheck.getAuthString() +  END_AUTH_REQUEST+"\n";
            outStreamWriter.write(req);
            outStreamWriter.flush();
            int n;
            StringBuffer buffer = new StringBuffer();
            try {
              while(inStream.available() == 0);
              while((n = inStream.available()) > 0) {
                  byte[] bbuffer = new byte[n];
                  inStream.read(bbuffer);
                  buffer.append(new String(bbuffer));
              }
            } catch (IOException e) {
            // TODO
              D("Exception while read: "+e);
            }
            String result = buffer.toString();
            ok =  result.equals(AUTH_SUCCESSFULL);
            if (!ok) {
              javax.swing.SwingUtilities.invokeLater(new Runnable () {
                  public void run () {
                    DialogDisplayer.getDefault ().notify (new NotifyDescriptor.Message(org.openide.util.NbBundle.getBundle(CVSPasswd.class).getString("CVSPasswd.wrongPassword")));
                  }
              });
            }   
        } catch (IOException e) {
            // TODO
            D("Exception getting input: "+e);
            ok = false;
        }
        finally {
          try {
            if (outStream != null) {outStream.close();}
            if (inStream != null) {inStream.close();}
            if (socket != null) {socket.close();}
          } catch (IOException e) {
              // TODO
              D("Exception when closing the connection: "+e);
          }
        }
        return ok;
        
    }

    private static void D(String debug) {
        //System.out.println("CvsPasswd(): "+debug);
    }
    
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.