diff --git a/configure.ac b/configure.ac index 9fe435f..e8a1ffb 100644 --- a/configure.ac +++ b/configure.ac @@ -81,7 +81,6 @@ AC_CHECK_HEADERS([ \ # Checks for header files. AC_HEADER_STDC - # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T @@ -97,7 +96,7 @@ AC_CHECK_DECLS([__CYGWIN__]) # Checks for library functions. AC_FUNC_FORK -AC_CHECK_FUNCS([gettimeofday inet_ntoa memset select socket strerror]) +AC_CHECK_FUNCS([gettimeofday inet_ntoa memset select socket strerror strlcpy]) AC_CONFIG_FILES([ Makefile diff --git a/src/modbus-private.h b/src/modbus-private.h index bb6dc3f..aba356e 100644 --- a/src/modbus-private.h +++ b/src/modbus-private.h @@ -109,6 +109,10 @@ struct _modbus { void _modbus_init_common(modbus_t *ctx); void _error_print(modbus_t *ctx, const char *context); +#ifndef HAVE_STRLCPY +size_t strlcpy(char *dest, const char *src, size_t dest_size); +#endif + MODBUS_END_DECLS #endif /* _MODBUS_PRIVATE_H_ */ diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c index 17c77d0..27be1f1 100644 --- a/src/modbus-rtu.c +++ b/src/modbus-rtu.c @@ -853,6 +853,8 @@ modbus_t* modbus_new_rtu(const char *device, { modbus_t *ctx; modbus_rtu_t *ctx_rtu; + size_t dest_size; + size_t src_size; ctx = (modbus_t *) malloc(sizeof(modbus_t)); _modbus_init_common(ctx); @@ -860,11 +862,23 @@ modbus_t* modbus_new_rtu(const char *device, ctx->backend = &_modbus_rtu_backend; ctx->backend_data = (modbus_rtu_t *) malloc(sizeof(modbus_rtu_t)); ctx_rtu = (modbus_rtu_t *)ctx->backend_data; -#if defined(OpenBSD) - strlcpy(ctx_rtu->device, device, sizeof(ctx_rtu->device)); -#else - strcpy(ctx_rtu->device, device); -#endif + + dest_size = sizeof(ctx_rtu->device); + src_size = strlcpy(ctx_rtu->device, device, dest_size); + if (src_size == 0) { + modbus_free(ctx); + fprintf(stderr, "The device string is empty\n"); + errno = EINVAL; + return NULL; + } + + if (src_size >= dest_size) { + modbus_free(ctx); + fprintf(stderr, "The device string has been truncated\n"); + errno = EINVAL; + return NULL; + } + ctx_rtu->baud = baud; if (parity == 'N' || parity == 'E' || parity == 'O') { ctx_rtu->parity = parity; diff --git a/src/modbus.c b/src/modbus.c index b741c4c..a283fd6 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -1425,3 +1425,42 @@ int modbus_accept(modbus_t *ctx, int *socket) { return ctx->backend->accept(ctx, socket); } + +#ifndef HAVE_STRLCPY +/* +/* Function strlcpy was originally developed by + * Todd C. Miller to simplify writing secure code. + * See ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.3 + * for more information. + * + * Thank you Ulrich Drepper... not! + * + * Copy src to string dest of size dest_size. At most dest_size-1 characters + * will be copied. Always NUL terminates (unless dest_size == 0). Returns + * strlen(src); if retval >= dest_size, truncation occurred. + */ +size_t strlcpy(char *dest, const char *src, size_t dest_size) +{ + register char *d = dest; + register const char *s = src; + register size_t n = dest_size; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dest, add NUL and traverse rest of src */ + if (n == 0) { + if (dest_size != 0) + *d = '\0'; /* NUL-terminate dest */ + while (*s++) + ; + } + + return (s - src - 1); /* count does not include NUL */ +} +#endif diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index fb853fa..7336720 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -48,6 +48,10 @@ int main(void) /* TCP */ ctx = modbus_new_tcp("127.0.0.1", 1502); + if (ctx == NULL) { + fprintf(stderr, "Unable to initialize TCP Modbus\n"); + return -1; + } modbus_set_debug(ctx, TRUE); if (modbus_connect(ctx) == -1) {