|
Packit |
517ee8 |
/*
|
|
Packit |
517ee8 |
* Copyright 2009--2013 Red Hat Inc., Durham, North Carolina.
|
|
Packit |
517ee8 |
* All Rights Reserved.
|
|
Packit |
517ee8 |
*
|
|
Packit |
517ee8 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
517ee8 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
517ee8 |
* License as published by the Free Software Foundation; either
|
|
Packit |
517ee8 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
517ee8 |
*
|
|
Packit |
517ee8 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
517ee8 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
517ee8 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
517ee8 |
* Lesser General Public License for more details.
|
|
Packit |
517ee8 |
*
|
|
Packit |
517ee8 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
517ee8 |
* License along with this library; if not, write to the Free Software
|
|
Packit |
517ee8 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
517ee8 |
*
|
|
Packit |
517ee8 |
* Authors:
|
|
Packit |
517ee8 |
* "Peter Vrabec" <pvrabec@redhat.com>
|
|
Packit |
517ee8 |
* Šimon Lukašík
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
517ee8 |
#include <config.h>
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#include <stdlib.h>
|
|
Packit |
517ee8 |
#include <stdio.h>
|
|
Packit |
517ee8 |
#include <math.h>
|
|
Packit |
517ee8 |
#include <string.h>
|
|
Packit |
517ee8 |
#include <ctype.h>
|
|
Packit |
517ee8 |
#include "oval_cmp_evr_string_impl.h"
|
|
Packit |
517ee8 |
#include "oval_definitions.h"
|
|
Packit |
517ee8 |
#include "oval_types.h"
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#include "common/_error.h"
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#ifdef HAVE_RPMVERCMP
|
|
Packit |
517ee8 |
#include <rpm/rpmlib.h>
|
|
Packit |
517ee8 |
#else
|
|
Packit |
517ee8 |
#ifdef OS_WINDOWS
|
|
Packit |
517ee8 |
#include <malloc.h>
|
|
Packit |
517ee8 |
#elif !defined(OS_FREEBSD)
|
|
Packit |
517ee8 |
#include <alloca.h>
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
static int rpmvercmp(const char *a, const char *b);
|
|
Packit |
517ee8 |
static int risdigit(int c) {
|
|
Packit |
517ee8 |
// locale independent
|
|
Packit |
517ee8 |
return (c >= '0' && c <= '9');
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static inline int rpmevrcmp(const char *a, const char *b);
|
|
Packit |
517ee8 |
static int compare_values(const char *str1, const char *str2);
|
|
Packit |
517ee8 |
static void parseEVR(char *evr, const char **ep, const char **vp, const char **rp);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
oval_result_t oval_evr_string_cmp(const char *state, const char *sys, oval_operation_t operation)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
int result = rpmevrcmp(sys, state);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (operation == OVAL_OPERATION_EQUALS) {
|
|
Packit |
517ee8 |
return ((result == 0) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_NOT_EQUAL) {
|
|
Packit |
517ee8 |
return ((result != 0) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_GREATER_THAN) {
|
|
Packit |
517ee8 |
return ((result == 1) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_GREATER_THAN_OR_EQUAL) {
|
|
Packit |
517ee8 |
return ((result != -1) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_LESS_THAN) {
|
|
Packit |
517ee8 |
return ((result == -1) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_LESS_THAN_OR_EQUAL) {
|
|
Packit |
517ee8 |
return ((result != 1) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
oscap_seterr(OSCAP_EFAMILY_OVAL, "Invalid type of operation in rpm version comparison: %d.", operation);
|
|
Packit |
517ee8 |
return OVAL_RESULT_ERROR;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static inline int rpmevrcmp(const char *a, const char *b)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
/* This mimics rpmevrcmp which is not exported by rpmlib version 4.
|
|
Packit |
517ee8 |
* Code inspired by rpm.labelCompare() from rpm4/python/header-py.c
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
const char *a_epoch, *a_version, *a_release;
|
|
Packit |
517ee8 |
const char *b_epoch, *b_version, *b_release;
|
|
Packit |
517ee8 |
char *a_copy, *b_copy;
|
|
Packit |
517ee8 |
int result;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
a_copy = oscap_strdup(a);
|
|
Packit |
517ee8 |
b_copy = oscap_strdup(b);
|
|
Packit |
517ee8 |
parseEVR(a_copy, &a_epoch, &a_version, &a_release);
|
|
Packit |
517ee8 |
parseEVR(b_copy, &b_epoch, &b_version, &b_release);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
result = compare_values(a_epoch, b_epoch);
|
|
Packit |
517ee8 |
if (!result) {
|
|
Packit |
517ee8 |
result = compare_values(a_version, b_version);
|
|
Packit |
517ee8 |
if (!result)
|
|
Packit |
517ee8 |
result = compare_values(a_release, b_release);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
free(a_copy);
|
|
Packit |
517ee8 |
free(b_copy);
|
|
Packit |
517ee8 |
return result;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static int compare_values(const char *str1, const char *str2)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
/*
|
|
Packit |
517ee8 |
* Code copied from rpm4/python/header-py.c
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
if (!str1 && !str2)
|
|
Packit |
517ee8 |
return 0;
|
|
Packit |
517ee8 |
else if (str1 && !str2)
|
|
Packit |
517ee8 |
return 1;
|
|
Packit |
517ee8 |
else if (!str1 && str2)
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
return rpmvercmp(str1, str2);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static void parseEVR(char *evr, const char **ep, const char **vp, const char **rp)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
/*
|
|
Packit |
517ee8 |
* Code copied from rpm4/lib/rpmds.c
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
const char *epoch;
|
|
Packit |
517ee8 |
const char *version; /* assume only version is present */
|
|
Packit |
517ee8 |
const char *release;
|
|
Packit |
517ee8 |
char *s, *se;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
s = evr;
|
|
Packit |
517ee8 |
while (*s && risdigit(*s)) s++; /* s points to epoch terminator */
|
|
Packit |
517ee8 |
se = strrchr(s, '-'); /* se points to version terminator */
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (*s == ':') {
|
|
Packit |
517ee8 |
epoch = evr;
|
|
Packit |
517ee8 |
*s++ = '\0';
|
|
Packit |
517ee8 |
version = s;
|
|
Packit |
517ee8 |
if (*epoch == '\0')
|
|
Packit |
517ee8 |
epoch = "0";
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
epoch = NULL; /* XXX disable epoch compare if missing */
|
|
Packit |
517ee8 |
version = evr;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (se) {
|
|
Packit |
517ee8 |
*se++ = '\0';
|
|
Packit |
517ee8 |
release = se;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
release = NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (ep) *ep = epoch;
|
|
Packit |
517ee8 |
if (vp) *vp = version;
|
|
Packit |
517ee8 |
if (rp) *rp = release;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#ifndef HAVE_RPMVERCMP
|
|
Packit |
517ee8 |
/*
|
|
Packit |
517ee8 |
* code from http://rpm.org/api/4.4.2.2/rpmvercmp_8c-source.html
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* compare alpha and numeric segments of two versions */
|
|
Packit |
517ee8 |
/* return 1: a is newer than b */
|
|
Packit |
517ee8 |
/* 0: a and b are the same version */
|
|
Packit |
517ee8 |
/* -1: b is newer than a */
|
|
Packit |
517ee8 |
static int rpmvercmp(const char *a, const char *b)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
char oldch1, oldch2;
|
|
Packit |
517ee8 |
char *str1, *str2;
|
|
Packit |
517ee8 |
char *one, *two;
|
|
Packit |
517ee8 |
int rc;
|
|
Packit |
517ee8 |
int isnum;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* easy comparison to see if versions are identical */
|
|
Packit |
517ee8 |
if (!strcmp(a, b))
|
|
Packit |
517ee8 |
return 0;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* TODO: make new malloca */
|
|
Packit |
517ee8 |
str1 = alloca(strlen(a) + 1);
|
|
Packit |
517ee8 |
str2 = alloca(strlen(b) + 1);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
strcpy(str1, a);
|
|
Packit |
517ee8 |
strcpy(str2, b);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
one = str1;
|
|
Packit |
517ee8 |
two = str2;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* loop through each version segment of str1 and str2 and compare them */
|
|
Packit |
517ee8 |
while (*one && *two) {
|
|
Packit |
517ee8 |
while (*one && !isalnum(*one))
|
|
Packit |
517ee8 |
one++;
|
|
Packit |
517ee8 |
while (*two && !isalnum(*two))
|
|
Packit |
517ee8 |
two++;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* If we ran to the end of either, we are finished with the loop */
|
|
Packit |
517ee8 |
if (!(*one && *two))
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
str1 = one;
|
|
Packit |
517ee8 |
str2 = two;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* grab first completely alpha or completely numeric segment */
|
|
Packit |
517ee8 |
/* leave one and two pointing to the start of the alpha or numeric */
|
|
Packit |
517ee8 |
/* segment and walk str1 and str2 to end of segment */
|
|
Packit |
517ee8 |
if (isdigit(*str1)) {
|
|
Packit |
517ee8 |
while (*str1 && isdigit(*str1))
|
|
Packit |
517ee8 |
str1++;
|
|
Packit |
517ee8 |
while (*str2 && isdigit(*str2))
|
|
Packit |
517ee8 |
str2++;
|
|
Packit |
517ee8 |
isnum = 1;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
while (*str1 && isalpha(*str1))
|
|
Packit |
517ee8 |
str1++;
|
|
Packit |
517ee8 |
while (*str2 && isalpha(*str2))
|
|
Packit |
517ee8 |
str2++;
|
|
Packit |
517ee8 |
isnum = 0;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* save character at the end of the alpha or numeric segment */
|
|
Packit |
517ee8 |
/* so that they can be restored after the comparison */
|
|
Packit |
517ee8 |
oldch1 = *str1;
|
|
Packit |
517ee8 |
*str1 = '\0';
|
|
Packit |
517ee8 |
oldch2 = *str2;
|
|
Packit |
517ee8 |
*str2 = '\0';
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* this cannot happen, as we previously tested to make sure that */
|
|
Packit |
517ee8 |
/* the first string has a non-null segment */
|
|
Packit |
517ee8 |
if (one == str1)
|
|
Packit |
517ee8 |
return -1; /* arbitrary */
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* take care of the case where the two version segments are */
|
|
Packit |
517ee8 |
/* different types: one numeric, the other alpha (i.e. empty) */
|
|
Packit |
517ee8 |
/* numeric segments are always newer than alpha segments */
|
|
Packit |
517ee8 |
/* result_test See patch #60884 (and details) from bugzilla #50977. */
|
|
Packit |
517ee8 |
if (two == str2)
|
|
Packit |
517ee8 |
return (isnum ? 1 : -1);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (isnum) {
|
|
Packit |
517ee8 |
/* this used to be done by converting the digit segments */
|
|
Packit |
517ee8 |
/* to ints using atoi() - it's changed because long */
|
|
Packit |
517ee8 |
/* digit segments can overflow an int - this should fix that. */
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* throw away any leading zeros - it's a number, right? */
|
|
Packit |
517ee8 |
while (*one == '0')
|
|
Packit |
517ee8 |
one++;
|
|
Packit |
517ee8 |
while (*two == '0')
|
|
Packit |
517ee8 |
two++;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* whichever number has more digits wins */
|
|
Packit |
517ee8 |
if (strlen(one) > strlen(two))
|
|
Packit |
517ee8 |
return 1;
|
|
Packit |
517ee8 |
if (strlen(two) > strlen(one))
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* strcmp will return which one is greater - even if the two */
|
|
Packit |
517ee8 |
/* segments are alpha or if they are numeric. don't return */
|
|
Packit |
517ee8 |
/* if they are equal because there might be more segments to */
|
|
Packit |
517ee8 |
/* compare */
|
|
Packit |
517ee8 |
rc = strcmp(one, two);
|
|
Packit |
517ee8 |
if (rc)
|
|
Packit |
517ee8 |
return (rc < 1 ? -1 : 1);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* restore character that was replaced by null above */
|
|
Packit |
517ee8 |
*str1 = oldch1;
|
|
Packit |
517ee8 |
one = str1;
|
|
Packit |
517ee8 |
*str2 = oldch2;
|
|
Packit |
517ee8 |
two = str2;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
/* this catches the case where all numeric and alpha segments have */
|
|
Packit |
517ee8 |
/* compared identically but the segment sepparating characters were */
|
|
Packit |
517ee8 |
/* different */
|
|
Packit |
517ee8 |
if ((!*one) && (!*two))
|
|
Packit |
517ee8 |
return 0;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* whichever version still has characters left over wins */
|
|
Packit |
517ee8 |
if (!*one)
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
else
|
|
Packit |
517ee8 |
return 1;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit Bot |
61bab5 |
/*
|
|
Packit Bot |
61bab5 |
* based on code from dpkg: lib/dpkg/version.c
|
|
Packit Bot |
61bab5 |
* Mino changes to use isdigit() and isalpha()
|
|
Packit Bot |
61bab5 |
*/
|
|
Packit Bot |
61bab5 |
/**
|
|
Packit Bot |
61bab5 |
* Give a weight to the character to order in the version comparison.
|
|
Packit Bot |
61bab5 |
*
|
|
Packit Bot |
61bab5 |
* @param c An ASCII character.
|
|
Packit Bot |
61bab5 |
*/
|
|
Packit Bot |
61bab5 |
static int order(int c)
|
|
Packit Bot |
61bab5 |
{
|
|
Packit Bot |
61bab5 |
if (isdigit(c))
|
|
Packit Bot |
61bab5 |
return 0;
|
|
Packit Bot |
61bab5 |
else if (isalpha(c))
|
|
Packit Bot |
61bab5 |
return c;
|
|
Packit Bot |
61bab5 |
else if (c == '~')
|
|
Packit Bot |
61bab5 |
return -1;
|
|
Packit Bot |
61bab5 |
else if (c)
|
|
Packit Bot |
61bab5 |
return c + 256;
|
|
Packit Bot |
61bab5 |
else
|
|
Packit Bot |
61bab5 |
return 0;
|
|
Packit Bot |
61bab5 |
}
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
/*
|
|
Packit Bot |
61bab5 |
* based on code from dpkg: lib/dpkg/version.c
|
|
Packit Bot |
61bab5 |
* Minor changes to use isdigit()
|
|
Packit Bot |
61bab5 |
*/
|
|
Packit Bot |
61bab5 |
static int verrevcmp(const char *a, const char *b)
|
|
Packit Bot |
61bab5 |
{
|
|
Packit Bot |
61bab5 |
if (a == NULL)
|
|
Packit Bot |
61bab5 |
a = "";
|
|
Packit Bot |
61bab5 |
if (b == NULL)
|
|
Packit Bot |
61bab5 |
b = "";
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
while (*a || *b) {
|
|
Packit Bot |
61bab5 |
int first_diff = 0;
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
while ((*a && !isdigit(*a)) || (*b && !isdigit(*b))) {
|
|
Packit Bot |
61bab5 |
int ac = order(*a);
|
|
Packit Bot |
61bab5 |
int bc = order(*b);
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
if (ac != bc)
|
|
Packit Bot |
61bab5 |
return ac - bc;
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
a++;
|
|
Packit Bot |
61bab5 |
b++;
|
|
Packit Bot |
61bab5 |
}
|
|
Packit Bot |
61bab5 |
while (*a == '0')
|
|
Packit Bot |
61bab5 |
a++;
|
|
Packit Bot |
61bab5 |
while (*b == '0')
|
|
Packit Bot |
61bab5 |
b++;
|
|
Packit Bot |
61bab5 |
while (isdigit(*a) && isdigit(*b)) {
|
|
Packit Bot |
61bab5 |
if (!first_diff)
|
|
Packit Bot |
61bab5 |
first_diff = *a - *b;
|
|
Packit Bot |
61bab5 |
a++;
|
|
Packit Bot |
61bab5 |
b++;
|
|
Packit Bot |
61bab5 |
}
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
if (isdigit(*a))
|
|
Packit Bot |
61bab5 |
return 1;
|
|
Packit Bot |
61bab5 |
if (isdigit(*b))
|
|
Packit Bot |
61bab5 |
return -1;
|
|
Packit Bot |
61bab5 |
if (first_diff)
|
|
Packit Bot |
61bab5 |
return first_diff;
|
|
Packit Bot |
61bab5 |
}
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
return 0;
|
|
Packit Bot |
61bab5 |
}
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
/*
|
|
Packit Bot |
61bab5 |
* Code copied from lib/dpkg/version.c
|
|
Packit Bot |
61bab5 |
*/
|
|
Packit Bot |
61bab5 |
/**
|
|
Packit Bot |
61bab5 |
* Compares two Debian versions.
|
|
Packit Bot |
61bab5 |
*
|
|
Packit Bot |
61bab5 |
* This function follows the convention of the comparator functions used by
|
|
Packit Bot |
61bab5 |
* qsort().
|
|
Packit Bot |
61bab5 |
*
|
|
Packit Bot |
61bab5 |
* @see deb-version(5)
|
|
Packit Bot |
61bab5 |
*
|
|
Packit Bot |
61bab5 |
* @param a The first version.
|
|
Packit Bot |
61bab5 |
* @param b The second version.
|
|
Packit Bot |
61bab5 |
*
|
|
Packit Bot |
61bab5 |
* @retval 0 If a and b are equal.
|
|
Packit Bot |
61bab5 |
* @retval <0 If a is smaller than b.
|
|
Packit Bot |
61bab5 |
* @retval >0 If a is greater than b.
|
|
Packit Bot |
61bab5 |
*/
|
|
Packit Bot |
61bab5 |
static int dpkg_version_compare(struct dpkg_version *a, struct dpkg_version *b)
|
|
Packit Bot |
61bab5 |
{
|
|
Packit Bot |
61bab5 |
int rc;
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
if (a->epoch > b->epoch)
|
|
Packit Bot |
61bab5 |
return 1;
|
|
Packit Bot |
61bab5 |
if (a->epoch < b->epoch)
|
|
Packit Bot |
61bab5 |
return -1;
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
rc = verrevcmp(a->version, b->version);
|
|
Packit Bot |
61bab5 |
if (rc)
|
|
Packit Bot |
61bab5 |
return rc;
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
return verrevcmp(a->revision, b->revision);
|
|
Packit Bot |
61bab5 |
}
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
oval_result_t oval_debian_evr_string_cmp(const char *state, const char *sys, oval_operation_t operation)
|
|
Packit Bot |
61bab5 |
{
|
|
Packit Bot |
61bab5 |
struct dpkg_version a, b;
|
|
Packit Bot |
61bab5 |
const char *a_epoch, *a_version, *a_release;
|
|
Packit Bot |
61bab5 |
const char *b_epoch, *b_version, *b_release;
|
|
Packit Bot |
61bab5 |
char *a_copy, *b_copy;
|
|
Packit Bot |
61bab5 |
long aux;
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
a_copy = oscap_strdup(sys);
|
|
Packit Bot |
61bab5 |
b_copy = oscap_strdup(state);
|
|
Packit Bot |
61bab5 |
parseEVR(a_copy, &a_epoch, &a_version, &a_release);
|
|
Packit Bot |
61bab5 |
parseEVR(b_copy, &b_epoch, &b_version, &b_release);
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
if (!a_epoch || !b_epoch) {
|
|
Packit Bot |
61bab5 |
oscap_seterr(OSCAP_EFAMILY_OVAL, "Invalid epoch.");
|
|
Packit Bot |
61bab5 |
free(a_copy);
|
|
Packit Bot |
61bab5 |
free(b_copy);
|
|
Packit Bot |
61bab5 |
return OVAL_RESULT_ERROR;
|
|
Packit Bot |
61bab5 |
}
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
aux = strtol(a_epoch, NULL, 10);
|
|
Packit Bot |
61bab5 |
if (aux < INT_MIN || aux > INT_MAX) {
|
|
Packit Bot |
61bab5 |
free(a_copy);
|
|
Packit Bot |
61bab5 |
free(b_copy);
|
|
Packit Bot |
61bab5 |
return OVAL_RESULT_ERROR; // Outside int range
|
|
Packit Bot |
61bab5 |
}
|
|
Packit Bot |
61bab5 |
a.epoch = (int) aux;
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
aux = strtol(b_epoch, NULL, 10);
|
|
Packit Bot |
61bab5 |
if (aux < INT_MIN || aux > INT_MAX) {
|
|
Packit Bot |
61bab5 |
free(a_copy);
|
|
Packit Bot |
61bab5 |
free(b_copy);
|
|
Packit Bot |
61bab5 |
return OVAL_RESULT_ERROR; // Outside int range
|
|
Packit Bot |
61bab5 |
}
|
|
Packit Bot |
61bab5 |
b.epoch = (int) aux;
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
a.version = a_version;
|
|
Packit Bot |
61bab5 |
a.revision = a_release;
|
|
Packit Bot |
61bab5 |
b.version = b_version;
|
|
Packit Bot |
61bab5 |
b.revision = b_release;
|
|
Packit Bot |
61bab5 |
int result = dpkg_version_compare(&a, &b);
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
free(a_copy);
|
|
Packit Bot |
61bab5 |
free(b_copy);
|
|
Packit Bot |
61bab5 |
switch (operation) {
|
|
Packit Bot |
61bab5 |
case OVAL_OPERATION_EQUALS:
|
|
Packit Bot |
61bab5 |
return ((result == 0) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit Bot |
61bab5 |
case OVAL_OPERATION_NOT_EQUAL:
|
|
Packit Bot |
61bab5 |
return ((result != 0) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit Bot |
61bab5 |
case OVAL_OPERATION_GREATER_THAN:
|
|
Packit Bot |
61bab5 |
return ((result > 0) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit Bot |
61bab5 |
case OVAL_OPERATION_GREATER_THAN_OR_EQUAL:
|
|
Packit Bot |
61bab5 |
return ((result >= 0) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit Bot |
61bab5 |
case OVAL_OPERATION_LESS_THAN:
|
|
Packit Bot |
61bab5 |
return ((result < 0) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit Bot |
61bab5 |
case OVAL_OPERATION_LESS_THAN_OR_EQUAL:
|
|
Packit Bot |
61bab5 |
return ((result <= 0) ? OVAL_RESULT_TRUE : OVAL_RESULT_FALSE);
|
|
Packit Bot |
61bab5 |
default:
|
|
Packit Bot |
61bab5 |
oscap_seterr(OSCAP_EFAMILY_OVAL, "Invalid type of operation in rpm version comparison: %d.", operation);
|
|
Packit Bot |
61bab5 |
}
|
|
Packit Bot |
61bab5 |
|
|
Packit Bot |
61bab5 |
return OVAL_RESULT_ERROR;
|
|
Packit Bot |
61bab5 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
oval_result_t oval_versiontype_cmp(const char *state, const char *syschar, oval_operation_t operation)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
int state_idx = 0;
|
|
Packit |
517ee8 |
int sys_idx = 0;
|
|
Packit |
517ee8 |
int result = -1;
|
|
Packit |
517ee8 |
/* int is_equal = 1; */
|
|
Packit |
517ee8 |
for (state_idx = 0, sys_idx = 0; (((state[state_idx]) || (syschar[sys_idx])) && (result == -1));) { // keep going as long as there is data in either the state or sysitem
|
|
Packit |
517ee8 |
int tmp_state_int, tmp_sys_int;
|
|
Packit |
517ee8 |
tmp_state_int = atoi(&state[state_idx]); // look at the current data field (if we're at the end, atoi should return 0)
|
|
Packit |
517ee8 |
tmp_sys_int = atoi(&syschar[sys_idx]);
|
|
Packit |
517ee8 |
/* o rly?
|
|
Packit |
517ee8 |
if (tmp_state_int != tmp_sys_int)
|
|
Packit |
517ee8 |
is_equal = 0; // we might need this later (if we don't terminate early)
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
if (operation == OVAL_OPERATION_EQUALS) {
|
|
Packit |
517ee8 |
if (tmp_state_int != tmp_sys_int)
|
|
Packit |
517ee8 |
return (OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_NOT_EQUAL) {
|
|
Packit |
517ee8 |
if (tmp_state_int != tmp_sys_int)
|
|
Packit |
517ee8 |
return (OVAL_RESULT_TRUE);
|
|
Packit |
517ee8 |
} else if ((operation == OVAL_OPERATION_GREATER_THAN)
|
|
Packit |
517ee8 |
|| (operation == OVAL_OPERATION_GREATER_THAN_OR_EQUAL)) {
|
|
Packit |
517ee8 |
if (tmp_sys_int > tmp_state_int)
|
|
Packit |
517ee8 |
return (OVAL_RESULT_TRUE);
|
|
Packit |
517ee8 |
if (tmp_sys_int < tmp_state_int)
|
|
Packit |
517ee8 |
return (OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else if ((operation == OVAL_OPERATION_LESS_THAN)
|
|
Packit |
517ee8 |
|| (operation == OVAL_OPERATION_LESS_THAN_OR_EQUAL)) {
|
|
Packit |
517ee8 |
if (tmp_sys_int < tmp_state_int)
|
|
Packit |
517ee8 |
return (OVAL_RESULT_TRUE);
|
|
Packit |
517ee8 |
if (tmp_sys_int > tmp_state_int)
|
|
Packit |
517ee8 |
return (OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
oscap_seterr(OSCAP_EFAMILY_OVAL, "Invalid type of operation in version comparison: %d.", operation);
|
|
Packit |
517ee8 |
return OVAL_RESULT_ERROR;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (state[state_idx])
|
|
Packit |
517ee8 |
++state_idx;
|
|
Packit |
517ee8 |
/* move to the next field within the version string (if there is one) */
|
|
Packit |
517ee8 |
while ((state[state_idx]) && (isdigit(state[state_idx])))
|
|
Packit |
517ee8 |
++state_idx;
|
|
Packit |
517ee8 |
if ((state[state_idx]) && (!isdigit(state[state_idx])))
|
|
Packit |
517ee8 |
++state_idx;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (syschar[sys_idx])
|
|
Packit |
517ee8 |
++sys_idx;
|
|
Packit |
517ee8 |
/* move to the next field within the version string (if there is one) */
|
|
Packit |
517ee8 |
while ((syschar[sys_idx]) && (isdigit(syschar[sys_idx])))
|
|
Packit |
517ee8 |
++sys_idx;
|
|
Packit |
517ee8 |
if ((syschar[sys_idx]) && (!isdigit(syschar[sys_idx])))
|
|
Packit |
517ee8 |
++sys_idx;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
// OK, we did not terminate early, and we're out of data, so we now know what to return
|
|
Packit |
517ee8 |
if (operation == OVAL_OPERATION_EQUALS) {
|
|
Packit |
517ee8 |
return (OVAL_RESULT_TRUE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_NOT_EQUAL) {
|
|
Packit |
517ee8 |
return (OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_GREATER_THAN) {
|
|
Packit |
517ee8 |
return (OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_GREATER_THAN_OR_EQUAL) {
|
|
Packit |
517ee8 |
return (OVAL_RESULT_TRUE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_LESS_THAN) {
|
|
Packit |
517ee8 |
return (OVAL_RESULT_FALSE);
|
|
Packit |
517ee8 |
} else if (operation == OVAL_OPERATION_LESS_THAN_OR_EQUAL) {
|
|
Packit |
517ee8 |
return (OVAL_RESULT_TRUE);
|
|
Packit |
517ee8 |
} // we have already filtered out the invalid ones
|
|
Packit |
517ee8 |
assert(0);
|
|
Packit |
517ee8 |
return OVAL_RESULT_ERROR;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
}
|