Oracle Java Runtime Environment (JRE) Detection (Unix)

2013-02-22T00:00:00
ID SUN_JAVA_JRE_INSTALLED_UNIX.NASL
Type nessus
Reporter This script is Copyright (C) 2013-2019 and is owned by Tenable, Inc. or an Affiliate thereof.
Modified 2013-02-22T00:00:00

Description

One or more instances of Oracle

                                        
                                            #TRUSTED 54a08c69033c5637100a82c900f407b254f13e35687ac93af7900c870e7403ead524cffe915b597cc399f49e4dfa4f10e4462e99b4993c8b2c779574186b6b0161ee0e639cdd5f92200287ddd358a4dfd9d7e04d6bb42e1dd5a81a0a0e4ac6cd79184334cd89b51b1b40410f12dbf8ee44a477c87f56508f1cd2ff88b496c92302f89932ea123799c558ee7721f19cd562dccf17675c256bbce622aee3c600bc75dfcc7d6b53eeb0085ec98ce2f9f391d2b5dc8efac72823c74e199c7fc91ad56452c90d380226d7a20298dc7aaf8068c9c27a514bc63c401356b66bb5afef90d30178aff67e7cdaa9f5c81df041e0130fd151028b2971ac0c92b8a57b8c028454bec24318f571eae8fc8aa630a6c3030e4b826e41ebd401e8df8433ecb50766ed7be339c0a2e33b27b7a37dce8d0cd630608a4e3d2322824b5b62b8f3cd685ccc9f2c1bc4a5b53c8cfb019d7af9c5457519ccbe4000da2190b0d2caf8984becac231500ea2fc264ef2779af560fb2e9305cce12fbb9558e69dc9f8c8f0449c01db22ca15e410cb2e316c9c606819629bc0c201e27b632b19307057e42692d31f993f07312867200cf502db7d7359035a7ea11b9ca044f76bb4a8f2c8a08daa377f67788410d020e94c08a93283d5aa21baa6736c4a4ecf479f7177b9bcc68c49d373e79a389fc847ce42f2f9b2495c7729fc191c07c7a50344144c781637bc6

#
# (C) Tenable Network Security, Inc.
#


include("compat.inc");


