/*
* Copyright (c) 2004, 2005 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: sm-conf-type-ipv4.c,v 1.7 2006/01/09 19:06:25 ca Exp $")
#if SM_LIBCONF_ALONE
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include "sm-conf.h"
#include "sm-util.h"
#else /* SM_LIBCONF_ALONE */
#include "sm/limits.h"
#include "sm/error.h"
#include "sm/ctype.h"
#include "sm/memops.h"
#include "sm/string.h"
#include "sm/sm-conf.h"
#include "sm/net.h"
#endif /* SM_LIBCONF_ALONE */
#include "sm-conf-node.h"
#include "sm-conf-state.h"
#include "sm-conf-type.h"
#include "sm-conf-util.h"
/*
** SM_MEMTOIPV4 --
**
** Parameters:
** text -- the text to be converted
** text_n -- # of bytes pointed to by text
** endptr -- if non-NULL, a pointer to the first
** unconverted byte is stored here.
** val_out -- value is stored here.
**
** Returns:
** EINVAL for a format error
** ERANGE for overflow
** 0 for success.
*/
static sm_ret_T
sm_memtoipv4(
char const *text,
size_t text_n,
char **endptr,
unsigned long *val_out)
{
size_t n;
sm_ret_T ret;
ipv4_T ipv4;
char ipv4str[20]; /* 4 * 4 + 2 "[]" + '\0' + 1 as safety */
if (text_n >= sizeof(ipv4str))
n = sizeof(ipv4str) - 1;
else
n = text_n;
sm_memcpy(ipv4str, text, n);
ipv4str[n] = '\0';
ret = sm_inet_a2ipv4(ipv4str, endptr, &ipv4);
*val_out = ipv4;
return ret;
}
static int
ipv4_write(
sm_conf_definition_T const *def,
void *data,
unsigned long val)
{
SM_IS_CONF_DEF(def);
if (def->scd_size != sizeof(ipv4_T))
return SM_CONF_ERR_INVALID;
*(ipv4_T *)data = (ipv4_T)val;
return 0;
}
static int
ipv4_scan(
sm_conf_T *smc,
sm_conf_node_T const *node,
sm_conf_definition_T const *def,
char const *text,
size_t text_n,
unsigned long *val_out)
{
char loc[SM_CONF_ERROR_BUFFER_SIZE];
size_t i;
int err;
char *endptr;
SM_IS_CONF_DEF(def);
err = sm_memtoipv4(text, text_n, &endptr, val_out);
if (err != 0)
{
sm_conf_error_add(smc,
"%s: expected IPv4 address, got '%.*s'",
sm_conf_node_location(smc, node, loc, sizeof loc),
(int)text_n, text);
return SM_CONF_ERR_TYPE;
}
i = endptr - text;
/* If there's something left, and we have suffixes, use them. */
if (i < text_n)
{
sm_conf_error_add(smc, "%s: unexpected trailing "
"characters in '%.*s'",
sm_conf_node_location(smc, node, loc, sizeof loc),
(int)text_n, text);
return SM_CONF_ERR_TYPE;
}
return 0;
}
static int
sm_conf_type_ipv4_node_to_value(
sm_conf_T *smc,
sm_conf_definition_T const *def,
sm_conf_node_T *node,
void *data)
{
char const *text;
size_t text_n;
int err;
unsigned long val;
SM_IS_CONF_DEF(def);
err = sm_conf_node_to_value(smc, "ipv4ean", node, &text, &text_n);
if (err != 0)
return err;
err = ipv4_scan(smc, node, def, text, text_n, &val);
if (err != 0)
return err;
if (data != NULL)
err = ipv4_write(def, data, val);
return err;
}
static int
sm_conf_type_ipv4_value_check(
sm_conf_T *smc,
sm_conf_definition_T const *def,
void const *data)
{
SM_IS_CONF_DEF(def);
/* if we have a check function, use it. */
if (def->scd_check != NULL)
return (* def->scd_check)(smc, def->scd_check_data, def, data);
return 0;
}
static int
sm_conf_type_ipv4_value_null(
sm_conf_T *smc,
sm_conf_definition_T const *def,
void *data)
{
unsigned long val;
int err;
if (data != NULL)
{
SM_IS_CONF_DEF(def);
val = 0;
/* is there a default? if NULL: don't set value to 0 */
if (def->scd_default != NULL)
{
/* is there an actual value? */
if (*def->scd_default != '\0')
{
err = ipv4_scan(smc, NULL, def, def->scd_default,
strlen(def->scd_default), &val);
if (err != 0)
return err;
}
err = ipv4_write(def, data, val);
if (err != 0)
return err;
}
}
return 0;
}
sm_conf_type_T const
sm_conf_type_ipv4_data =
{
sm_conf_type_ipv4_node_to_value,
sm_conf_type_ipv4_value_check,
sm_conf_type_ipv4_value_null
};
syntax highlighted by Code2HTML, v. 0.9.1