# -*- sh -*-
# This script is copyright 2004 Michel Arboi <mikhail@nessus.org>
# It is released under the GNU Public Licence (GPLv2)
# $Revision: 1.3 $

global_var	qpkg_list;

function qpkg_ver_cmp(ver, ref, op)
{
  local_var	inf, sup, eq;
  local_var	r, v, i, n, nr, nv;


  # Easy cases: identity
  if (op == '=')
   if (ver == ref) return 1; else return -1;
  if (ver == ref)
    if ('=' >< op) return 1; else return -1;

  if (op == '<' || op == '<=') { inf = 1; sup = -1; } else { inf = -1; sup = 1; }
  if ('=' >< op) { eq = 1; } else { eq = -1; }
  
  # -r0 treatement
  v = eregmatch(string: ref, icase: 0, pattern: '^(.+)-r([0-9])+$');
  if (isnull(v)) { ref_base = ref; ref_r = 0; }
  else { ref_base = v[1]; ref_r = int(v[2]); }

  v = eregmatch(string: ver, icase: 0, pattern: '^(.+)-r([0-9])+$');
  if (isnull(v)) { ver_base = ver; ver_r = 0; }
  else { ver_base = v[1]; ver_r = int(v[2]); }

  if (ver_base == ref_base)
    if  (ver_r < ref_r) return inf;
    else if (ver_r == ref_r) return eq;
    else return sup;

  if (ref_base =~ "^[0-9]{4}\.?[0-9]{2}\.?[0-9]{2}$")	# Date
    if (ver_base !~ "^[0-9]{4}\.?[0-9]{2}\.?[0-9]{2}$")
    {
      display("qpkg_ver_cmp: do not know how to compare a date to something else\n");
      return;
    }
    else
    {
      ref_base = int(ereg_replace(string: ref_base, pattern: ".", replace: ""));
      ver_base = int(ereg_replace(string: ref_base, pattern: ".", replace: ""));
      if (ver_base < ref_base) return inf;
      else if (ver_base > ref_base) return sup;
      else return eq;
    }

  if (ver =~ "^[0-9.]+" && ref =~ "^[0-9.]+")
  {
    v = split(ver, sep: '.');
    r = split(ref, sep: '.');
    nv = max_index(v); nr = max_index(r);
    if (nv < nr) n = nv; else n = nr;
    for (i = 0; i < n; i ++)
     if (int(v[i]) < int(r[i])) return inf;
     else if (int(v[i]) > int(r[i])) return sup;
    # 1.6.3.1 > 1.6.3
    if (nv < nr) return inf;
    else if (nv > nr) return sup;
    else return eq;
  }

  display("qpkg_ver_cmp: do not known how to compare  ", ver, " ",op, " ", ref, "\n");
  return;
}

# Retuns 1 if surely matches, -1 if surely does not match, NULL or 0 otherwise
function qpkg_cmp(pkg)
{
  local_var	v, cmp, name, ver, ver2, from_qpkg;

  v = split(pkg, sep: ' ');

  if (max_index(v) != 3) { display("qpkg_cmp: bad format: ", pkg, "\n"); return;}

  cmp = chomp(v[0]); name = chomp(v[1]); ver = chomp(v[2]);
  #nameRE = escape_string(str: name);
  from_qpkg = chomp(egrep(string: qpkg_list, pattern: name));
  if (! from_qpkg) return -1;
  v = eregmatch(string: from_qpkg, icase: 1, 
                pattern: '^[a-z0-9-]+/([a-z-]|[^-][0-9])+-([0-9a-z.-]+)$');
  if (isnull(v))
  {
    display("qpkg_cmp: cannot parse ", from_qpkg, "\n");
    return;
  }
  ver2 = v[2];
  return qpkg_ver_cmp(ver: ver2, ref: ver, op: cmp);
}

function qpkg_check(vulnerable, unaffected)
{
  local_var	f1, f2;

# qpkg_list = pread(cmd: "qpkg", argv: [ "qpkg", "-nc", "-I", "-v"]);

  if (! qpkg_list) qpkg_list = get_kb_item("Host/Gentoo/qpkg-list");
  if (! qpkg_list) { display("No Gentoo packages!\n"); return; }

  # Package is not installed  
  f1 = qpkg_cmp(pkg: unaffected);
  f2 = qpkg_cmp(pkg: vulnerable);

  if (! f1 && ! f2) return;
  if (f1 == -1 && f2 == -1) return;	# Not installed?

  if (f1 == f2)
  {
    display("qpkg_check: bug or inconsistency in calling script. System cannot be both affected AND unaffected\n");
    return;
  }
  if (f2 == 1 || f1 == -1) return 1;
  if (f1 == 1 || f2 == -1) return 0;
  display("qpkg_check: bug or inconsistency in calling script. Cannot decide\n");
  return;
}
