package com.runjva.sourceforge.jsocks.server; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import com.runjva.sourceforge.jsocks.protocol.InetRange; import com.runjva.sourceforge.jsocks.protocol.ProxyMessage; /** * An implementation of socks.ServerAuthentication which provides simple * authentication based on the host from which the connection is made and the * name of the user on the remote machine, as reported by identd daemon on the * remote machine. * <p> * It can also be used to provide authentication based only on the contacting * host address. */ public class IdentAuthenticator extends ServerAuthenticatorBase { /** Vector of InetRanges */ Vector<InetRange> hosts; /** Vector of user hashes */ Vector<Hashtable<?, ?>> users; String user; /** * Constructs empty IdentAuthenticator. */ public IdentAuthenticator() { hosts = new Vector<InetRange>(); users = new Vector<Hashtable<?, ?>>(); } /** * Used to create instances returned from startSession. * * @param in * Input stream. * @param out * OutputStream. * @param user * Username associated with this connection,could be null if name * was not required. */ IdentAuthenticator(InputStream in, OutputStream out, String user) { super(in, out); this.user = user; } /** * Adds range of addresses from which connection is allowed. Hashtable users * should contain user names as keys and anything as values (value is not * used and will be ignored). * * @param hostRange * Range of ip addresses from which connection is allowed. * @param users * Hashtable of users for whom connection is allowed, or null to * indicate that anybody is allowed to connect from the hosts * within given range. */ public synchronized void add(InetRange hostRange, Hashtable<?, ?> users) { this.hosts.addElement(hostRange); this.users.addElement(users); } /** * Grants permission only to those users, who connect from one of the hosts * registered with add(InetRange,Hashtable) and whose names, as reported by * identd daemon, are listed for the host the connection came from. */ public ServerAuthenticator startSession(Socket s) throws IOException { final int ind = getRangeIndex(s.getInetAddress()); String user = null; // System.out.println("getRangeReturned:"+ind); if (ind < 0) { return null; // Host is not on the list. } final ServerAuthenticator serverAuthenticator = super.startSession(s); final ServerAuthenticatorBase auth = (ServerAuthenticatorBase) serverAuthenticator; // System.out.println("super.startSession() returned:"+auth); if (auth == null) { return null; } // do the authentication final Hashtable<?, ?> user_names = users.elementAt(ind); if (user_names != null) { // If need to do authentication Ident ident; ident = new Ident(s); // If can't obtain user name, fail if (!ident.successful) { return null; } // If user name is not listed for this address, fail if (!user_names.containsKey(ident.userName)) { return null; } user = ident.userName; } return new IdentAuthenticator(auth.in, auth.out, user); } /** * For SOCKS5 requests allways returns true. For SOCKS4 requests checks * wether the user name supplied in the request corresponds to the name * obtained from the ident daemon. */ public boolean checkRequest(ProxyMessage msg, java.net.Socket s) { // If it's version 5 request, or if anybody is permitted, return true; if ((msg.version == 5) || (user == null)) { return true; } if (msg.version != 4) { return false; // Who knows? } return user.equals(msg.user); } /** Get String representaion of the IdentAuthenticator. */ public String toString() { String s = ""; for (int i = 0; i < hosts.size(); ++i) { s += "(Range:" + hosts.elementAt(i) + "," + // " Users:" + userNames(i) + ") "; } return s; } // Private Methods // //////////////// private int getRangeIndex(InetAddress ip) { int index = 0; final Enumeration<InetRange> enumx = hosts.elements(); while (enumx.hasMoreElements()) { final InetRange ir = enumx.nextElement(); if (ir.contains(ip)) { return index; } index++; } return -1; // Not found } private String userNames(int i) { if (users.elementAt(i) == null) { return "Everybody is permitted."; } final Enumeration<?> enumx = ((Hashtable<?, ?>) users.elementAt(i)) .keys(); if (!enumx.hasMoreElements()) { return ""; } String s = enumx.nextElement().toString(); while (enumx.hasMoreElements()) { s += "; " + enumx.nextElement(); } return s; } }