Blame src/OVAL/results/oval_cmp_evr_string.c

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
}