/*	$CoreSDI: version.c,v 1.6 2001/10/10 00:30:11 claudio Exp $	*/

/*
 *   Copyright (c) 2000, 2001, Core SDI S.A., Argentina
 *   All rights reserved
 *  
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *  
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *   3. Neither name of the Core SDI S.A. nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *  
 *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Version handling functions.
 * Author: Claudio Castiglia
 */

#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#ifdef __linux__
#include <netinet/in.h>		/* in_addr_t */
#endif

#ifndef	WIN32
#include <sysexits.h>
#else	
#include "exits.h"
#include "winsyslog.h"
#endif /* WIN32 */

#include "sysdep.h"
#include "packet.h"
#include "version.h"
#include "log.h"


/*
 * Extract version numbers (major and minor) from specified string;
 * returns 0 on success or -1 on error (invalid version number).
 */
int
extract_version_numbers(const char *ver, int *major, int *minor)
{
	char	*ma, *mi, *err, version[10];
	long	 i;

	if (version == NULL) {
		errno = EINVAL;
		return (-1);
	}

	strlcpy(version, ver, sizeof(version));
	mi = version;
	ma = strsep(&mi, "."); 
	if (ma != NULL && major != NULL) {
		i = strtol(ma, &err, 10);
		if (*err != '\0' || i == LONG_MIN || i == LONG_MAX)
			return (-1);
		*major = (int)i;
	}
	if (mi != NULL && minor != NULL) {
		i = strtol(mi, &err, 10);
		if (*err != '\0' || i == LONG_MIN || i == LONG_MAX)
			return (-1);
		*minor = (int)i;
	}
	return (0);
}


/*
 * id_exchange()
 *	Exchange identification strings;
 *	return 0 on success and -1 on error;
 *	abort program execution on protocol violation.
 */
int
id_exchange(PACKET *p, int *his_major, int *his_minor)
{
	char msg[20] = { "audit-" };

	if (p == NULL || his_major == NULL || his_minor == NULL) {
		errno = EINVAL;
		return (-1);
	}

	/* Send our identification string, receive peer's */
	strlcat(msg, AUDIT_VERSION, sizeof(msg));
	packet_put_string(p, msg);
	packet_get_string(p, msg, sizeof(msg));

	/* Check and extract peer's version numbers */
	if (!strncmp("audit-", msg, 6))
		if (!extract_version_numbers(msg + 6, his_major, his_minor))
			return (0);

	fatal(EX_PROTOCOL, "Protocol violation: "
	    "Invalid identification string: '%s'.", msg);
	/* NOTREACHED */

	return (-1);
}




/*
 * compatible_peer()
 *	Exchange version numbers and check compatibility;
 *	return nonzero value if compatible and 0 if not.
 */
int
compatible_peer(PACKET *p)
{
	int my_major, my_minor, his_major, his_minor;

	if (extract_version_numbers(AUDIT_VERSION, &my_major, &my_minor) < 0) {
		fatal(EX_SOFTWARE, "Invalid internal id: '%s'.", AUDIT_VERSION);
		/* NOTREACHED */
	}

	if (id_exchange(p, &his_major, &his_minor) < 0) {
		fatal(EX_SOFTWARE, "Unknown error: %s.", strerror(errno));
		/* NOTREACHED */
	}

	log_debug("my version: %d.%d, his version: %d.%d.", my_major, my_minor,
	    his_major, his_minor);

	/* Check compatibility */
	return ((my_major == his_major) && (my_minor == his_minor));
}

