/*
 * (c) 2003, visigoth <visigoth@securitycentric.com>
 *
 * NmapScanner.java
 * 
 */

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

import java.util.*;
import java.io.*;
import nmapxml.*;
import javax.xml.bind.*;

/**
 *
 * @author  visigoth
 */
public class NmapScanner extends AbstractProbe {
    
    /** Creates a new instance of NmapScanner */
    public NmapScanner() {
        
        setName("Nmap Scanner");
        setFamily("Network");
        setVersion("$Id: NmapScanner.java,v 1.3 2003/10/02 02:20:43 visigoth_6 Exp $");
        setProbeId(42);
        setCopyright("(c) 2003, visigoth <visigoth@securitycentric.com>");
        setSeverity(0);
        setEnabled(false);
        
        addProvides("tcp/ports","tcp/<port> Boolean for open/closed");
        addOption("command","nmap");
        addOption("args","-v -oX - _TARGET_");

        setReport("The following ports were fount open by NMAP\n"+
                  "================================\n");
        
        setHelp("This probe runs NMAP if available using the given command arguments.  It will then create a Hashtable for other probes to lookup open services.");
    }

    public void probe() throws ProbeException {
        String fullStr = getOption("command")+" "+getOption("args");
        String line;
        String response = new String();
        JAXBContext jc;
        Nmaprun nmr;

        fullStr = fullStr.replaceAll("_TARGET_",getHost());

        try {
            jc = JAXBContext.newInstance("nmapxml");
            Unmarshaller u = jc.createUnmarshaller();
            Marshaller m = jc.createMarshaller();

            Process proc = Runtime.getRuntime().exec(fullStr);

            nmr = (Nmaprun)u.unmarshal(proc.getInputStream());
            String services = nmr.getScaninfo().getServices();
            
            List hosts = nmr.getHost();
            /* We should be the only target  */
            NHost ourHost = (NHost)hosts.get(0);
            NPorts ports = ourHost.getPorts();

            NExPorts extraPorts = ports.getExtraports();

            if (! extraPorts.getState().matches("open")) {

                String servArray[] = services.split(",");

                /* parse each listed service or service range */
                for (int i = 0; i<servArray.length; i++) {

                    if (servArray[i].matches("\\d+\\-\\d+")) {

                        String range[] = servArray[i].split("-");
                        int min = Integer.parseInt(range[0]);
                        int max = Integer.parseInt(range[1]);

                        while (min <= max) {
                            kbPut("tcp/"+min, new Boolean("false"));
                            min++;
                        }

                    } else {
                        kbPut("tcp/"+servArray[i], new Boolean("false"));
                    }
                }
            }

            /* get a vector of the ports (likely open) and add entries
             * to the KB for listed ports
             */
            List portVect = ports.getPort();
            Iterator portIter = portVect.iterator();
            while (portIter.hasNext()) {

                NPort nPort = (NPort)portIter.next();

                int portInt = nPort.getPortid();

                String state = nPort.getState().getState();

                if (state.matches("open")) {
                    kbPut("tcp/"+portInt, new Boolean("true"));
                    addReport(portInt+" ");
                }
            }

            /* Lets include the entire XML output in the report */
            addReport("\n\nBelow this line is the raw XML output\n"+
                      "========================================\n");
            // FIXME
            //addReport(m.marshal(nmr));

            setReportable(true);

        } catch (IOException e) {
            throw(new ProbeException("IOException: "+e.getMessage()));
        } catch (JAXBException e) {
            throw(new ProbeException("JAXBException: "+e.getMessage()));
        } catch (NumberFormatException e) {
            throw(new ProbeException("NumberFormatException: "+e.getMessage()));
        }
    }
}