if (description)
{
  script_id(64815);
  script_version("1.70");
  script_set_attribute(attribute:"plugin_modification_date", value:"2019/07/29");

  script_name(english:"Oracle Java Runtime Environment (JRE) Detection (Unix)");
  script_summary(english:"Checks for Oracle/Sun JRE installs.");

  script_set_attribute(attribute:"synopsis", value:
"The Java runtime environment is installed on the remote Unix host.");
  script_set_attribute(attribute:"description", value:
"One or more instances of Oracle's (formerly Sun's) Java Runtime
Environment (JRE) are installed on the remote host. This may include
private JREs bundled with the Java Development Kit (JDK).

Notes:
  
  - This plugin does not detect non-Oracle JRE instances such
    as OpenJDK, GCJ, IBM Java, etc.

  - To discover instances of JRE that are not in PATH, 
    or installed via a package manager, thorough tests 
    must be enabled.");
  script_set_attribute(attribute:"see_also", value:"https://www.oracle.com/technetwork/java/index.html");
  script_set_attribute(attribute:"solution", value:"n/a");
  script_set_attribute(attribute:"risk_factor", value:"None");

  script_set_attribute(attribute:"plugin_publication_date", value:"2013/02/22");

  script_set_attribute(attribute:"plugin_type", value:"local");
  script_set_attribute(attribute:"cpe", value:"cpe:/a:oracle:jre");
  script_set_attribute(attribute:"agent", value:"unix");
  script_end_attributes();

  script_category(ACT_GATHER_INFO);
  script_family(english:"General");

  script_copyright(english:"This script is Copyright (C) 2013-2019 and is owned by Tenable, Inc. or an Affiliate thereof.");

  script_dependencies("ssh_get_info.nasl", "oracle_enum_products_nix.nbin");
  script_require_keys("Host/local_checks_enabled");
  script_timeout(1500);  # Allow more time than the default (see also 'maxtime' below)

  exit(0);
}

include("audit.inc");
include("global_settings.inc");
include("ssh_func.inc");
include("telnet_func.inc");
include("hostlevel_funcs.inc");
include("misc_func.inc");
include("install_func.inc");
include("find_cmd.inc");
include("sh_commands_find.inc");
include("spad_log_func.inc");
include("spad_logger.inc");

var starttime = gettimeofday();
var time_limit_met = FALSE;

if(sshlib::get_support_level() >= sshlib::SSH_LIB_SUPPORTS_COMMANDS)
  enable_ssh_wrappers();
else disable_ssh_wrappers();


##
#  Functions
##

##
# Checks to see if a java install is bundled with an Oracle Product
#
# @remark This function basically checks to see if javapath contains any known
#         ohome path.
#
# @param javapath string absolute path to the java binary to check
#
# @returns TRUE if javapath is bundled in an Oracle application, FALSE if not
##
function oracle_bundled_java(javapath)
{
  spad_log(message:'java_inst_debug: Entering ' + FUNCTION_NAME + '\n');
  # Optimization: if no Oracle products are installed it can't be bundled
  if(!get_kb_item("Oracle/Products/Installed"))
    return FALSE;
  local_var sqlq = "SELECT path FROM oracle_homes";
  local_var sqlr = query_scratchpad(sqlq);
  local_var row  = NULL;
  if(isnull(sqlr))
    return FALSE;
  foreach row (sqlr)
  {
    if(row["path"] >< javapath)
      return TRUE;
  }
  return FALSE;
}

# Simple wrapper to make run_cmd_template a drop in replacement for
# info_send_cmd
function run_cmd_template_wrapper(template,args)
{
  spad_log(message:'java_inst_debug: Entering ' + FUNCTION_NAME + '\n');
  local_var resp;
  resp = run_cmd_template(template:template,args:args);
  if (resp['error'] == HLF_OK)
    resp = resp['data'];
  else
    resp = NULL;
  return resp;
}

# Attempts to resolve a symlinks "true" path via namei if
# namei is not available we will use ls and follow up to
# 5 links, if item is not a symlink or cannot be resolved
# in 5 traversals it is returned unchanged otherwise 
# the true path is returned.
function resolve_symlink(item)
{
  spad_log(message:'java_inst_debug: Entering ' + FUNCTION_NAME + '\n');
  local_var sympath,buf2,line,lines,count,path;
  local_var old_sympath, pattern, match;

  # If the path / item doesn't start with / 
  # then its an error like "find : cycle detect"
  # ect ...
  if(item !~ "^/(.*)$")
    return item;

  sympath = '';
  old_sympath =  item;
  spad_log(message:'java_inst_debug: calling namei ' + item + '\n');
  buf2 = info_send_cmd(cmd:"namei " + item);
  spad_log(message:'java_inst_debug: Response ' + obj_rep(buf2) + '\n');
  
  if (buf2 && 'not found' >!< buf2 && "segmentation fault" >!< tolower(buf2))
  {
    lines = split(buf2, keep:FALSE);
    foreach line (lines)
    {
      # symlinks start with 'l'
      if (preg(pattern:'^(\\s)+l .*', string:line))
      {
        sympath = ereg_replace(pattern:'^(\\s)+l [^>]+> (.*)$', string:line, replace:"\2");
        if(sympath !~ "^/")
        {
          match = pregmatch(pattern:"^\s+l ([^>]+) .> (.*)", string:line);
          if(!isnull(match))
          {
             pattern = match[1];
             sympath = ereg_replace(pattern:pattern, string:old_sympath, replace:match[2]);
             sympath = ereg_replace(pattern:'//', replace:'/', string:sympath);
          }
        }
        old_sympath = sympath;
      }
    }
    if (sympath) item = chomp(sympath);
  }
  # Not all hosts support namei. In those cases,
  # just use ls to follow the symlink
  else
  {
    # Go up to 5 deep on the symlinks
    count = 0;
    while (count < 5)
    {
      path = item;
      path = ereg_replace(pattern:"^(.*)/$",string:path,replace:"\1"); # Strip trailing /
      spad_log(message:'java_inst_debug: calling ls -l ' + path + '\n');
      buf2 = info_send_cmd(cmd:"ls -l " + path);
      spad_log(message:'java_inst_debug: Response ' + obj_rep(buf2) + '\n');

      # No buf : there was an error return original item
      if (!buf2)
        break;
      #  Not a symlink : we're done following
      if (buf2 !~ "^l.*")
      {
        spad_log(message:'java_inst_debug: Breaking because item is not a symlink\n');
        break;
      }

      sympath = ereg_replace(pattern:'^l[^>]+> (.*)', string:buf2, replace:"\1");
      # Some more mangling in case the symlink points to ../*
      # so we can get the correct path
      # For each ../ remove one level from the path until ../ is no longer
      # in the symlink path or we are at the root directory for path
      if (sympath =~ '^../')
      {
        spad_log(message:'java_inst_debug: Original path: ' + path + '\n');
        while (sympath =~ '^../')
        {
          path = ereg_replace(pattern:'^(/(.*/)?).*/.*', string:path, replace:"\1");
          if (path == '/')
          {
            sympath = sympath - '../';
            break;
          }
          sympath = substr(sympath, 3);
        }
	
        path = path + sympath;
        item = chomp(path);
        spad_log(message:'java_inst_debug: Modified path: ' + item + '\n');
      }
      # Absolute sympath
      else if(sympath =~ "^/(.*)$")
      {
        item = chomp(sympath);
      }
      # Symlink relative to it's parent dir
      else
      {
        path = ereg_replace(pattern:'^(.*)/[^/]+$',string:path, replace:"\1");
        item = chomp(path)+"/"+chomp(sympath);
      }
      count++;
    }
  }
  return item;
}

function safe_java_version(path,java,shell_path)
{
  spad_log(message:'java_inst_debug: Entering ' + FUNCTION_NAME + '\n');
  local_var chkorcl_ptrn, version_ptrn, # grep patterns
            version_ptrn_escaped,       # an escaped style of ver pattern (use with grep -o -a styles)
            chkorcl_cmdt, version_cmdt, # command template to run
            chkorcl_file, version_file, # files to check
            chkorcl_resp, version_resp, # responses from commands
            exclude_cmdt, exclude_resp, # variables use to check if the rt.jar contains "openjdk / icedt / ect"
            exclude_ptrn,
            version,                    # parsed version
            chkjlib_resp,               # response from running ls path+"/lib/"
            libpath,                    # the path where the lib is, needed to find runtime
            chkorcl_exists_resp;        # the response from running ls for certain files existence

  if(isnull(shell_path))
    shell_path = "/bin/bash";

  # Figure out if we're dealing with JDK or JRE
  libpath = path+"/lib/";
  chkjlib_resp = run_cmd_template_wrapper(template:shell_path+' -c "ls $1$/rt.jar" 2>&1',args:make_list(libpath));
  # If no rt.jar, look for modules instead
  if("no such file or directory" >< tolower(chkjlib_resp))
  {
    chkjlib_resp = run_cmd_template_wrapper(template:shell_path+' -c "ls $1$/modules" 2>&1',args:make_list(libpath));
    if("no such file or directory" >< tolower(chkjlib_resp))
    {
      # If no rt.jar and no modules, probably is JDK, so look lower down into its jre dir
      libpath = path+"/jre/lib/";
      chkjlib_resp = run_cmd_template_wrapper(template:shell_path+' -c "ls $1$/rt.jar" 2>&1',args:make_list(libpath));
      if("no such file or directory" >< tolower(chkjlib_resp))
      {
        # If no rt.jar in JDK, try modules
        chkjlib_resp = run_cmd_template_wrapper(template:shell_path+' -c "ls $1$/modules" 2>&1',args:make_list(libpath));
        if("no such file or directory" >< tolower(chkjlib_resp))
        {
          # No rt.jar and no modules in either of JDK nor JRE ... done here
          return FALSE;
        }
        else
        {
          # JDK without rt.jar
          chkorcl_file = libpath+"modules";
          chkorcl_ptrn = "'Copyright.*Oracle.*affiliates'";
        }
      }
      else
      {
        # JDK with rt.jar
        chkorcl_file = libpath+"rt.jar";
        chkorcl_ptrn = "'Implementation-Vendor: .*'";
      }
    }
    else
    {
      # JRE without rt.jar
      chkorcl_file = libpath+"modules";
      chkorcl_ptrn = "'Copyright.*Oracle.*affiliates'";
    }
  }
  else
  {
    # JRE with rt.jar
    chkorcl_file = libpath+"rt.jar";
    chkorcl_ptrn = "'Implementation-Vendor: .*'";
  }

  # Parse files for version information
  # The runtime (rt.jar) contains oracle / sun specific strings, the java binary
  # contains the version string itself
  #version_ptrn = "'[0-9]\.[0-9]\{1,2\}\.[0-9]\{1,2\}\(_[0-9]\{1,3\}\)\{0,1\}-b[0-9]\{1,2\}'";
  # e.g., 1.7.0_111 or 9.0.4+11 
  version_ptrn         = "'[0-9]+\.[0-9]{1,2}\.[0-9]{1,2}((_[0-9]{1,3}){0,1}-b[0-9]{1,2}|\+[0-9]+)'";
  version_ptrn_escaped = "'[0-9]\+\.[0-9]\{1,2\}\.[0-9]\{1,2\}\(\(_[0-9]\{1,3\}\)\{0,1\}-b[0-9]\{1,2\}\|+[0-9]\{1,\}\)'";
  exclude_ptrn = "-i '(OpenJDK Runtime Environment)'"; # IcedT / OpenJDK sometimes, erroneous 

  # HPUX does not have "-m" for grep
  if (get_kb_item("Host/HP-UX/version"))
  {
    chkorcl_cmdt = shell_path+" -c "+'"'+"strings $1$ | grep "+chkorcl_ptrn+'" | head -n 1';
    version_cmdt = shell_path+" -c "+'"'+"strings $1$ | grep -E "+version_ptrn+'" | head -n 1';
    exclude_cmdt = shell_path+" -c "+'"'+"strings $1$ | grep "+exclude_ptrn+'" | head -n 1';
  }
  else
  {
    chkorcl_cmdt = shell_path+" -c "+'"'+"strings $1$ | grep -m 1 "+chkorcl_ptrn+'"';
    version_cmdt = shell_path+" -c "+'"'+"strings $1$ | grep -E -m 1 "+version_ptrn+'"';
    exclude_cmdt = shell_path+" -c "+'"'+"strings $1$ | grep -m 1 "+exclude_ptrn+'"';
  }

  chkorcl_exists_resp = run_cmd_template_wrapper(template:shell_path+' -c "ls $1$" 2>&1',args:make_list(chkorcl_file));
  if ("no such file or directory" >< tolower(chkorcl_exists_resp))
    chkorcl_file = libpath+"modules";
  chkorcl_exists_resp = run_cmd_template_wrapper(template:shell_path+' -c "ls $1$" 2>&1',args:make_list(chkorcl_file));

  version_file = java;
  # Stuff without strings by default
  if ( get_kb_item("Host/Ubuntu/release") ||
       get_kb_item("Host/Debian/release") ||
       get_kb_item("Host/SuSE/release")
  )
  {
    version_cmdt  = shell_path+" -c "+'"'+"grep -o -a "+version_ptrn_escaped+" $1$"+'"';
    chkorcl_cmdt  = shell_path+" -c "+'"'+"grep -o -a "+chkorcl_ptrn+" $1$"+'"';
    exclude_cmdt  = shell_path+" -c "+'"'+"grep -o -a "+exclude_ptrn+" $1$"+'"';
  }
  # Use egrep on solaris and hpux
  if (
    get_kb_item("Host/Solaris/Version") ||
    get_kb_item("Host/Solaris11/Version") ||
    get_kb_item("Host/HP-UX/version")
  )
  {
    if (!get_kb_item("Host/HP-UX/version"))
      chkorcl_ptrn = "'Implementation-Vendor: .*'";

    version_ptrn = "'[0-9]+\.[0-9]+\.[0-9]+(_[0-9]+)?-b[0-9]+'";
    chkorcl_cmdt = shell_path+" -c "+'"'+"strings $1$ | egrep "+chkorcl_ptrn+'"';
    version_cmdt = shell_path+" -c "+'"'+"strings $1$ | egrep "+version_ptrn+'"';
    exclude_cmdt = shell_path+" -c "+'"'+"strings $1$ | egrep "+exclude_ptrn+'"';
  }

  version_resp = run_cmd_template_wrapper(template:version_cmdt,args:make_list(version_file));
  chkorcl_resp = run_cmd_template_wrapper(template:chkorcl_cmdt,args:make_list(chkorcl_file));
  exclude_resp = run_cmd_template_wrapper(template:exclude_cmdt,args:make_list(chkorcl_file));

  #In some cases, the java binary is stripped out of java by namei
  #If that happened, try sending the command again with /bin/java appended
  if (isnull(version_resp) || (!isnull(version_resp) && 'is a directory' >< tolower(version_resp)))
  {
    java += '/bin/java';
    version_file += '/bin/java';
    version_resp = run_cmd_template_wrapper(template:version_cmdt,args:make_list(version_file));
  }

  #In some cases (web apps) it's rt.pack not rt.jar
  if (!isnull(chkorcl_resp) && 'no such file' >< tolower(chkorcl_resp))
  {
    chkorcl_file = libpath+"rt.pack";
    chkorcl_resp = run_cmd_template_wrapper(template:chkorcl_cmdt,args:make_list(chkorcl_file));
    exclude_resp = run_cmd_template_wrapper(template:exclude_cmdt,args:make_list(chkorcl_file));
  }

  if("OpenJDK Runtime Environment" >< tolower(exclude_resp))
  {
    return FALSE;
  }

  if(!version_resp)
  {
    return FALSE;
  }

  # Oracle bought Sun around ~ Java v1.5
  if(chkorcl_resp !~ "(Sun Microsystems, Inc.|Oracle Corporation|Copyright.*Oracle)")
  {
    return FALSE;
  }

  # Parse and format version
  if ("_" >< version_resp)
    version = pregmatch(pattern:"(\d+\.\d+\.\d+(_\d+)?)-b\d+", string:version_resp);
  else
  {
    # 9.0.4 and up, version looks like :
    # 9.0.4+11 and so forth
    matches = pregmatch(pattern:"^([0-9]+)\.([0-9]+)\.([0-9]+)", string:version_resp);
    if (!matches)
      return FALSE;

    version = make_list("astring","1." + matches[1] + "." + matches[2] + '_' + matches[3]);
  }

  if(isnull(version))
    return FALSE;

  version = version[1];
  if(version =~ "^\d+\.\d+\.\d+$")
    version += "_0";

  # Java bin location may have been updated: return both java and version
  return make_array("version", version, "java", java);
}

##
# Attempts to find java actively running in /proc/
##
function find_paths_in_proc()
{
  spad_log(message:'java_inst_debug: Entering ' + FUNCTION_NAME + '\n');

  local_var fnd = NULL;
  local_var cmd = "ls -l /proc/*/exe 2> /dev/null | awk '/java/'";
  local_var buf = info_send_cmd(cmd:cmd);
  local_var line = NULL;

  if("command not found" >< buf)
    return make_list();

  buf = split(buf);
  foreach line (buf)
  {
    line = pregmatch(pattern:'exe[ \t]+->[ \t]+(.*java)$', string:line);
    if(!empty_or_null(line))
      fnd += line[1] + '\n';
  }
  return fnd;
}


##
# Validates ^*/bin*/java$
#  which will remove javadoc, javac, etc
##
function validate_paths(buf)
{
  spad_log(message:'java_inst_debug: Entering ' + FUNCTION_NAME + '\n');
  local_var tmp_buf, valid_paths, line, regtest;
  tmp_buf = split(buf);
  foreach line (tmp_buf)
  {
    ##
    #  Must match many cases:
    #   /bin/java
    #   /usr/bin/java
    #   /usr/bin/sparcv9/java
    #   /usr/bin/subdir1/subdir2/java
    ##
    regtest = pregmatch(pattern:"^.*\/bin\/(.*\/+)?java$", string:line);
    if (!empty_or_null(regtest) && !empty_or_null(regtest[0]))
      valid_paths += regtest[0] + '\n';
  }
  spad_log(message:'java_inst_debug: Returning ' + valid_paths + '\n');
  return valid_paths;
}


function which_java()
{
  spad_log(message:'java_inst_debug: Entering ' + FUNCTION_NAME + '\n');
  local_var buf, command;
  
  # Check for java in PATH (thorough or not)
  if (
    get_kb_item("Host/HP-UX/version") ||
    get_kb_item("Host/Solaris/Version") ||
    get_kb_item("Host/Solaris11/Version") ||
    get_kb_item("Host/FreeBSD/release") ||
    get_kb_item("Host/AIX/version")
  ) command = "which java";
  else command = "which -a java";
  spad_log(message:'java_inst_debug: calling ' + command + '\n');
  buf = info_send_cmd(cmd:command);
  spad_log(message:'java_inst_debug: Response ' + obj_rep(buf) + '\n');
  return buf;
}


function locate_java()
{
  spad_log(message:'java_inst_debug: Entering ' + FUNCTION_NAME + '\n');
  local_var buf, command;
  command = "locate --basename -r '^java$' --existing";
  spad_log(message:'java_inst_debug: calling ' + command + '\n');
  buf = info_send_cmd(cmd:command);
  spad_log(message:'java_inst_debug: Response ' + obj_rep(buf) + '\n');
  return buf;
}



function find_cmd_search_for_java(dir, partial_find_results)
{
  spad_log(message:'java_inst_debug: Entering ' + FUNCTION_NAME + '\n');
  spad_log(message:'java_inst_debug: dir is ' + dir + '\n');

  buf = NULL;

  buf = find_cmd(
    path_patterns : make_list("*/java"),
    start         : dir,
    maxdepth      : NULL,
    timeout       : 240,
    exit_on_fail  : TRUE
  );
  spad_log(message:'java_inst_debug: find_cmd() response:\n' + obj_rep(buf) + '\n');

  if (!empty_or_null(buf))
  {
    # Find command returned something but also timedout
    # results may be partial
    if (!partial_find_results)
    {
      partial_find_results = (!empty_or_null(buf[1]) && timedout);
      if (partial_find_results)
        spad_log(message:'java_inst_debug: Partial results returned while searching ' + dir + '\n');
    }


    # find_cmd failed or timed out without returning anything
    if(buf[0] != FIND_OK || (empty_or_null(buf[1]) && timedout))
    {
      # The code being updated below replaces code
      # meant to handle systems that may have had
      # problems running find().
      #
      # These systems are now handled more effectively
      # via the improved find_cmd() function

      spad_log(message:'java_inst_debug: find_cmd() call did not complete successfully while searching ' + dir + '\n');

      if (buf[0] != FIND_OK && !empty_or_null(buf[1]))
        spad_log(message:'java_inst_debug: find_cmd() call reported error: ' + buf[1] + '\n');
      if (timedout)
        spad_log(message:'java_inst_debug: find_cmd() timed out\n');

      buf = "";
    }
    else
    {
      # All good use these results
      buf = buf[1];
    }
  }

  ##
  #  Some platforms do not allow the same level
  #  of control over find_cmd() params.
  ##
  if ("javadoc" >< buf || "javac" >< buf)
  {
    buf = validate_paths(buf:buf);
  }

  ret['buf'] = buf;
  ret['partial_find_results'] = partial_find_results;
  return ret;
  
} # end of find_cmd_search_for_java()


##
#  Implementing this as a function
#   so it can be easily modified
##
function constrain_time()
{
  spad_log(message:'java_inst_debug: Entering ' + FUNCTION_NAME + '\n');
  if (!time_limit_met)
  {
    difftime = datetime::timeofday_diff(begin:starttime, end:gettimeofday());
    spad_log(message:'java_inst_debug: constrain_time difftime: ' + difftime + '\n');
    if (int(difftime) < (maxtime/4))
    {
      return TRUE;
    }
    else
    {
      spad_log(message:'java_inst_debug: Setting time_limit_met flag\n');
      time_limit_met = TRUE;
      return FALSE;
    }
  }
  else
  {
    return FALSE;
  }
}


##
#  Setup
##
app = "Oracle Java";

shell_path = "/bin/bash";
# OSes unlikely to have bash
if (get_kb_item("Host/FreeBSD/release") || get_kb_item("Host/HP-UX/version"))
  shell_path = "/bin/sh";


# Only the following OSes are currently supported
unsupported = TRUE;
if ( get_kb_item("Host/CentOS/release") ||
     get_kb_item("Host/Debian/release") ||
     get_kb_item("Host/FreeBSD/release") ||
     get_kb_item("Host/Gentoo/release") ||
     get_kb_item("Host/HP-UX/version") ||
     get_kb_item("Host/Mandrake/release") ||
     get_kb_item("Host/RedHat/release") ||
     get_kb_item("Host/Slackware/release") ||
     get_kb_item("Host/Solaris/Version") ||
     get_kb_item("Host/Solaris11/Version") ||
     get_kb_item("Host/SuSE/release") ||
     get_kb_item("Host/Ubuntu/release") ||
     get_kb_item("Host/AIX/version") ||
     get_kb_item("Host/EulerOS/release")
  ) unsupported = FALSE;

if (unsupported) exit(0, "Unix Java checks are not supported on the remote OS at this time.");

# We may support other protocols here
if ( islocalhost() )
{
 if ( ! defined_func("pread") ) audit(AUDIT_FN_UNDEF,"pread");
 info_t = INFO_LOCAL;
}
else
{
 sock_g = ssh_open_connection();
 if (! sock_g) audit(AUDIT_FN_FAIL,"ssh_open_connection");
 info_t = INFO_SSH;
}

info = "";
path_already_seen = make_array();
buffers = make_nested_array(
  'located_via_which', NULL,
  'located_via_locate', NULL,
  'located_via_proc', NULL,
  'located_via_find', NULL
);


var maxtime, difftime;
if (thorough_tests)
{
  #   3x find_cmd() calls @ 4 min timeout each
  # + (double that time) for managed_install checks
  # + additional time for cleanup
  maxtime = 1500;
}
else
{
  #   min 1x find_cmd() call @ 4 min timeout
  # + (double that time) for managed_install checks
  # + additional time for cleanup
  maxtime = 540;
}


###
##  We should spend only half our time
##  collecting java installations. Do not
##  attempt additional collections if we have
##  already spent more than 1/4 total time.
###

##
#  Find Java using 'which java' linux command
##
buffers['located_via_which'] = which_java();

##
#  Find Java using 'locate' linux command
##
if (constrain_time())
  buffers['located_via_locate'] = locate_java();
else
  spad_log(message:'java_inst_debug: Not running locate_java due to time constraints (' + difftime + ')\n');


##
#  Find Java in running processes
##
if (constrain_time())
  buffers['located_via_proc'] = find_paths_in_proc();
else
  spad_log(message:'java_inst_debug: Not running find_paths_in_proc due to time constraints (' + difftime + ')\n');


###
##  find_cmd calls
###
##
#  $PATH
##
partial_find_results = FALSE;
if (constrain_time())
{
  home = info_send_cmd(cmd:"echo $HOME 2>/dev/null");
  home = chomp(home);
  spad_log(message:'java_inst_debug: HOME env var response: ' + home + '\n');
  if (!empty_or_null(home))
  {
    envpath =  info_send_cmd(cmd:"source "+home+"/.bashrc 2>/dev/null; echo $PATH 2>/dev/null", force_priv_escl:TRUE);
    envpath = chomp(envpath);
    spad_log(message:'java_inst_debug: PATH env var response: ' + envpath + '\n');
    if (empty_or_null(envpath))
      spad_log(message:'java_inst_debug: Error returned attempting to establish $PATH');
    else
    {
      envpath = str_replace(string:envpath, find:':', replace:' ');
      ret = find_cmd_search_for_java(dir:envpath, partial_find_results:partial_find_results);
      if (!empty_or_null(ret))
      {
        if (!empty_or_null(ret['buf']))
          buffers['located_via_find'] = ret['buf'];
        if (!empty_or_null(ret['partial_find_results']))
          partial_find_results = ret['partial_find_results'];
      }
    }
  }
}
else
  spad_log(message:'java_inst_debug: Not searching for Java in $PATH due to time constraints (' + difftime + ')\n');


##
#  /usr/, /opt/
##
if (constrain_time())
{
  # Default directories to inspect
  dirs_to_check = make_list("/opt/", "/usr/");

  # OSes that frequently have find timeout because of large
  # directory structures in /usr/
  if(get_kb_item("Host/FreeBSD/release"))
    dirs_to_check = make_list("/usr/lib/", "/usr/lib34/", "/usr/lib64/", "/usr/bin/", "/usr/sbin/", "/usr/local/", "/opt/");


  ret = find_cmd_search_for_java(dir:join(dirs_to_check, sep:" "), partial_find_results:partial_find_results);
  if (empty_or_null(buffers['located_via_find']))
    buffers['located_via_find'] = ret['buf'];
  else
    buffers['located_via_find'] += ret['buf'];
  partial_find_results = ret['partial_find_results'];

}
else
  spad_log(message:'java_inst_debug: Not searching for Java in /usr/, /opt/ due to time constraints (' + difftime + ')\n');


##
#  /home/
##
if (constrain_time())
{
  ret = find_cmd_search_for_java(dir:'/home/', partial_find_results:partial_find_results);
  if (empty_or_null(buffers['located_via_find']))
    buffers['located_via_find'] = ret['buf'];
  else
    buffers['located_via_find'] += ret['buf'];
  partial_find_results = ret['partial_find_results'];
}
else
  spad_log(message:'java_inst_debug: Not searching for Java in /home  due to time constraints (' + difftime + ')\n');


spad_log(message: 'java_inst_debug: Data located : ' + obj_rep(buffers) + '\n');
difftime = datetime::timeofday_diff(begin:starttime, end:gettimeofday());
spad_log(message:'java_inst_debug: difftime after locating javas: ' + difftime + '\n');


# Nothing found; done
if ( empty_or_null(buffers['located_via_which']) &&
     empty_or_null(buffers['located_via_locate']) &&
     empty_or_null(buffers['located_via_proc']) &&
     empty_or_null(buffers['located_via_find']) )
{
  spad_log(message: 'No data located.  Exiting.\n');
  if (info_t == INFO_SSH) ssh_close_connection();
  audit(AUDIT_NOT_INST, app);
}


##
#  Remove duplication and note javas found via
#  running process.  Ordered from (potentially)
#  most relevant to least relevant
##
found_javas = make_list();
location_methods = [
  'located_via_which',
  'located_via_proc',
  'located_via_locate',
  'located_via_find'
  ];

foreach located_via (location_methods)
{
  buf = buffers[located_via];
  if ('no java in' >!< buf && 'Command not found' >!< buf)
  {
    buf = chomp(buf);
    array = split(buf);
    foreach item (array)
    {
      item = chomp(item);
      if (empty_or_null(found_javas[item]))
      {
        if (item =~ "^\/.+")
          found_javas[item] = located_via;
	else
	  spad_log(message:'java_inst_debug: not including incorrectly formatted item: ' + item + '\n');
      }
    }
  }
}

info = NULL;
foreach java (sort(keys(found_javas)))
{
  difftime = datetime::timeofday_diff(begin:starttime, end:gettimeofday());
  spad_log(message:'java_inst_debug: ####################################################\n');
  spad_log(message:'java_inst_debug: checking found java: ' + java + ' - ' + found_javas[java] + ' - ' + difftime + '\n');

  ##############################################################
  # Parse / normalize install path
  #
  item = resolve_symlink(item:java);
  spad_log(message:'java_inst_debug: resolve_symlink returned ' + item + '\n');

  path = item;
  # attempt to identify the install directory
  path = ereg_replace(pattern:"\/solr\/jre\/bin\/.*java$" , replace:"/", string:path);
  path = ereg_replace(pattern:"\/runtime\/jre\/bin\/.*java$" , replace:"/", string:path);
  path = ereg_replace(pattern:"\/jre\/bin\/.*java$" , replace:"/", string:path);

  if (path !~ '/usr/bin/java')
  {
    spad_log(message:'java_inst_debug: Original path: ' + path + '\n');
    path = ereg_replace(pattern:"\/bin\/.*java$" , replace:"/", string:path);
    spad_log(message:'java_inst_debug: Modified path: ' + path + '\n');
  }
  path = chomp(path);
  # path could also be a symlink: try to resolve it
  path = resolve_symlink(item:path);
  spad_log(message:'java_inst_debug: resolve_symlink (2) returned ' + item + '\n');

  # ensure that path ends in /
  if(path !~ "^.*/$") path += "/";

  # Optimization: skip paths containing openjdk
  # this isn't guaranteed to skip all openjdk
  # installs but at least we won't run expensive
  # commands against these dirs. And gcj. 
  if ("openjdk" >< tolower(path) ||
      "gcj" >< tolower(path)
  )
  {
    #  Enhancement RES-24466 created
    spad_log(message: 'Skipping openjdk/gcj ' + tolower(path) + '\n');
    continue;
  }

  ############################################################
  # Retrieve version information
  resp = FALSE;

  # Obtain version from located binaries
  resp = safe_java_version(path:path,java:item,shell_path:shell_path);

  # No version found for path / item -> next path / item
  if(!resp)
  {
    spad_log(message:'java_inst_debug: No response from safe_java_version()\n');
    continue;
  }

  item = resp['java'];
  ver_formatted = resp['version'];

  ############################################################
  # More Path Normalization
  #
  # Note: we'd like to be more specific in the path
  # for things like Coldfusion, Signacert, tarantella,
  # so just remove not so much of the path
  if (
    "/solr/" >< item       ||
    "/runtime/" >< item    ||
    "/signacert/" >< item
  )
    path = ereg_replace(pattern:"\/bin\/.*java$" , replace:"/", string:item);

  if ("/tarantella/" >< item)
  {
    matches = pregmatch(
      string  :item,
      pattern :"^(\/.*tarantella\/.*\/jdk\.[^/]+\/(jre\/)?)bin\/java$",
      icase   : TRUE
    );
    if (matches)
      path = matches[1];
  }

  # path + version already seen -> next path / item
  if (path_already_seen[path+ver_formatted]++)
  {
    spad_log(message:'java_inst_debug: Path already seen.  Continuing\n');
    continue;
  }

  ##
  #  Only report on temp directories if
  #   thorough_checks are enabled
  ##
  if ((path =~ "/temp/" || path =~ "/tmp/") && !thorough_tests)
    continue;

  ############################################################
  # Determine if Java is managed
  #
  managed = 0;
  cmdtarg = make_list(item, path);
  foreach cmdtarg_piece (cmdtarg)
  {
    cmdtarg_piece = make_list(preg_replace(pattern:"(^.*)(\/$)", replace:"\1", string:cmdtarg_piece));

    # check to see if the install was installed via a native package management software
    if (get_kb_item("Host/RedHat/rpm-list") || get_kb_item("Host/SuSE/rpm-list") || get_kb_item("Host/CentOS/rpm-list"))
    {
      buf2 = run_cmd_template_wrapper(template:'rpm -qf $1$',args:cmdtarg_piece);
      if ( buf2 )
        if ( ('-sun' >< buf2 || '-oracle' >< buf2 || '-fcs' >< buf2) && ("is not owned by any package" >!< buf2) && ("No such file or directory" >!< buf2) )
        {
          managed = 1;
          break;
        }
    }
    else if ( get_kb_item("Host/HP-UX/swlist") )
    {
      # this may be a bit slow, eventually we may need to find a faster solution
      buf2 = sh_commands::find('/var/adm/sw/products', '-name', 'INFO', '-exec', 'grep -il "' + cmdtarg_piece[0] + '" \'{}\' \\;');
      if (buf2[0] == sh_commands::CMD_OK)
      {
        if ( "/var/adm/sw/products/" >< buf2[1] )
        {
          managed = 1;
          break;
        }
      }
    }
    else if ( get_kb_item("Host/Solaris11/pkg-list") )
    {
      buf2 = run_cmd_template_wrapper(template:'pkg search -l -H -o pkg.name "$1$" && echo MANAGED',args:cmdtarg_piece);
      if ( buf2 )
        if ( "MANAGED" >< buf2 )
        {
          managed = 1;
          break;
        }
    }
    else if ( get_kb_item("Host/Solaris/showrev") )
    {
      buf2 = run_cmd_template_wrapper(template:'pkgchk -l -p "$1$"',args:cmdtarg_piece);
      if ( buf2 )
        if ( cmdtarg_piece[0] >< buf2 )
        {
          managed = 1;
          break;
        }
    }
    else if ( get_kb_item("Host/AIX/lslpp") )
    {
      buf2 = run_cmd_template_wrapper(template:'lslpp -w "$1$"',args:cmdtarg_piece);
      if ( buf2 )
        if ( item >< buf2 )
        {
          managed = 1;
          break;
        }
    }
  }

  # Register install information
  kb_str = "Host/Java/JRE/";
  if(oracle_bundled_java(javapath:path))
    kb_str += "Bundled/";
  else if (managed == 1)
    kb_str += "Managed/";
  else
    kb_str += "Unmanaged/";
  set_kb_item(name:kb_str+ver_formatted, value:path);

  spad_log(message: 'Adding app : ' + app + '\n');
  spad_log(message: 'Adding path : ' + path + '\n');
  spad_log(message: 'Adding version : ' + ver_formatted + '\n');
  spad_log(message: 'Adding managed : ' + managed + '\n');

  if (!managed)
    register_install(
      app_name:app,
      path:path,
      version:ver_formatted,
      display_version:ver_formatted,
      cpe:"cpe:/a:oracle:jre",
      extra_no_report:make_array('managed', managed)
    );
  else
    register_install(
      app_name:app,
      path:path,
      version:ver_formatted,
      display_version:ver_formatted,
      cpe:"cpe:/a:oracle:jre",
      extra_no_report:make_array('managed', managed),
      extra:make_array('Managed by OS', "True")
    );

  if(found_javas[java] == "located_via_proc")
  {
    info +=
    '\n  Note    : This install was discovered by checking the currently'+
    '\n            running processes on the system, and it may not always'+
    '\n            be reported in future scans.';
  }
  info += '\n';


}  # foreach java (keys(found_javas))


if (info_t == INFO_SSH) ssh_close_connection();

# Report what we found.
if (!empty_or_null(info))
{
  set_kb_item(name:"Host/Java/JRE/Installed", value:TRUE);

  if(partial_find_results)
  {
    info +=
    '\n' +
    'Note: During execution it appears that the find command timed' +
    ' out and may have only returned partial results.\n\n';
  }

  # info may contain just newlines
  if (info =~ "\S")
    report_installs(app_name:app, extra:info);
  else
    report_installs(app_name:app);

}
else
{
  audit(AUDIT_NOT_INST, app);
}

exit(0);