/* * 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 #include #include #include #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 };