/* * Created on 26/01/2005 * Created by Paul Duran * Copyright (C) 2004 Aelitis, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * AELITIS, SARL au capital de 30,000 euros * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. * */ package org.gudy.azureus2.ui.telnet; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.Iterator; import java.util.Set; import org.gudy.azureus2.core3.util.AEThread2; import org.gudy.azureus2.ui.common.UIConst; import org.gudy.azureus2.ui.console.UserProfile; import org.gudy.azureus2.ui.console.multiuser.UserManager; /** * this class is used to receive incoming connections for the telnet UI and * then authenticate and create a console session for the connection * @author pauld */ final class SocketServer implements Runnable { private final ServerSocket serverSocket; private final Set allowedHosts; private final int maxLoginAttempts; private final UserManager userManager; private final UI ui; public SocketServer(UI ui, int port, Set allowedHosts, UserManager userManager, int maxLoginAttempts) throws IOException { this.ui = ui; this.allowedHosts = allowedHosts; this.userManager = userManager; serverSocket = new ServerSocket(port); this.maxLoginAttempts = maxLoginAttempts; } /** * start up the server socket and when a new connection is received, check that * the source address is in our permitted list and if so, start a new console input * on that socket. */ public void run() { int threadNum = 1; System.out.println("Telnet server started. Listening on port: " + serverSocket.getLocalPort()); new AEThread2( "AZCoreStartup", true ) { public void run() { UIConst.getAzureusCore(); } }.start(); while( true ) { try { Socket socket = serverSocket.accept(); InetSocketAddress addr = (InetSocketAddress) socket.getRemoteSocketAddress(); if( addr.isUnresolved() || ! isAllowed(addr) ) { System.out.println("TelnetUI: rejecting connection from: " + addr + " as address is not allowed"); socket.close(); } else { System.out.println("TelnetUI: accepting connection from: " + addr); int loginAttempts = 0; while( true ) { // TODO: might want to put this in another thread so the port doesnt block while the user logs in //System.out.println("TelnetUI: starting login" ); UserProfile profile = login( socket.getInputStream(), socket.getOutputStream() ); //System.out.println("TelnetUI: login profile obtained" ); if( profile != null ) { //System.out.println("TelnetUI: creating console input" ); ui.createNewConsoleInput("Telnet Console " + threadNum++, socket.getInputStream(), new PrintStream(socket.getOutputStream()), profile); break; } //System.out.println("TelnetUI: failed to obtain login profile" ); loginAttempts++; if( loginAttempts >= maxLoginAttempts ) { System.out.println("TelnetUI: rejecting connection from: " + addr + " as number of failed connections > max login attempts (" + maxLoginAttempts + ")"); socket.close(); break; } } } } catch (Throwable t) { t.printStackTrace(); break; } } } /** * if usermanager is null (ie: multi user is not enabled), returns the default user profile * otherwise, requests username and password and authenticates user before returning * the user profile for this user * @param in input stream to read from * @param out stream to write messages to * @return username if login was successful, null otherwise * @throws IOException */ private UserProfile login(InputStream in, OutputStream out) throws IOException { if( userManager == null ) return UserProfile.DEFAULT_USER_PROFILE; PrintStream ps = new PrintStream(out); BufferedReader br = new BufferedReader(new InputStreamReader(in)); ps.print("Username: "); String username = br.readLine(); ps.print("Password: "); String password = br.readLine(); UserProfile userProfile = userManager.authenticate(username, password); if( userProfile != null ) { ps.println("Login successful"); return userProfile; } ps.println("Login failed"); return null; } /** * check that the specified host/ip is allowed * @param addr * @return */ private boolean isAllowed(InetSocketAddress addr) { InetAddress address = addr.getAddress(); if( checkHost(address.getHostAddress()) ) return true; else if( checkHost(address.getHostName())) return true; else return false; } /** * compare the specified host (might be a hostname or an IP - dont really care) * and see if it is a match against one of the allowed hosts * @param hostName * @return true if this hostname matches one in our allowed hosts */ private boolean checkHost(String hostName) { if( hostName == null ) return false; hostName = hostName.toLowerCase(); // System.out.println("checking host: " + hostName); for (Iterator iter = allowedHosts.iterator(); iter.hasNext();) { String allowedHost = (String) iter.next(); if( hostName.equals(allowedHost) ) return true; } return false; } }