/*
 *(c) 2003, visigoth <visigoth@securitycentric.com>
 * This source code is distributed under a BSD license,
 * please see the LICENSE file for details
 *
 * OracleDefaults.java
 *
 * Created on May 5, 2003, 7:26 AM
 */

import com.securitycentric.metacoretex.*;
import com.securitycentric.metacoretex.lib.*;
import com.securitycentric.metacoretex.interfaces.*;

import java.sql.*;
import java.util.*;
import java.io.*;

/**
 *
 * @author  visigoth
 */
public class OracleDefaults extends AbstractAuthProbe {
    
    /** Creates a new instance of OracleAuth */
    public OracleDefaults() {
        
        setName("Oracle Default Accounts");
        setFamily("Oracle");
        setCopyright("(c) 2003, visigoth <visigoth@securitycentric.com>");
        setVersion("$Id: OracleDefaults.java,v 1.8 2003/10/02 02:20:43 visigoth_6 Exp $");
        setProbeId(7);
        setTimeout(0);
        setBrute(true);
        
        addDepends("tcp/ports");
        addDepends("oracle/sids");
        
        /* This strange combination will cause it 
         * to be placed just _after_ the other providor
         * for oracle/connection
         */
        addDepends("oracle/connection");
        addProvides("oracle/connection","java.sql.Connection to target Oracle");
        
        addOption("accounts_file",System.getProperty("user.dir")+"/conf/oracle_accounts.txt");
        addOption("sid","oracle");
        
        setHelp("This probe attempts to connect to an available Oracle database "+
        "using a file specified list of defaults.\n\n"+
        "Options:\n"+
        "account_file - The default account list\n\n"+
        "sid - The name of the database to connect to.  This can be ignored if OracleTNSStatus probe finds SIDS");
        
        setReport("Found the following default accounts:\n"+
        "=================================\n");
        
        accounts = new Hashtable();
        pwHashes = new Hashtable();
    }
    
    public void probe() throws ProbeException {
        
        if (kbHas("tcp/1521")) {
            Boolean bol = (Boolean)kbGet("tcp/1521");
            if ( ! bol.booleanValue())
                return;
        }
        
        fillHashes();
        
        if (kbHas("oracle/sysdba")) {
            con = (Connection)kbGet("oracle/connection");
            try {
                PreparedStatement stmt = con.prepareStatement("SELECT username,password,account_status FROM sys.dba_users WHERE username=? AND password=?");
                Iterator acIt = pwHashes.keySet().iterator();
                
                while (acIt.hasNext()) {
                    tried++;
                    String key = (String)acIt.next();
                    stmt.setString(1,key);
                    stmt.setString(2,(String)pwHashes.get(key));
                    res = stmt.executeQuery();
                    setReportable(true);
                    
                    while (res.next()) {
                        addReport(res.getString("username")+"\t"+
                        res.getString("password")+"\t"+
                        res.getString("account_status"));
                        
                        if (res.getString("account_status").matches("OPEN"))
                            setSeverity(3);
                    }
                }
            } catch (SQLException se) {
                throw(new ProbeException(se.getMessage()));
            }
            
        } else {
            
            Properties prop = new Properties();
            String oracleUrl = "jdbc:oracle:thin:@" + getHost() + ":1521:";
            
            if (kbHas("oracle/sids"))
                sidVect = (Vector)kbGet("oracle/sids");
            else {
                sidVect = new Vector();
                sidVect.add(getOption("sid"));
            }
            
            Iterator sidIt = sidVect.iterator();
            while (sidIt.hasNext()) {
                String sid = (String)sidIt.next();
                addReport("SID " + sid + " :");
                sidCount++;
                tried = 0;
                
                Iterator acIt = accounts.keySet().iterator();
                while (acIt.hasNext()) {
                    String key = (String)acIt.next();
                    tried++;
                    
                    prop.setProperty("user",key);
                    prop.setProperty("password",(String)accounts.get(key));
                    //prop.setProperty("internal_logon",getOption("oracle/role"));
                    
                    
                    try {
                        con = DriverManager.getConnection(oracleUrl + sid, prop);
                    } catch (SQLException se) {
                        
                        // Username/Pass failed
                        if (se.getMessage().startsWith("ORA-01017"))
                            continue;
                        
                        // Sid isn't running
                        if (se.getMessage().startsWith("ORA-01034")) {
                            throw(new ProbeException(se.getMessage()));
                        }
                        // Account is locked
                        if (se.getMessage().startsWith("ORA-28000")) {
                            addReport("\t"+key + " : " + (String)accounts.get(key) + " LOCKED");
                            setReportable(true);
                            continue;
                        }
                        continue;
                    }
                    
                    setReportable(true);
                    setSeverity(3);
                    addReport("\t" + key + " : " + (String)accounts.get(key));
                    
                    if (!kbHas("oracle/connection"))
                        kbPut("oracle/connection", con);
                }
            }
        }
        addReport("\n\nTried " + tried + " accounts\nIn " + sidCount + " sids\n");
    }
    
    public void fillHashes() throws ProbeException {
        try {
            BufferedReader br = new BufferedReader(new FileReader(getOption("accounts_file")));
            String line;
            while((line = br.readLine()) != null) {
                if (line.startsWith("#"))
                    continue;
                
                String[] account = line.split(",");
                
                accounts.put(account[0],account[1]);
                pwHashes.put(account[0],account[2].trim());
                
            }
        } catch (FileNotFoundException e) {
            throw(new ProbeException("fillHashes() Failed: " + e.getMessage()));
        } catch (IOException e) {
            throw(new ProbeException("fillHashes() Failed: " + e.getMessage()));
        }
    }
    
    Hashtable accounts;
    Hashtable pwHashes;
    ResultSet res;
    Vector sidVect;
    int tried = 0;
    int sidCount = 0;
    Connection con;
}
