001: package socks.server;
002:
003: import java.io.BufferedReader;
004: import java.io.IOException;
005: import java.io.InputStreamReader;
006:
007: import java.net.InetSocketAddress;
008: import java.net.Socket;
009:
010: import java.util.StringTokenizer;
011:
012: /**
013: Class Ident provides means to obtain user name of the owner of the socket
014: on remote machine, providing remote machine runs identd daemon.
015: <p>
016: To use it:
017: <tt><pre>
018: Socket s = ss.accept();
019: Ident id = new Ident(s);
020: if(id.successful) goUseUser(id.userName);
021: else handleIdentError(id.errorCode,id.errorMessage)
022: </pre></tt>
023: */
024: public class Ident {
025: /** Identd on port 113 can't be contacted*/
026: public static final int ERR_NO_CONNECT = 1;
027:
028: /** Connection timed out*/
029: public static final int ERR_TIMEOUT = 2;
030:
031: /** Identd daemon responded with ERROR, in this case errorMessage
032: contains the string explanation, as send by the daemon.
033: */
034: public static final int ERR_PROTOCOL = 3;
035:
036: /**
037: When parsing server response protocol error happened.
038: */
039: public static final int ERR_PROTOCOL_INCORRECT = 4;
040:
041: /** Maximum amount of time we should wait before dropping the
042: connection to identd server.Setting it to 0 implies infinit
043: timeout.
044: */
045: public static final int connectionTimeout = 10000;
046:
047: /** Host type as returned by daemon, can be null, if error happened*/
048: private String hostType;
049:
050: /** User name as returned by the identd daemon, or null, if it failed*/
051: private String userName;
052:
053: /** Error code*/
054: public int errorCode;
055:
056: /**
057: Constructor tries to connect to Identd daemon on the host of the
058: given socket, and retrieve user name of the owner of given socket
059: connection on remote machine. After constructor returns public
060: fields are initialised to whatever the server returned.
061: <p>
062: If user name was successfully retrieved successful is set to true,
063: and userName and hostType are set to whatever server returned. If
064: however for some reason user name was not obtained, successful is set
065: to false and errorCode contains the code explaining the reason of
066: failure, and errorMessage contains human readable explanation.
067: <p>
068: Constructor may block, for a while.
069: @param s Socket whose ownership on remote end should be obtained.
070: */
071: public Ident(Socket s) throws IOException {
072: Socket sock = null;
073:
074: try {
075: sock = new Socket();
076: sock.bind(s.isBound() ? new InetSocketAddress(s
077: .getLocalAddress(), 0) : null);
078: sock.setSoTimeout(connectionTimeout);
079: sock.connect(
080: new InetSocketAddress(s.getInetAddress(), 113),
081: connectionTimeout);
082:
083: byte[] request = ("" + s.getPort() + " , "
084: + s.getLocalPort() + "\r\n").getBytes();
085:
086: sock.getOutputStream().write(request);
087:
088: BufferedReader in = new BufferedReader(
089: new InputStreamReader(sock.getInputStream()));
090:
091: parseResponse(in.readLine());
092: } finally {
093: try {
094: if (sock != null) {
095: sock.close();
096: }
097: } catch (IOException ioe) {
098: }
099: }
100: }
101:
102: private void parseResponse(String response) throws IOException {
103: if (response == null) {
104: throw new IOException("Identd server closed connection.");
105: }
106:
107: StringTokenizer st = new StringTokenizer(response, ":");
108:
109: if (st.countTokens() < 3) {
110: throw new IOException("Can't parse server response: "
111: + response);
112: }
113:
114: st.nextToken(); //Discard first token, it's basically what we have send
115:
116: String command = st.nextToken().trim().toUpperCase();
117:
118: if (command.equals("USERID") && (st.countTokens() >= 2)) {
119: hostType = st.nextToken().trim();
120: userName = st.nextToken().trim(); //Get all that is left
121:
122: if (userName.indexOf('@') != -1) {
123: throw new IOException("Illegal username: " + userName);
124: }
125:
126: return;
127: } else if (command.equals("ERROR")) {
128: throw new IOException("Ident ERROR: " + response);
129: } else {
130: throw new IOException("Unexpected reply: " + response);
131: }
132: }
133:
134: public String getUserName() {
135: return userName;
136: }
137:
138: public String getHostType() {
139: return hostType;
140: }
141: }
|