[PATCH] Fix string to integer conversion

Jeremy Allison jra at samba.org
Fri Feb 22 21:42:12 UTC 2019


On Tue, Feb 05, 2019 at 02:02:03PM +0100, swen via samba-technical wrote:
> Hi Jeremy
> On Mon, 2019-01-28 at 15:19 -0800, Jeremy Allison via samba-technical
> wrote:
> > On Mon, Jan 28, 2019 at 02:43:36PM +0100, swen wrote:
> > 
> > > I still believe your suggested way is not good a good API.
> > > Anyhow, because I believe that that solution is still better than
> > > none,
> > > I will prepare a patch with your code suggestion.
> > 
> > Thanks Swen, but I'm out with the flu at the moment.
> > I'm hoping to get better so I can go to FOSDEM to
> > give my talk. I'll try and get to the patch as soon
> > as health permits.
> 
> ...as could be seen on samba-tech you're healthy again :-)
> 
> Please find attached the updated version of the
> string conversion patch.
> I fixed 2-3 typos and ran it on gitlab...(at some stage with success).
> 
> If time permits, please let me know if there's anything left to be
> done.

One small thing:

In a couple of places you have:

+               int error;

I'd prefer you initialize that to zero at declaration
time, i.e.:

+               int error = 0;

Now I know both strtoul_err() and strtoull_err()
will return zero there on success (arguably
they shouldn't touch &error on success, but
I'm not going to fight that battle :-), but
it's good habits (and I think in the README.Coding)
standards that we initialize on declaration if
possible.

With that (minor) change (which I'm happy
to add myself if someone else RB+'s) RB+ me.

Can I get a second Team reviewer ?

Jeremy.

> Thanks for your support in advance.
> 
> Cheers Swen

> From fe3441dc8692aa8e55c42d93ae7fe5621eca6845 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Mon, 28 Jan 2019 09:42:13 +0100
> Subject: [PATCH 01/19] util: Add two wrapper for string to int conversion
> 
> Adding wrapper strtoull_err and strtoul_err to handle
> error conditions of the conversion process.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  lib/util/util.c | 28 ++++++++++++++++++++++++++++
>  lib/util/util.h |  7 +++++++
>  2 files changed, 35 insertions(+)
> 
> diff --git a/lib/util/util.c b/lib/util/util.c
> index f52f69c6ef0..d2f7160e02e 100644
> --- a/lib/util/util.c
> +++ b/lib/util/util.c
> @@ -47,6 +47,34 @@
>   * @brief Misc utility functions
>   */
>  
> +unsigned long int
> +strtoul_err(const char *nptr, char **endptr, int base, int *err)
> +{
> +	unsigned long int val;
> +	int saved_errno = errno;
> +
> +	errno = 0;
> +	val = strtoul(nptr, endptr, base);
> +	*err = errno;
> +
> +	errno = saved_errno;
> +	return val;
> +}
> +
> +unsigned long long int
> +strtoull_err(const char *nptr, char **endptr, int base, int *err)
> +{
> +	unsigned long long int val;
> +	int saved_errno = errno;
> +
> +	errno = 0;
> +	val = strtoull(nptr, endptr, base);
> +	*err = errno;
> +
> +	errno = saved_errno;
> +	return val;
> +}
> +
>  /**
>   Find a suitable temporary directory. The result should be copied immediately
>   as it may be overwritten by a subsequent call.
> diff --git a/lib/util/util.h b/lib/util/util.h
> index 5a0ce5cdb2a..fcd81759b9c 100644
> --- a/lib/util/util.h
> +++ b/lib/util/util.h
> @@ -21,6 +21,13 @@
>  #ifndef __UTIL_SAMBA_UTIL_H__
>  #define __UTIL_SAMBA_UTIL_H__
>  
> +unsigned long int
> +strtoul_err(const char *nptr, char **endptr, int base, int *err);
> +
> +unsigned long long int
> +strtoull_err(const char *nptr, char **endptr, int base, int *err);
> +
> +
>  /**
>   * Write dump of binary data to a callback
>   */
> -- 
> 2.20.1
> 
> 
> From c3a0d44f6268248c4edf635196cc28542435d01b Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Mon, 28 Jan 2019 12:54:07 +0100
> Subject: [PATCH 02/19] lib: Use wrapper for string to integer conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  source3/lib/interface.c     | 17 +++++++++++++----
>  source3/lib/messages_dgm.c  | 17 +++++++++--------
>  source3/lib/namemap_cache.c | 17 +++++++----------
>  source3/lib/sysquotas.c     |  7 ++++++-
>  source3/lib/tldap_util.c    | 11 ++++++++++-
>  source3/lib/util_str.c      |  5 +++--
>  source3/wscript_build       |  2 ++
>  7 files changed, 50 insertions(+), 26 deletions(-)
> 
> diff --git a/source3/lib/interface.c b/source3/lib/interface.c
> index a3bc5d24e91..1d8dfd6501b 100644
> --- a/source3/lib/interface.c
> +++ b/source3/lib/interface.c
> @@ -358,6 +358,7 @@ static void parse_extra_info(char *key, uint64_t *speed, uint32_t *cap,
>  	while (key != NULL && *key != '\0') {
>  		char *next_key;
>  		char *val;
> +		int error;
>  
>  		next_key = strchr_m(key, ',');
>  		if (next_key != NULL) {
> @@ -369,7 +370,10 @@ static void parse_extra_info(char *key, uint64_t *speed, uint32_t *cap,
>  			*val++ = 0;
>  
>  			if (strequal_m(key, "speed")) {
> -				*speed = (uint64_t)strtoull(val, NULL, 0);
> +				*speed = (uint64_t)strtoull_err(val, NULL, 0, &error);
> +				if (error != 0) {
> +					DBG_DEBUG("Invalid speed value (%s)\n", val);
> +				}
>  			} else if (strequal_m(key, "capability")) {
>  				if (strequal_m(val, "RSS")) {
>  					*cap |= FSCTL_NET_IFACE_RSS_CAPABLE;
> @@ -380,7 +384,10 @@ static void parse_extra_info(char *key, uint64_t *speed, uint32_t *cap,
>  						    "'%s'\n", val);
>  				}
>  			} else if (strequal_m(key, "if_index")) {
> -				*if_index = (uint32_t)strtoul(val, NULL, 0);
> +				*if_index = (uint32_t)strtoul_err(val, NULL, 0, &error);
> +				if (error != 0) {
> +					DBG_DEBUG("Invalid key value (%s)\n", val);
> +				}
>  			} else {
>  				DBG_DEBUG("Key unknown: '%s'\n", key);
>  			}
> @@ -515,9 +522,11 @@ static void interpret_interface(char *token)
>  			return;
>  		}
>  	} else {
> +		int error = 0;
>  		char *endp = NULL;
> -		unsigned long val = strtoul(p, &endp, 0);
> -		if (p == endp || (endp && *endp != '\0')) {
> +		unsigned long val = strtoul_err(p, &endp, 0, &error);
> +
> +		if (p == endp || (endp && *endp != '\0') || error != 0) {
>  			DEBUG(2,("interpret_interface: "
>  				"can't determine netmask value from %s\n",
>  				p));
> diff --git a/source3/lib/messages_dgm.c b/source3/lib/messages_dgm.c
> index 37eefeb0a4a..4836697bcf3 100644
> --- a/source3/lib/messages_dgm.c
> +++ b/source3/lib/messages_dgm.c
> @@ -18,6 +18,7 @@
>   */
>  
>  #include "replace.h"
> +#include "util/util.h"
>  #include "system/network.h"
>  #include "system/filesys.h"
>  #include "system/dir.h"
> @@ -1442,6 +1443,7 @@ static int messaging_dgm_read_unique(int fd, uint64_t *punique)
>  {
>  	char buf[25];
>  	ssize_t rw_ret;
> +	int error = 0;
>  	unsigned long long unique;
>  	char *endptr;
>  
> @@ -1451,13 +1453,11 @@ static int messaging_dgm_read_unique(int fd, uint64_t *punique)
>  	}
>  	buf[rw_ret] = '\0';
>  
> -	unique = strtoull(buf, &endptr, 10);
> -	if ((unique == 0) && (errno == EINVAL)) {
> -		return EINVAL;
> -	}
> -	if ((unique == ULLONG_MAX) && (errno == ERANGE)) {
> -		return ERANGE;
> +	unique = strtoull_err(buf, &endptr, 10, &error);
> +	if (error != 0) {
> +		return error;
>  	}
> +
>  	if (endptr[0] != '\n') {
>  		return EINVAL;
>  	}
> @@ -1599,6 +1599,7 @@ int messaging_dgm_forall(int (*fn)(pid_t pid, void *private_data),
>  	struct messaging_dgm_context *ctx = global_dgm_context;
>  	DIR *msgdir;
>  	struct dirent *dp;
> +	int error = 0;
>  
>  	if (ctx == NULL) {
>  		return ENOTCONN;
> @@ -1621,8 +1622,8 @@ int messaging_dgm_forall(int (*fn)(pid_t pid, void *private_data),
>  		unsigned long pid;
>  		int ret;
>  
> -		pid = strtoul(dp->d_name, NULL, 10);
> -		if (pid == 0) {
> +		pid = strtoul_err(dp->d_name, NULL, 10, &error);
> +		if ((pid == 0) || (error != 0)) {
>  			/*
>  			 * . and .. and other malformed entries
>  			 */
> diff --git a/source3/lib/namemap_cache.c b/source3/lib/namemap_cache.c
> index fa179517f9f..42656ede0b7 100644
> --- a/source3/lib/namemap_cache.c
> +++ b/source3/lib/namemap_cache.c
> @@ -22,6 +22,7 @@
>  #include "source3/lib/gencache.h"
>  #include "lib/util/debug.h"
>  #include "lib/util/strv.h"
> +#include "lib/util/util.h"
>  #include "lib/util/talloc_stack.h"
>  #include "lib/util/charset/charset.h"
>  #include "libcli/security/dom_sid.h"
> @@ -105,6 +106,7 @@ static void namemap_cache_find_sid_parser(
>  	const char *domain;
>  	const char *name;
>  	const char *typebuf;
> +	int error = 0;
>  	char *endptr;
>  	unsigned long type;
>  
> @@ -123,11 +125,8 @@ static void namemap_cache_find_sid_parser(
>  		return;
>  	}
>  
> -	type = strtoul(typebuf, &endptr, 10);
> -	if (*endptr != '\0') {
> -		return;
> -	}
> -	if ((type == ULONG_MAX) && (errno == ERANGE)) {
> +	type = strtoul_err(typebuf, &endptr, 10, &error);
> +	if ((*endptr != '\0') || (error != 0)) {
>  		return;
>  	}
>  
> @@ -253,6 +252,7 @@ static void namemap_cache_find_name_parser(
>  	const char *sid_endptr;
>  	const char *typebuf;
>  	char *endptr;
> +	int error = 0;
>  	struct dom_sid sid;
>  	unsigned long type;
>  	bool ok;
> @@ -276,11 +276,8 @@ static void namemap_cache_find_name_parser(
>  		return;
>  	}
>  
> -	type = strtoul(typebuf, &endptr, 10);
> -	if (*endptr != '\0') {
> -		return;
> -	}
> -	if ((type == ULONG_MAX) && (errno == ERANGE)) {
> +	type = strtoul_err(typebuf, &endptr, 10, &error);
> +	if ((*endptr != '\0') || (error != 0)) {
>  		return;
>  	}
>  
> diff --git a/source3/lib/sysquotas.c b/source3/lib/sysquotas.c
> index 9b2d37b8375..c89dc96d690 100644
> --- a/source3/lib/sysquotas.c
> +++ b/source3/lib/sysquotas.c
> @@ -250,6 +250,7 @@ static int command_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t
>  		char *p2;
>  		char *syscmd = NULL;
>  		int _id = -1;
> +		int error = 0;
>  
>  		switch(qtype) {
>  			case SMB_USER_QUOTA_TYPE:
> @@ -282,7 +283,11 @@ static int command_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t
>  
>  			/* we need to deal with long long unsigned here, if supported */
>  
> -			dp->qflags = strtoul(line, &p2, 10);
> +			dp->qflags = strtoul_err(line, &p2, 10, &error);
> +			if (error != 0) {
> +				goto invalid_param;
> +			}
> +
>  			p = p2;
>  			while (p && *p && isspace(*p)) {
>  				p++;
> diff --git a/source3/lib/tldap_util.c b/source3/lib/tldap_util.c
> index 508c6c02f80..3135a8c4396 100644
> --- a/source3/lib/tldap_util.c
> +++ b/source3/lib/tldap_util.c
> @@ -389,13 +389,22 @@ bool tldap_pull_uint64(struct tldap_message *msg, const char *attr,
>  {
>  	char *str;
>  	uint64_t result;
> +	int error = 0;
>  
>  	str = tldap_talloc_single_attribute(msg, attr, talloc_tos());
>  	if (str == NULL) {
>  		DEBUG(10, ("Could not find attribute %s\n", attr));
>  		return false;
>  	}
> -	result = strtoull(str, NULL, 10);
> +
> +	result = strtoull_err(str, NULL, 10, &error);
> +	if (error != 0) {
> +		DBG_DEBUG("Attribute conversion failed (%s)\n",
> +			  strerror(error));
> +		TALLOC_FREE(str);
> +		return false;
> +	}
> +
>  	TALLOC_FREE(str);
>  	*presult = result;
>  	return true;
> diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
> index 8568af46c17..a773b9b68f1 100644
> --- a/source3/lib/util_str.c
> +++ b/source3/lib/util_str.c
> @@ -851,14 +851,15 @@ uint64_t conv_str_size(const char * str)
>  {
>          uint64_t lval;
>  	char * end;
> +	int error;
>  
>          if (str == NULL || *str == '\0') {
>                  return 0;
>          }
>  
> -	lval = strtoull(str, &end, 10 /* base */);
> +	lval = strtoull_err(str, &end, 10, &error);
>  
> -        if (end == NULL || end == str) {
> +        if (end == NULL || end == str || error != 0) {
>                  return 0;
>          }
>  
> diff --git a/source3/wscript_build b/source3/wscript_build
> index f25a27ba3a8..2b5b3ca2c4f 100644
> --- a/source3/wscript_build
> +++ b/source3/wscript_build
> @@ -367,6 +367,7 @@ bld.SAMBA3_LIBRARY('messages_dgm',
>                          PTHREADPOOL
>                          msghdr
>                          genrand
> +			samba-util
>                          ''',
>                     private_library=True)
>  
> @@ -1362,6 +1363,7 @@ bld.RECURSE('smbd/notifyd')
>  bld.RECURSE('rpcclient')
>  bld.RECURSE('utils')
>  bld.RECURSE('nmbd')
> +bld.RECURSE('lib/util')
>  
>  bld.ENFORCE_GROUP_ORDERING()
>  bld.CHECK_PROJECT_RULES()
> -- 
> 2.20.1
> 
> 
> From 8fe24b7be23bda4ece6d55b62aabc5e4e110f480 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Mon, 28 Jan 2019 13:12:09 +0100
> Subject: [PATCH 03/19] groupdb: Use wrapper for string to integer conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  source3/groupdb/mapping.c     | 11 ++++++++++-
>  source3/groupdb/mapping_tdb.c | 12 ++++++++----
>  2 files changed, 18 insertions(+), 5 deletions(-)
> 
> diff --git a/source3/groupdb/mapping.c b/source3/groupdb/mapping.c
> index 43722e777d4..77eb0d6e5cd 100644
> --- a/source3/groupdb/mapping.c
> +++ b/source3/groupdb/mapping.c
> @@ -208,6 +208,7 @@ int smb_create_group(const char *unix_group, gid_t *new_gid)
>  	char *add_script = NULL;
>  	int 	ret = -1;
>  	int 	fd = 0;
> +	int error = 0;
>  
>  	*new_gid = 0;
>  
> @@ -244,7 +245,15 @@ int smb_create_group(const char *unix_group, gid_t *new_gid)
>  			nread = read(fd, output, sizeof(output)-1);
>  			if (nread > 0) {
>  				output[nread] = '\0';
> -				*new_gid = (gid_t)strtoul(output, NULL, 10);
> +				*new_gid = (gid_t)strtoul_err(output,
> +							      NULL,
> +							      10,
> +							      &error);
> +				if (error != 0) {
> +					*new_gid = 0;
> +					close(fd);
> +					return -1;
> +				}
>  			}
>  
>  			close(fd);
> diff --git a/source3/groupdb/mapping_tdb.c b/source3/groupdb/mapping_tdb.c
> index d6a06ef199b..c80ff1f859a 100644
> --- a/source3/groupdb/mapping_tdb.c
> +++ b/source3/groupdb/mapping_tdb.c
> @@ -860,6 +860,7 @@ static int convert_ldb_record(TDB_CONTEXT *ltdb, TDB_DATA key,
>  	char *q;
>  	uint32_t num_mem = 0;
>  	struct dom_sid *members = NULL;
> +	int error = 0;
>  
>  	p = (uint8_t *)data.dptr;
>  	if (data.dsize < 8) {
> @@ -974,8 +975,8 @@ static int convert_ldb_record(TDB_CONTEXT *ltdb, TDB_DATA key,
>  			/* we ignore unknown or uninteresting attributes
>  			 * (objectclass, etc.) */
>  			if (strcasecmp_m(name, "gidNumber") == 0) {
> -				map->gid = strtoul(val, &q, 10);
> -				if (*q) {
> +				map->gid = strtoul_err(val, &q, 10, &error);
> +				if (*q || (error != 0)) {
>  					errno = EIO;
>  					goto failed;
>  				}
> @@ -985,8 +986,11 @@ static int convert_ldb_record(TDB_CONTEXT *ltdb, TDB_DATA key,
>  					goto failed;
>  				}
>  			} else if (strcasecmp_m(name, "sidNameUse") == 0) {
> -				map->sid_name_use = strtoul(val, &q, 10);
> -				if (*q) {
> +				map->sid_name_use = strtoul_err(val,
> +								&q,
> +								10,
> +								&error);
> +				if (*q || (error != 0)) {
>  					errno = EIO;
>  					goto failed;
>  				}
> -- 
> 2.20.1
> 
> 
> From 6c5bc97f04c6a890038c76471b9bd9b07bdec1f8 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Mon, 28 Jan 2019 13:36:45 +0100
> Subject: [PATCH 04/19] utils: Use wrapper for string to integer conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  source3/utils/net_idmap.c        |  9 +++------
>  source3/utils/net_registry.c     | 14 ++++++++++++--
>  source3/utils/net_rpc_registry.c |  8 +++++++-
>  source3/utils/net_sam.c          |  5 +++--
>  source3/utils/pdbedit.c          | 12 +++++++++---
>  source3/utils/regedit_dialog.c   |  5 +++--
>  6 files changed, 37 insertions(+), 16 deletions(-)
> 
> diff --git a/source3/utils/net_idmap.c b/source3/utils/net_idmap.c
> index b49d5f43381..f6c9f3a1a3d 100644
> --- a/source3/utils/net_idmap.c
> +++ b/source3/utils/net_idmap.c
> @@ -628,8 +628,9 @@ static bool parse_uint32(const char *str, uint32_t *result)
>  {
>  	unsigned long val;
>  	char *endptr;
> +	int error = 0;
>  
> -	val = strtoul(str, &endptr, 10);
> +	val = strtoul_err(str, &endptr, 10, &error);
>  
>  	if (str == endptr) {
>  		return false;
> @@ -637,11 +638,7 @@ static bool parse_uint32(const char *str, uint32_t *result)
>  	if (*endptr != '\0') {
>  		return false;
>  	}
> -	if ((val == ULONG_MAX) && (errno == ERANGE)) {
> -		return false;
> -	}
> -	if ((val & UINT32_MAX) != val) {
> -		/* overflow */
> +	if (error != 0) {
>  		return false;
>  	}
>  	*result = val;		/* Potential crop */
> diff --git a/source3/utils/net_registry.c b/source3/utils/net_registry.c
> index 01a36b20e7c..b7711873561 100644
> --- a/source3/utils/net_registry.c
> +++ b/source3/utils/net_registry.c
> @@ -509,7 +509,13 @@ static int net_registry_setvalue(struct net_context *c, int argc,
>  	}
>  
>  	if (strequal(argv[2], "dword")) {
> -		uint32_t v = strtoul(argv[3], NULL, 10);
> +		int error = 0;
> +		uint32_t v = strtoul_err(argv[3], NULL, 10, &error);
> +
> +		if (error != 0) {
> +			goto done;
> +		}
> +
>  		value.type = REG_DWORD;
>  		value.data = data_blob_talloc(ctx, NULL, 4);
>  		SIVAL(value.data.data, 0, v);
> @@ -641,7 +647,11 @@ static int net_registry_increment(struct net_context *c, int argc,
>  
>  	state.increment = 1;
>  	if (argc == 3) {
> -		state.increment = strtoul(argv[2], NULL, 10);
> +		int error = 0;
> +		state.increment = strtoul_err(argv[2], NULL, 10, &error);
> +		if (error != 0) {
> +			goto done;
> +		}
>  	}
>  
>  	status = g_lock_do(string_term_tdb_data("registry_increment_lock"),
> diff --git a/source3/utils/net_rpc_registry.c b/source3/utils/net_rpc_registry.c
> index 19b73fd7042..dc51137e15b 100644
> --- a/source3/utils/net_rpc_registry.c
> +++ b/source3/utils/net_rpc_registry.c
> @@ -603,7 +603,13 @@ static NTSTATUS rpc_registry_setvalue_internal(struct net_context *c,
>  	}
>  
>  	if (strequal(argv[2], "dword")) {
> -		uint32_t v = strtoul(argv[3], NULL, 10);
> +		int error = 0;
> +		uint32_t v = strtoul_err(argv[3], NULL, 10, &error);
> +
> +		if (error != 0) {
> +			goto error;
> +		}
> +
>  		value.type = REG_DWORD;
>  		value.data = data_blob_talloc(mem_ctx, NULL, 4);
>  		SIVAL(value.data.data, 0, v);
> diff --git a/source3/utils/net_sam.c b/source3/utils/net_sam.c
> index 5a9d1792d51..fc2a7baacef 100644
> --- a/source3/utils/net_sam.c
> +++ b/source3/utils/net_sam.c
> @@ -484,6 +484,7 @@ static int net_sam_policy_set(struct net_context *c, int argc, const char **argv
>  	uint32_t old_value = 0;
>  	enum pdb_policy_type field;
>  	char *endptr;
> +	int err = 0;
>  
>          if (argc != 2 || c->display_usage) {
>                  d_fprintf(stderr, "%s\n%s",
> @@ -500,9 +501,9 @@ static int net_sam_policy_set(struct net_context *c, int argc, const char **argv
>  		value = -1;
>  	}
>  	else {
> -		value = strtoul(argv[1], &endptr, 10);
> +		value = strtoul_err(argv[1], &endptr, 10, &err);
>  
> -		if ((endptr == argv[1]) || (endptr[0] != '\0')) {
> +		if ((endptr == argv[1]) || (endptr[0] != '\0') || (err != 0)) {
>  			d_printf(_("Unable to set policy \"%s\"! Invalid value "
>  				 "\"%s\".\n"),
>  				 account_policy, argv[1]);
> diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c
> index 585f1bfada3..51db6710ff3 100644
> --- a/source3/utils/pdbedit.c
> +++ b/source3/utils/pdbedit.c
> @@ -598,9 +598,15 @@ static int set_user_info(const char *username, const char *fullname,
>  		time_t value = get_time_t_max();
>  
>  		if (strcmp(kickoff_time, "never") != 0) {
> -			uint32_t num = strtoul(kickoff_time, &endptr, 10);
> -
> -			if ((endptr == kickoff_time) || (endptr[0] != '\0')) {
> +			int error = 0;
> +			uint32_t num = strtoul_err(kickoff_time,
> +						   &endptr,
> +						   10,
> +						   &error);
> +
> +			if ((endptr == kickoff_time) ||
> +			    (endptr[0] != '\0') ||
> +			    (error != 0)) {
>  				fprintf(stderr, "Failed to parse kickoff time\n");
>  				return -1;
>  			}
> diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c
> index dcce66bf208..aeea70ac22e 100644
> --- a/source3/utils/regedit_dialog.c
> +++ b/source3/utils/regedit_dialog.c
> @@ -1032,6 +1032,7 @@ bool dialog_section_text_field_get_uint(struct dialog_section *section,
>  	bool rv;
>  	const char *buf;
>  	char *endp;
> +	int error = 0;
>  	struct dialog_section_text_field *text_field =
>  		talloc_get_type_abort(section, struct dialog_section_text_field);
>  
> @@ -1041,9 +1042,9 @@ bool dialog_section_text_field_get_uint(struct dialog_section *section,
>  	if (buf == NULL) {
>  		return false;
>  	}
> -	*out = strtoull(buf, &endp, 0);
> +	*out = strtoull_err(buf, &endp, 0, &error);
>  	rv = true;
> -	if (endp == buf || endp == NULL || endp[0] != '\0') {
> +	if (endp == buf || endp == NULL || endp[0] != '\0' || error != 0) {
>  		rv = false;
>  	}
>  
> -- 
> 2.20.1
> 
> 
> From 77acd059051a50ccffbe1d7e6b9d78db5f5bb49f Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Mon, 28 Jan 2019 13:57:15 +0100
> Subject: [PATCH 05/19] passdb: Use wrapper for string to integer conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  source3/passdb/account_pol.c |  7 +++-
>  source3/passdb/pdb_ldap.c    | 72 +++++++++++++++++++++++++++++-------
>  source3/passdb/pdb_tdb.c     |  6 ++-
>  3 files changed, 70 insertions(+), 15 deletions(-)
> 
> diff --git a/source3/passdb/account_pol.c b/source3/passdb/account_pol.c
> index e566eca78eb..b1463c647b7 100644
> --- a/source3/passdb/account_pol.c
> +++ b/source3/passdb/account_pol.c
> @@ -456,7 +456,12 @@ bool cache_account_policy_get(enum pdb_policy_type type, uint32_t *value)
>  	}
>  
>  	if (gencache_get(cache_key, talloc_tos(), &cache_value, NULL)) {
> -		uint32_t tmp = strtoul(cache_value, NULL, 10);
> +		int error = 0;
> +		uint32_t tmp = strtoul_err(cache_value, NULL, 10, &error);
> +
> +		if (error != 0) {
> +			goto done;
> +		}
>  		*value = tmp;
>  		ret = True;
>  	}
> diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c
> index 7f8903ba96d..273baac8c7f 100644
> --- a/source3/passdb/pdb_ldap.c
> +++ b/source3/passdb/pdb_ldap.c
> @@ -982,6 +982,7 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
>  		struct dom_sid mapped_gsid;
>  		const struct dom_sid *primary_gsid;
>  		struct unixid id;
> +		int error = 0;
>  
>  		ZERO_STRUCT(unix_pw);
>  
> @@ -995,7 +996,11 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
>  				ctx);
>  		if (temp) {
>  			/* We've got a uid, feed the cache */
> -			unix_pw.pw_uid = strtoul(temp, NULL, 10);
> +			unix_pw.pw_uid = strtoul_err(temp, NULL, 10, &error);
> +			if (error != 0) {
> +				DBG_ERR("Failed to convert UID\n");
> +				goto fn_exit;
> +			}
>  			have_uid = true;
>  		}
>  		temp = smbldap_talloc_single_attribute(
> @@ -1005,7 +1010,11 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
>  				ctx);
>  		if (temp) {
>  			/* We've got a uid, feed the cache */
> -			unix_pw.pw_gid = strtoul(temp, NULL, 10);
> +			unix_pw.pw_gid = strtoul_err(temp, NULL, 10, &error);
> +			if (error != 0) {
> +				DBG_ERR("Failed to convert GID\n");
> +				goto fn_exit;
> +			}
>  			have_gid = true;
>  		}
>  		unix_pw.pw_gecos = smbldap_talloc_single_attribute(
> @@ -2879,6 +2888,7 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
>  	uint32_t num_gids;
>  	char *gidstr;
>  	gid_t primary_gid = -1;
> +	int error = 0;
>  
>  	*pp_sids = NULL;
>  	num_sids = 0;
> @@ -2928,7 +2938,11 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
>  				ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
>  				goto done;
>  			}
> -			primary_gid = strtoul(gidstr, NULL, 10);
> +			primary_gid = strtoul_err(gidstr, NULL, 10, &error);
> +			if (error != 0) {
> +				DBG_ERR("Failed to convert GID\n");
> +				goto done;
> +			}
>  			break;
>  		default:
>  			DEBUG(1, ("found more than one account with the same user name ?!\n"));
> @@ -2996,10 +3010,11 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
>  						  str, sizeof(str)-1))
>  			continue;
>  
> -		gid = strtoul(str, &end, 10);
> +		gid = strtoul_err(str, &end, 10, &error);
>  
> -		if (PTR_DIFF(end, str) != strlen(str))
> +		if ((PTR_DIFF(end, str) != strlen(str)) || (error != 0)) {
>  			goto done;
> +		}
>  
>  		if (gid == primary_gid) {
>  			sid_copy(&(*pp_sids)[0], &sid);
> @@ -4924,6 +4939,7 @@ static NTSTATUS ldapsam_get_new_rid(struct ldapsam_privates *priv,
>  	int rc;
>  	uint32_t nextRid = 0;
>  	const char *dn;
> +	int error = 0;
>  
>  	TALLOC_CTX *mem_ctx;
>  
> @@ -4959,21 +4975,33 @@ static NTSTATUS ldapsam_get_new_rid(struct ldapsam_privates *priv,
>  	value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
>  						"sambaNextRid",	mem_ctx);
>  	if (value != NULL) {
> -		uint32_t tmp = (uint32_t)strtoul(value, NULL, 10);
> +		uint32_t tmp = (uint32_t)strtoul_err(value, NULL, 10, &error);
> +		if (error != 0) {
> +			goto done;
> +		}
> +
>  		nextRid = MAX(nextRid, tmp);
>  	}
>  
>  	value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
>  						"sambaNextUserRid", mem_ctx);
>  	if (value != NULL) {
> -		uint32_t tmp = (uint32_t)strtoul(value, NULL, 10);
> +		uint32_t tmp = (uint32_t)strtoul_err(value, NULL, 10, &error);
> +		if (error != 0) {
> +			goto done;
> +		}
> +
>  		nextRid = MAX(nextRid, tmp);
>  	}
>  
>  	value = smbldap_talloc_single_attribute(priv2ld(priv), entry,
>  						"sambaNextGroupRid", mem_ctx);
>  	if (value != NULL) {
> -		uint32_t tmp = (uint32_t)strtoul(value, NULL, 10);
> +		uint32_t tmp = (uint32_t)strtoul_err(value, NULL, 10, &error);
> +		if (error != 0) {
> +			goto done;
> +		}
> +
>  		nextRid = MAX(nextRid, tmp);
>  	}
>  
> @@ -5043,6 +5071,7 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods,
>  	struct ldapsam_privates *priv =
>  		(struct ldapsam_privates *)methods->private_data;
>  	char *filter;
> +	int error = 0;
>  	struct dom_sid_buf buf;
>  	const char *attrs[] = { "sambaGroupType", "gidNumber", "uidNumber",
>  				NULL };
> @@ -5106,7 +5135,11 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods,
>  			goto done;
>  		}
>  
> -		id->id = strtoul(gid_str, NULL, 10);
> +		id->id = strtoul_err(gid_str, NULL, 10, &error);
> +		if (error != 0) {
> +			goto done;
> +		}
> +
>  		id->type = ID_TYPE_GID;
>  		ret = True;
>  		goto done;
> @@ -5122,9 +5155,12 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods,
>  		goto done;
>  	}
>  
> -	id->id = strtoul(value, NULL, 10);
> -	id->type = ID_TYPE_UID;
> +	id->id = strtoul_err(value, NULL, 10, &error);
> +	if (error != 0) {
> +		goto done;
> +	}
>  
> +	id->type = ID_TYPE_UID;
>  	ret = True;
>   done:
>  	TALLOC_FREE(mem_ctx);
> @@ -5665,6 +5701,7 @@ static NTSTATUS ldapsam_create_dom_group(struct pdb_methods *my_methods,
>  	struct dom_sid_buf buf;
>  	gid_t gid = -1;
>  	int rc;
> +	int error = 0;
>  
>  	groupname = escape_ldap_string(talloc_tos(), name);
>  	filter = talloc_asprintf(tmp_ctx, "(&(cn=%s)(objectClass=%s))",
> @@ -5709,7 +5746,11 @@ static NTSTATUS ldapsam_create_dom_group(struct pdb_methods *my_methods,
>  			return NT_STATUS_INTERNAL_DB_CORRUPTION;
>  		}
>  
> -		gid = strtoul(tmp, NULL, 10);
> +		gid = strtoul_err(tmp, NULL, 10, &error);
> +		if (error != 0) {
> +			DBG_ERR("Failed to convert gidNumber\n");
> +			return NT_STATUS_UNSUCCESSFUL;
> +		}
>  
>  		dn = smbldap_talloc_dn(tmp_ctx, priv2ld(ldap_state), entry);
>  		if (!dn) {
> @@ -5916,6 +5957,7 @@ static NTSTATUS ldapsam_change_groupmem(struct pdb_methods *my_methods,
>  	struct dom_sid member_sid;
>  	struct dom_sid_buf buf;
>  	int rc;
> +	int error = 0;
>  
>  	switch (modop) {
>  	case LDAP_MOD_ADD:
> @@ -5981,7 +6023,11 @@ static NTSTATUS ldapsam_change_groupmem(struct pdb_methods *my_methods,
>  			return NT_STATUS_INTERNAL_DB_CORRUPTION;
>  		}
>  
> -		user_gid = strtoul(gidstr, NULL, 10);
> +		user_gid = strtoul_err(gidstr, NULL, 10, &error);
> +		if (error != 0) {
> +			DBG_ERR("Failed to convert user gid\n");
> +			return NT_STATUS_UNSUCCESSFUL;
> +		}
>  
>  		if (!sid_to_gid(&group_sid, &group_gid)) {
>  			DEBUG (0, ("ldapsam_change_groupmem: Unable to get group gid from SID!\n"));
> diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c
> index 91735ff7084..067150334a3 100644
> --- a/source3/passdb/pdb_tdb.c
> +++ b/source3/passdb/pdb_tdb.c
> @@ -1173,6 +1173,7 @@ static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
>  		private_data, struct tdbsam_search_state);
>  	size_t prefixlen = strlen(RIDPREFIX);
>  	uint32_t rid;
> +	int error = 0;
>  	TDB_DATA key;
>  
>  	key = dbwrap_record_get_key(rec);
> @@ -1182,7 +1183,10 @@ static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
>  		return 0;
>  	}
>  
> -	rid = strtoul((char *)key.dptr+prefixlen, NULL, 16);
> +	rid = strtoul_err((char *)key.dptr+prefixlen, NULL, 16, &error);
> +	if (error != 0) {
> +		return 0;
> +	}
>  
>  	ADD_TO_LARGE_ARRAY(state, uint32_t, rid, &state->rids, &state->num_rids,
>  			   &state->array_size);
> -- 
> 2.20.1
> 
> 
> From 30806dd91ce678bbf41cf134fef2400664ecee5f Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Mon, 28 Jan 2019 14:07:39 +0100
> Subject: [PATCH 06/19] winbindd: Use wrapper for string to integer conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  source3/winbindd/idmap_ldap.c          | 17 ++++++++++++-----
>  source3/winbindd/winbindd_lookuprids.c |  6 ++++--
>  source3/winbindd/winbindd_util.c       | 24 +++++++++++++++++++-----
>  3 files changed, 35 insertions(+), 12 deletions(-)
> 
> diff --git a/source3/winbindd/idmap_ldap.c b/source3/winbindd/idmap_ldap.c
> index 17cc7404f12..2bc9c082f00 100644
> --- a/source3/winbindd/idmap_ldap.c
> +++ b/source3/winbindd/idmap_ldap.c
> @@ -222,6 +222,7 @@ static NTSTATUS idmap_ldap_allocate_id_internal(struct idmap_domain *dom,
>  	const char **attr_list;
>  	const char *type;
>  	struct idmap_ldap_context *ctx;
> +	int error = 0;
>  
>  	/* Only do query if we are online */
>  	if (idmap_is_offline())	{
> @@ -299,7 +300,11 @@ static NTSTATUS idmap_ldap_allocate_id_internal(struct idmap_domain *dom,
>  		goto done;
>  	}
>  
> -	xid->id = strtoul(id_str, NULL, 10);
> +	xid->id = strtoul_err(id_str, NULL, 10, &error);
> +	if (error != 0) {
> +		ret = NT_STATUS_UNSUCCESSFUL;
> +		goto done;
> +	}
>  
>  	/* make sure we still have room to grow */
>  
> @@ -641,6 +646,7 @@ static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
>  	int count;
>  	int rc;
>  	int i;
> +	int error = 0;
>  
>  	/* Only do query if we are online */
>  	if (idmap_is_offline())	{
> @@ -769,8 +775,8 @@ again:
>  			continue;
>  		}
>  
> -		id = strtoul(tmp, NULL, 10);
> -		if (!idmap_unix_id_is_in_range(id, dom)) {
> +		id = strtoul_err(tmp, NULL, 10, &error);
> +		if (error != 0 || !idmap_unix_id_is_in_range(id, dom)) {
>  			DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
>  				  "Filtered!\n", id,
>  				  dom->low_id, dom->high_id));
> @@ -947,6 +953,7 @@ again:
>  		struct dom_sid sid;
>  		struct dom_sid_buf buf;
>  		uint32_t id;
> +		int error = 0;
>  
>  		if (i == 0) { /* first entry */
>  			entry = ldap_first_entry(
> @@ -1005,8 +1012,8 @@ again:
>  			continue;
>  		}
>  
> -		id = strtoul(tmp, NULL, 10);
> -		if (!idmap_unix_id_is_in_range(id, dom)) {
> +		id = strtoul_err(tmp, NULL, 10, &error);
> +		if (error != 0 || !idmap_unix_id_is_in_range(id, dom)) {
>  			DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
>  				  "Filtered!\n", id,
>  				  dom->low_id, dom->high_id));
> diff --git a/source3/winbindd/winbindd_lookuprids.c b/source3/winbindd/winbindd_lookuprids.c
> index 1e80b78a92e..959a4a7db38 100644
> --- a/source3/winbindd/winbindd_lookuprids.c
> +++ b/source3/winbindd/winbindd_lookuprids.c
> @@ -182,8 +182,10 @@ static bool parse_ridlist(TALLOC_CTX *mem_ctx, char *ridstr,
>  
>  	for (i=0; i<num_rids; i++) {
>  		char *q;
> -		rids[i] = strtoul(p, &q, 10);
> -		if (*q != '\n') {
> +		int error = 0;
> +
> +		rids[i] = strtoul_err(p, &q, 10, &error);
> +		if (error != 0 || *q != '\n') {
>  			DEBUG(0, ("Got invalid ridstr: %s\n", p));
>  			return false;
>  		}
> diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
> index d266eb3048e..91a2f6ef197 100644
> --- a/source3/winbindd/winbindd_util.c
> +++ b/source3/winbindd/winbindd_util.c
> @@ -461,6 +461,7 @@ static void trustdom_list_done(struct tevent_req *req)
>  		uint32_t trust_type;
>  		uint32_t trust_attribs;
>  		uint32_t trust_flags;
> +		int error = 0;
>  
>  		DBG_DEBUG("parsing response line '%s'\n", p);
>  
> @@ -506,7 +507,11 @@ static void trustdom_list_done(struct tevent_req *req)
>  			break;
>  		}
>  
> -		trust_flags = (uint32_t)strtoul(q, NULL, 10);
> +		trust_flags = (uint32_t)strtoul_err(q, NULL, 10, &error);
> +		if (error != 0) {
> +			DBG_ERR("Failed to convert trust_flags\n");
> +			break;
> +		}
>  
>  		q = strtok(NULL, "\\");
>  		if (q == NULL) {
> @@ -514,7 +519,11 @@ static void trustdom_list_done(struct tevent_req *req)
>  			break;
>  		}
>  
> -		trust_type = (uint32_t)strtoul(q, NULL, 10);
> +		trust_type = (uint32_t)strtoul_err(q, NULL, 10, &error);
> +		if (error != 0) {
> +			DBG_ERR("Failed to convert trust_type\n");
> +			break;
> +		}
>  
>  		q = strtok(NULL, "\n");
>  		if (q == NULL) {
> @@ -522,7 +531,11 @@ static void trustdom_list_done(struct tevent_req *req)
>  			break;
>  		}
>  
> -		trust_attribs = (uint32_t)strtoul(q, NULL, 10);
> +		trust_attribs = (uint32_t)strtoul_err(q, NULL, 10, &error);
> +		if (error != 0) {
> +			DBG_ERR("Failed to convert trust_attribs\n");
> +			break;
> +		}
>  
>  		if (!within_forest) {
>  			trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
> @@ -2142,6 +2155,7 @@ bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
>  		struct unixid xid;
>  		unsigned long long id;
>  		char *endp;
> +		int error = 0;
>  
>  		switch (p[0]) {
>  		case 'U':
> @@ -2156,8 +2170,8 @@ bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
>  
>  		p += 1;
>  
> -		id = strtoull(p, &endp, 10);
> -		if ((id == ULLONG_MAX) && (errno == ERANGE)) {
> +		id = strtoull_err(p, &endp, 10, &error);
> +		if (error != 0) {
>  			goto fail;
>  		}
>  		if (*endp != '\n') {
> -- 
> 2.20.1
> 
> 
> From 7f59f3a0faf7768871625f1fdb82d94d97f028a9 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Mon, 28 Jan 2019 14:30:15 +0100
> Subject: [PATCH 07/19] modules: Use wrapper for string to integer conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  source3/modules/vfs_preopen.c       | 6 +++++-
>  source3/modules/vfs_snapper.c       | 5 +++--
>  source3/modules/vfs_unityed_media.c | 6 +++++-
>  3 files changed, 13 insertions(+), 4 deletions(-)
> 
> diff --git a/source3/modules/vfs_preopen.c b/source3/modules/vfs_preopen.c
> index 84b13556195..24d33fafacd 100644
> --- a/source3/modules/vfs_preopen.c
> +++ b/source3/modules/vfs_preopen.c
> @@ -345,6 +345,7 @@ static bool preopen_parse_fname(const char *fname, unsigned long *pnum,
>  	const char *p;
>  	char *q = NULL;
>  	unsigned long num;
> +	int error = 0;
>  
>  	p = strrchr_m(fname, '/');
>  	if (p == NULL) {
> @@ -363,7 +364,10 @@ static bool preopen_parse_fname(const char *fname, unsigned long *pnum,
>  		return false;
>  	}
>  
> -	num = strtoul(p, (char **)&q, 10);
> +	num = strtoul_err(p, (char **)&q, 10, &error);
> +	if (error != 0) {
> +		return false;
> +	}
>  
>  	if (num+1 < num) {
>  		/* overflow */
> diff --git a/source3/modules/vfs_snapper.c b/source3/modules/vfs_snapper.c
> index 443a940b17a..0f52f9e71c5 100644
> --- a/source3/modules/vfs_snapper.c
> +++ b/source3/modules/vfs_snapper.c
> @@ -1218,6 +1218,7 @@ static NTSTATUS snapper_snap_path_to_id(TALLOC_CTX *mem_ctx,
>  	char *str_idx;
>  	char *str_end;
>  	uint32_t snap_id;
> +	int error = 0;
>  
>  	path_dup = talloc_strdup(mem_ctx, snap_path);
>  	if (path_dup == NULL) {
> @@ -1250,8 +1251,8 @@ static NTSTATUS snapper_snap_path_to_id(TALLOC_CTX *mem_ctx,
>  	}
>  
>  	str_idx++;
> -	snap_id = strtoul(str_idx, &str_end, 10);
> -	if (str_idx == str_end) {
> +	snap_id = strtoul_err(str_idx, &str_end, 10, &error);
> +	if (error != 0 || str_idx == str_end) {
>  		talloc_free(path_dup);
>  		return NT_STATUS_INVALID_PARAMETER;
>  	}
> diff --git a/source3/modules/vfs_unityed_media.c b/source3/modules/vfs_unityed_media.c
> index 235adf523a3..fa200e64b61 100644
> --- a/source3/modules/vfs_unityed_media.c
> +++ b/source3/modules/vfs_unityed_media.c
> @@ -103,6 +103,7 @@ static bool get_digit_group(const char *path, uintmax_t *digit)
>  	char *endp = NULL;
>  	codepoint_t cp;
>  	size_t size;
> +	int error;
>  
>  	DEBUG(10, ("get_digit_group entering with path '%s'\n",
>  		   path));
> @@ -120,7 +121,10 @@ static bool get_digit_group(const char *path, uintmax_t *digit)
>  			return false;
>  		}
>  		if ((size == 1) && (isdigit(cp))) {
> -			*digit = (uintmax_t)strtoul(p, &endp, 10);
> +			*digit = (uintmax_t)strtoul_err(p, &endp, 10, &error);
> +			if (error != 0) {
> +				return false;
> +			}
>  			DEBUG(10, ("num_suffix = '%ju'\n",
>  				   *digit));
>  			return true;
> -- 
> 2.20.1
> 
> 
> From dd8349c4ae9e4af032cfee39181a0d41a65a102e Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Mon, 28 Jan 2019 14:35:30 +0100
> Subject: [PATCH 08/19] rpcclient: Use wrapper for string to integer conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  source3/rpcclient/cmd_samr.c    | 7 ++++++-
>  source3/rpcclient/cmd_spoolss.c | 8 +++++++-
>  2 files changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c
> index 7e396f92a48..898ae6ad6fc 100644
> --- a/source3/rpcclient/cmd_samr.c
> +++ b/source3/rpcclient/cmd_samr.c
> @@ -1406,13 +1406,18 @@ static NTSTATUS cmd_samr_delete_alias(struct rpc_pipe_client *cli,
>  	uint32_t alias_rid;
>  	uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS;
>  	struct dcerpc_binding_handle *b = cli->binding_handle;
> +	int error = 0;
>  
>  	if (argc != 3) {
>  		printf("Usage: %s builtin|domain [rid|name]\n", argv[0]);
>  		return NT_STATUS_OK;
>  	}
>  
> -	alias_rid = strtoul(argv[2], NULL, 10);
> +	alias_rid = strtoul_err(argv[2], NULL, 10, &error);
> +	if (error != 0) {
> +		return NT_STATUS_INVALID_PARAMETER;
> +	}
> +
>  
>  	/* Open SAMR handle */
>  
> diff --git a/source3/rpcclient/cmd_spoolss.c b/source3/rpcclient/cmd_spoolss.c
> index 0a850ddc6aa..f6d631761b2 100644
> --- a/source3/rpcclient/cmd_spoolss.c
> +++ b/source3/rpcclient/cmd_spoolss.c
> @@ -2642,6 +2642,7 @@ static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
>  	union spoolss_PrinterData data;
>  	DATA_BLOB blob;
>  	struct dcerpc_binding_handle *b = cli->binding_handle;
> +	int error = 0;
>  
>  	/* parse the command arguments */
>  	if (argc < 5) {
> @@ -2707,7 +2708,12 @@ static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
>  		W_ERROR_HAVE_NO_MEMORY(data.string);
>  		break;
>  	case REG_DWORD:
> -		data.value = strtoul(argv[4], NULL, 10);
> +		data.value = strtoul_err(argv[4], NULL, 10, &error);
> +		if (error != 0) {
> +			result = WERR_INVALID_PARAMETER;
> +			goto done;
> +		}
> +
>  		break;
>  	case REG_BINARY:
>  		data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
> -- 
> 2.20.1
> 
> 
> From 8fde0768ecedb5c6e817de0c817797ebc6ae45f6 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Tue, 29 Jan 2019 13:03:20 +0100
> Subject: [PATCH 09/19] ctdb-protocol: Use wrapper for string to integer
>  conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  ctdb/protocol/protocol_util.c | 11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/ctdb/protocol/protocol_util.c b/ctdb/protocol/protocol_util.c
> index 75427e44f50..f22afea20df 100644
> --- a/ctdb/protocol/protocol_util.c
> +++ b/ctdb/protocol/protocol_util.c
> @@ -26,6 +26,7 @@
>  
>  #include "protocol.h"
>  #include "protocol_util.h"
> +#include "lib/util/util.h"
>  
>  static struct {
>  	enum ctdb_runstate runstate;
> @@ -286,8 +287,8 @@ int ctdb_sock_addr_from_string(const char *str,
>  		return EINVAL;
>  	}
>  
> -	port = strtoul(p+1, &endp, 10);
> -	if (endp == p+1 || *endp != '\0') {
> +	port = strtoul_err(p+1, &endp, 10, &ret);
> +	if (endp == p+1 || *endp != '\0' || ret != 0) {
>  		/* Empty string or trailing garbage */
>  		return EINVAL;
>  	}
> @@ -309,7 +310,7 @@ int ctdb_sock_addr_mask_from_string(const char *str,
>  	unsigned int m;
>  	char *endp = NULL;
>  	ssize_t len;
> -	bool ret;
> +	int ret;
>  
>  	if (addr == NULL || mask == NULL) {
>  		return EINVAL;
> @@ -325,8 +326,8 @@ int ctdb_sock_addr_mask_from_string(const char *str,
>  		return EINVAL;
>  	}
>  
> -	m = strtoul(p+1, &endp, 10);
> -	if (endp == p+1 || *endp != '\0') {
> +	m = strtoul_err(p+1, &endp, 10, &ret);
> +	if (endp == p+1 || *endp != '\0' || ret != 0) {
>  		/* Empty string or trailing garbage */
>  		return EINVAL;
>  	}
> -- 
> 2.20.1
> 
> 
> From 5c24c1c00d5768866e3887a0546235125c61689e Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Tue, 29 Jan 2019 13:07:56 +0100
> Subject: [PATCH 10/19] ctdb-server: Use wrapper for string to integer
>  conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  ctdb/server/ctdb_recovery_helper.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/ctdb/server/ctdb_recovery_helper.c b/ctdb/server/ctdb_recovery_helper.c
> index 7fdcc2e5a29..627b3ebdca3 100644
> --- a/ctdb/server/ctdb_recovery_helper.c
> +++ b/ctdb/server/ctdb_recovery_helper.c
> @@ -30,6 +30,7 @@
>  #include "lib/util/sys_rw.h"
>  #include "lib/util/time.h"
>  #include "lib/util/tevent_unix.h"
> +#include "lib/util/util.h"
>  
>  #include "protocol/protocol.h"
>  #include "protocol/protocol_api.h"
> @@ -2750,7 +2751,11 @@ int main(int argc, char *argv[])
>  
>  	write_fd = atoi(argv[1]);
>  	sockpath = argv[2];
> -	generation = (uint32_t)strtoul(argv[3], NULL, 0);
> +	generation = (uint32_t)strtoul_err(argv[3], NULL, 0, &ret);
> +	if (ret != 0) {
> +		fprintf(stderr, "recovery: unable to initialize generation\n");
> +		goto failed;
> +	}
>  
>  	mem_ctx = talloc_new(NULL);
>  	if (mem_ctx == NULL) {
> -- 
> 2.20.1
> 
> 
> From 618255b5e3a757ec803b77d6c764b9f2a01f8917 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Tue, 29 Jan 2019 13:27:28 +0100
> Subject: [PATCH 11/19] ctdb-tools: Use wrapper for string to integer
>  conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  ctdb/tools/ctdb.c | 45 ++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 34 insertions(+), 11 deletions(-)
> 
> diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c
> index bef9c5f97fb..677551823a8 100644
> --- a/ctdb/tools/ctdb.c
> +++ b/ctdb/tools/ctdb.c
> @@ -315,6 +315,7 @@ static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
>  		goto done;
>  	} else {
>  		char *ns, *tok;
> +		int error = 0;
>  
>  		ns = talloc_strdup(mem_ctx, nodestring);
>  		if (ns == NULL) {
> @@ -326,8 +327,8 @@ static bool parse_nodestring(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
>  			uint32_t pnn;
>  			char *endptr;
>  
> -			pnn = (uint32_t)strtoul(tok, &endptr, 0);
> -			if (pnn == 0 && tok == endptr) {
> +			pnn = (uint32_t)strtoul_err(tok, &endptr, 0, &error);
> +			if (error != 0 || (pnn == 0 && tok == endptr)) {
>  				fprintf(stderr, "Invalid node %s\n", tok);
>  					return false;
>  			}
> @@ -544,7 +545,10 @@ static bool db_exists(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
>  	}
>  
>  	if (strncmp(db_arg, "0x", 2) == 0) {
> -		id = strtoul(db_arg, NULL, 0);
> +		id = strtoul_err(db_arg, NULL, 0, &ret);
> +		if (ret != 0) {
> +			return false;
> +		}
>  		for (i=0; i<dbmap->num; i++) {
>  			if (id == dbmap->dbs[i].db_id) {
>  				db = &dbmap->dbs[i];
> @@ -1089,7 +1093,10 @@ static int control_setvar(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
>  	}
>  
>  	tunable.name = argv[0];
> -	tunable.value = strtoul(argv[1], NULL, 0);
> +	tunable.value = strtoul_err(argv[1], NULL, 0, &ret);
> +	if (ret != 0) {
> +		return ret;
> +	}
>  
>  	ret = ctdb_ctrl_set_tunable(mem_ctx, ctdb->ev, ctdb->client,
>  				    ctdb->cmd_pnn, TIMEOUT(), &tunable);
> @@ -1875,7 +1882,10 @@ static int control_process_exists(TALLOC_CTX *mem_ctx,
>  
>  	pid = atoi(argv[0]);
>  	if (argc == 2) {
> -		srvid = strtoull(argv[1], NULL, 0);
> +		srvid = strtoull_err(argv[1], NULL, 0, &ret);
> +		if (ret != 0) {
> +			return ret;
> +		}
>  	}
>  
>  	if (srvid == 0) {
> @@ -2779,7 +2789,10 @@ static int control_ban(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
>  	}
>  
>  	ban_state.pnn = ctdb->cmd_pnn;
> -	ban_state.time = strtoul(argv[0], NULL, 0);
> +	ban_state.time = strtoul_err(argv[0], NULL, 0, &ret);
> +	if (ret != 0) {
> +		return ret;
> +	}
>  
>  	if (ban_state.time == 0) {
>  		fprintf(stderr, "Ban time cannot be zero\n");
> @@ -3099,7 +3112,10 @@ static int control_gettickles(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
>  	}
>  
>  	if (argc == 2) {
> -		port = strtoul(argv[1], NULL, 10);
> +		port = strtoul_err(argv[1], NULL, 10, &ret);
> +		if (ret != 0) {
> +			return ret;
> +		}
>  	}
>  
>  	ret = ctdb_sock_addr_from_string(argv[0], &addr, false);
> @@ -3804,8 +3820,8 @@ static int control_moveip(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
>  		return 1;
>  	}
>  
> -	pnn = strtoul(argv[1], NULL, 10);
> -	if (pnn == CTDB_UNKNOWN_PNN) {
> +	pnn = strtoul_err(argv[1], NULL, 10, &ret);
> +	if (pnn == CTDB_UNKNOWN_PNN || ret != 0) {
>  		fprintf(stderr, "Invalid PNN %s\n", argv[1]);
>  		return 1;
>  	}
> @@ -5257,7 +5273,10 @@ static int control_tstore(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb,
>  	ZERO_STRUCT(header);
>  
>  	if (argc > 3) {
> -		header.rsn = (uint64_t)strtoull(argv[3], NULL, 0);
> +		header.rsn = (uint64_t)strtoull_err(argv[3], NULL, 0, &ret);
> +		if (ret != 0) {
> +			return ret;
> +		}
>  	}
>  	if (argc > 4) {
>  		header.dmaster = (uint32_t)atol(argv[4]);
> @@ -6269,7 +6288,11 @@ int main(int argc, const char *argv[])
>  
>  		ctdb_timeout = getenv("CTDB_TIMEOUT");
>  		if (ctdb_timeout != NULL) {
> -			options.maxruntime = strtoul(ctdb_timeout, NULL, 0);
> +			options.maxruntime = strtoul_err(ctdb_timeout, NULL, 0, &ret);
> +			if (ret != 0) {
> +				fprintf(stderr, "Invalid value CTDB_TIMEOUT\n");
> +				exit(1);
> +			}
>  		} else {
>  			options.maxruntime = 120;
>  		}
> -- 
> 2.20.1
> 
> 
> From 4b041d4bc76734ed95f0bc3d1b1b1f77ac06e241 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Tue, 29 Jan 2019 14:21:25 +0100
> Subject: [PATCH 12/19] libwbclient: Use wrapper for string to integer
>  conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  nsswitch/libwbclient/wbc_idmap.c | 10 +++++----
>  nsswitch/libwbclient/wbc_sid.c   | 36 ++++++++++++++++++--------------
>  nsswitch/libwbclient/wscript     |  2 +-
>  3 files changed, 27 insertions(+), 21 deletions(-)
> 
> diff --git a/nsswitch/libwbclient/wbc_idmap.c b/nsswitch/libwbclient/wbc_idmap.c
> index f61efb92b8d..29500b61e6e 100644
> --- a/nsswitch/libwbclient/wbc_idmap.c
> +++ b/nsswitch/libwbclient/wbc_idmap.c
> @@ -24,6 +24,7 @@
>  #include "replace.h"
>  #include "libwbclient.h"
>  #include "../winbind_client.h"
> +#include "lib/util/util.h"
>  
>  /* Convert a Windows SID to a Unix uid, allocating an uid if needed */
>  wbcErr wbcCtxSidToUid(struct wbcContext *ctx, const struct wbcDomainSid *sid,
> @@ -374,26 +375,27 @@ wbcErr wbcCtxSidsToUnixIds(struct wbcContext *ctx,
>  	for (i=0; i<num_sids; i++) {
>  		struct wbcUnixId *id = &ids[i];
>  		char *q;
> +		int error = 0;
>  
>  		switch (p[0]) {
>  		case 'U':
>  			id->type = WBC_ID_TYPE_UID;
> -			id->id.uid = strtoul(p+1, &q, 10);
> +			id->id.uid = strtoul_err(p+1, &q, 10, &error);
>  			break;
>  		case 'G':
>  			id->type = WBC_ID_TYPE_GID;
> -			id->id.gid = strtoul(p+1, &q, 10);
> +			id->id.gid = strtoul_err(p+1, &q, 10, &error);
>  			break;
>  		case 'B':
>  			id->type = WBC_ID_TYPE_BOTH;
> -			id->id.uid = strtoul(p+1, &q, 10);
> +			id->id.uid = strtoul_err(p+1, &q, 10, &error);
>  			break;
>  		default:
>  			id->type = WBC_ID_TYPE_NOT_SPECIFIED;
>  			q = strchr(p, '\n');
>  			break;
>  		};
> -		if (q == NULL || q[0] != '\n') {
> +		if (q == NULL || q[0] != '\n' || error != 0) {
>  			goto wbc_err_invalid;
>  		}
>  		p = q+1;
> diff --git a/nsswitch/libwbclient/wbc_sid.c b/nsswitch/libwbclient/wbc_sid.c
> index 77445afc5e9..464f1aedd76 100644
> --- a/nsswitch/libwbclient/wbc_sid.c
> +++ b/nsswitch/libwbclient/wbc_sid.c
> @@ -26,6 +26,7 @@
>  #include "replace.h"
>  #include "libwbclient.h"
>  #include "../winbind_client.h"
> +#include "lib/util/util.h"
>  
>  /* Convert a sid to a string into a buffer. Return the string
>   * length. If buflen is too small, return the string length that would
> @@ -99,6 +100,7 @@ wbcErr wbcStringToSid(const char *str,
>  {
>  	const char *p;
>  	char *q;
> +	int error;
>  	uint64_t x;
>  	wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
>  
> @@ -120,8 +122,8 @@ wbcErr wbcStringToSid(const char *str,
>  	/* Get the SID revision number */
>  
>  	p = str+2;
> -	x = (uint64_t)strtoul(p, &q, 10);
> -	if (x==0 || x > UINT8_MAX || !q || *q!='-') {
> +	x = (uint64_t)strtoul_err(p, &q, 10, &error);
> +	if (x == 0 || x > UINT8_MAX || !q || *q != '-' || error != 0) {
>  		wbc_status = WBC_ERR_INVALID_SID;
>  		BAIL_ON_WBC_ERROR(wbc_status);
>  	}
> @@ -133,8 +135,8 @@ wbcErr wbcStringToSid(const char *str,
>  	 * be expressed as a hex value, according to MS-DTYP.
>  	 */
>  	p = q+1;
> -	x = strtoull(p, &q, 0);
> -	if (!q || *q!='-' || (x & AUTHORITY_MASK)) {
> +	x = strtoull_err(p, &q, 0, &error);
> +	if (!q || *q != '-' || (x & AUTHORITY_MASK) || error != 0) {
>  		wbc_status = WBC_ERR_INVALID_SID;
>  		BAIL_ON_WBC_ERROR(wbc_status);
>  	}
> @@ -149,10 +151,10 @@ wbcErr wbcStringToSid(const char *str,
>  	p = q +1;
>  	sid->num_auths = 0;
>  	while (sid->num_auths < WBC_MAXSUBAUTHS) {
> -		x = strtoull(p, &q, 10);
> +		x = strtoull_err(p, &q, 10, &error);
>  		if (p == q)
>  			break;
> -		if (x > UINT32_MAX) {
> +		if (x > UINT32_MAX || error != 0) {
>  			wbc_status = WBC_ERR_INVALID_SID;
>  			BAIL_ON_WBC_ERROR(wbc_status);
>  		}
> @@ -337,6 +339,7 @@ wbcErr wbcCtxLookupSids(struct wbcContext *ctx,
>  	char *sidlist, *p, *q, *extra_data;
>  	struct wbcDomainInfo *domains = NULL;
>  	struct wbcTranslatedName *names = NULL;
> +	int error;
>  
>  	buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1;
>  
> @@ -386,8 +389,8 @@ wbcErr wbcCtxLookupSids(struct wbcContext *ctx,
>  
>  	p = extra_data;
>  
> -	num_domains = strtoul(p, &q, 10);
> -	if (*q != '\n') {
> +	num_domains = strtoul_err(p, &q, 10, &error);
> +	if (*q != '\n' || error != 0) {
>  		goto wbc_err_invalid;
>  	}
>  	p = q+1;
> @@ -426,8 +429,8 @@ wbcErr wbcCtxLookupSids(struct wbcContext *ctx,
>  		p = q+1;
>  	}
>  
> -	num_names = strtoul(p, &q, 10);
> -	if (*q != '\n') {
> +	num_names = strtoul_err(p, &q, 10, &error);
> +	if (*q != '\n' || error != 0) {
>  		goto wbc_err_invalid;
>  	}
>  	p = q+1;
> @@ -446,8 +449,8 @@ wbcErr wbcCtxLookupSids(struct wbcContext *ctx,
>  
>  	for (i=0; i<num_names; i++) {
>  
> -		names[i].domain_index = strtoul(p, &q, 10);
> -		if (names[i].domain_index < 0) {
> +		names[i].domain_index = strtoul_err(p, &q, 10, &error);
> +		if (names[i].domain_index < 0 || error != 0) {
>  			goto wbc_err_invalid;
>  		}
>  		if (names[i].domain_index >= num_domains) {
> @@ -459,8 +462,8 @@ wbcErr wbcCtxLookupSids(struct wbcContext *ctx,
>  		}
>  		p = q+1;
>  
> -		names[i].type = strtoul(p, &q, 10);
> -		if (*q != ' ') {
> +		names[i].type = strtoul_err(p, &q, 10, &error);
> +		if (*q != ' ' || error != 0) {
>  			goto wbc_err_invalid;
>  		}
>  		p = q+1;
> @@ -515,6 +518,7 @@ wbcErr wbcCtxLookupRids(struct wbcContext *ctx, struct wbcDomainSid *dom_sid,
>  	size_t i, len, ridbuf_size;
>  	char *ridlist;
>  	char *p;
> +	int error;
>  	struct winbindd_request request;
>  	struct winbindd_response response;
>  	char *domain_name = NULL;
> @@ -581,9 +585,9 @@ wbcErr wbcCtxLookupRids(struct wbcContext *ctx, struct wbcDomainSid *dom_sid,
>  			goto done;
>  		}
>  
> -		types[i] = (enum wbcSidType)strtoul(p, &q, 10);
> +		types[i] = (enum wbcSidType)strtoul_err(p, &q, 10, &error);
>  
> -		if (*q != ' ') {
> +		if (*q != ' ' || error != 0) {
>  			wbc_status = WBC_ERR_INVALID_RESPONSE;
>  			goto done;
>  		}
> diff --git a/nsswitch/libwbclient/wscript b/nsswitch/libwbclient/wscript
> index 7bb612d670a..d926067df91 100644
> --- a/nsswitch/libwbclient/wscript
> +++ b/nsswitch/libwbclient/wscript
> @@ -37,7 +37,7 @@ def build(bld):
>                               wbc_pwd.c
>                               wbc_sid.c
>                               wbc_util.c''',
> -                      deps='winbind-client',
> +                      deps='winbind-client samba-util',
>                        pc_files='wbclient.pc',
>                        public_headers='wbclient.h',
>                        abi_directory='ABI',
> -- 
> 2.20.1
> 
> 
> From 9d544d8b071f86f9eb999db9cdbe5e394d5e5d24 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Tue, 29 Jan 2019 14:36:44 +0100
> Subject: [PATCH 13/19] wbinfo: Use wrapper for string to integer conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  nsswitch/wbinfo.c | 13 ++++++++++---
>  1 file changed, 10 insertions(+), 3 deletions(-)
> 
> diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c
> index b6f0ff8ccbf..d67f7c75888 100644
> --- a/nsswitch/wbinfo.c
> +++ b/nsswitch/wbinfo.c
> @@ -141,6 +141,7 @@ static bool parse_wbinfo_domain_user(const char *domuser, fstring domain,
>  static bool parse_mapping_arg(char *arg, int *id, char **sid)
>  {
>  	char *tmp, *endptr;
> +	int error;
>  
>  	if (!arg || !*arg)
>  		return false;
> @@ -153,9 +154,9 @@ static bool parse_mapping_arg(char *arg, int *id, char **sid)
>  
>  	/* Because atoi() can return 0 on invalid input, which would be a valid
>  	 * UID/GID we must use strtoul() and do error checking */
> -	*id = strtoul(tmp, &endptr, 10);
> +	*id = strtoul_err(tmp, &endptr, 10, &error);
>  
> -	if (endptr[0] != '\0')
> +	if (endptr[0] != '\0' || error != 0)
>  		return false;
>  
>  	return true;
> @@ -1417,7 +1418,13 @@ static bool wbinfo_lookuprids(const char *domain, const char *arg)
>  	p = arg;
>  
>  	while (next_token_talloc(mem_ctx, &p, &ridstr, " ,\n")) {
> -		uint32_t rid = strtoul(ridstr, NULL, 10);
> +		int error;
> +		uint32_t rid = strtoul_err(ridstr, NULL, 10, &error);
> +
> +		if (error != 0) {
> +			d_printf("failed to conver rid\n");
> +			goto done;
> +		}
>  		rids = talloc_realloc(mem_ctx, rids, uint32_t, num_rids + 1);
>  		if (rids == NULL) {
>  			d_printf("talloc_realloc failed\n");
> -- 
> 2.20.1
> 
> 
> From e068f51edacc76dd4f3ad7793076dfccc64b1d65 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Wed, 30 Jan 2019 08:33:02 +0100
> Subject: [PATCH 14/19] common-lib: Use wrapper for string to integer
>  conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  lib/ldb-samba/ldb_matching_rules.c | 19 +++++++++++++++----
>  lib/ldb-samba/ldif_handlers.c      |  7 +++++--
>  lib/param/loadparm.c               | 24 ++++++++++++++++++++----
>  lib/util/access.c                  |  6 ++++--
>  lib/util/asn1.c                    | 17 +++++++++++------
>  lib/util/util_str.c                | 10 ++++++----
>  6 files changed, 61 insertions(+), 22 deletions(-)
> 
> diff --git a/lib/ldb-samba/ldb_matching_rules.c b/lib/ldb-samba/ldb_matching_rules.c
> index 2aaaeb7450b..51909d966dc 100644
> --- a/lib/ldb-samba/ldb_matching_rules.c
> +++ b/lib/ldb-samba/ldb_matching_rules.c
> @@ -383,15 +383,20 @@ static int dsdb_match_for_dns_to_tombstone_time(struct ldb_context *ldb,
>  		return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
>  	} else {
>  		char *p = NULL;
> +		int error;
>  		char s[value_to_match->length+1];
> +
>  		memcpy(s, value_to_match->data, value_to_match->length);
>  		s[value_to_match->length] = 0;
>  		if (s[0] == '\0' || s[0] == '-') {
>  			DBG_ERR("Empty timestamp passed\n");
>  			return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
>  		}
> -		tombstone_time = strtoull(s, &p, 10);
> -		if (p == NULL || p == s || *p != '\0' ||
> +		tombstone_time = strtoull_err(s, &p, 10, &error);
> +		if (p == NULL ||
> +		    p == s ||
> +		    *p != '\0' ||
> +		    error != 0 ||
>  		    tombstone_time == ULLONG_MAX) {
>  			DBG_ERR("Invalid timestamp string passed\n");
>  			return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
> @@ -514,14 +519,20 @@ static int dsdb_match_for_expunge(struct ldb_context *ldb,
>  		return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
>  	} else {
>  		char *p = NULL;
> +		int error;
>  		char s[value_to_match->length+1];
> +
>  		memcpy(s, value_to_match->data, value_to_match->length);
>  		s[value_to_match->length] = 0;
>  		if (s[0] == '\0' || s[0] == '-') {
>  			return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
>  		}
> -		tombstone_time = strtoull(s, &p, 10);
> -		if (p == NULL || p == s || *p != '\0' || tombstone_time == ULLONG_MAX) {
> +		tombstone_time = strtoull_err(s, &p, 10, &error);
> +		if (p == NULL ||
> +		    p == s ||
> +		    *p != '\0' ||
> +		    error != 0 ||
> +		    tombstone_time == ULLONG_MAX) {
>  			return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
>  		}
>  	}
> diff --git a/lib/ldb-samba/ldif_handlers.c b/lib/ldb-samba/ldif_handlers.c
> index ecc02e51c1d..9ae82400c73 100644
> --- a/lib/ldb-samba/ldif_handlers.c
> +++ b/lib/ldb-samba/ldif_handlers.c
> @@ -596,6 +596,8 @@ static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
>  
>  	line = string;
>  	while (line && line[0]) {
> +		int error;
> +
>  		p=strchr(line, ';');
>  		if (p) {
>  			p[0] = '\0';
> @@ -619,9 +621,10 @@ static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
>  			return -1;
>  		}
>  
> -		blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
> +		blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix =
> +			strtoul_err(line, &oid, 10, &error);
>  
> -		if (oid[0] != ':') {
> +		if (oid[0] != ':' || error != 0) {
>  			talloc_free(tmp_ctx);
>  			return -1;
>  		}
> diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
> index f31ef2319ac..89849762760 100644
> --- a/lib/param/loadparm.c
> +++ b/lib/param/loadparm.c
> @@ -331,13 +331,21 @@ int lp_int(const char *s)
>   */
>  unsigned long lp_ulong(const char *s)
>  {
> +	int error;
> +	unsigned long int ret;
>  
>  	if (!s || !*s) {
> -		DEBUG(0,("lp_ulong(%s): is called with NULL!\n",s));
> +		DBG_DEBUG("lp_ulong(%s): is called with NULL!\n",s);
>  		return -1;
>  	}
>  
> -	return strtoul(s, NULL, 0);
> +	ret = strtoul_err(s, NULL, 0, &error);
> +	if (error != 0) {
> +		DBG_DEBUG("lp_ulong(%s): conversion failed\n",s);
> +		return -1;
> +	}
> +
> +	return ret;
>  }
>  
>  /**
> @@ -345,13 +353,21 @@ unsigned long lp_ulong(const char *s)
>   */
>  unsigned long long lp_ulonglong(const char *s)
>  {
> +	int error;
> +	unsigned long long int ret;
>  
>  	if (!s || !*s) {
> -		DEBUG(0, ("lp_ulonglong(%s): is called with NULL!\n", s));
> +		DBG_DEBUG("lp_ulonglong(%s): is called with NULL!\n", s);
>  		return -1;
>  	}
>  
> -	return strtoull(s, NULL, 0);
> +	ret = strtoull_err(s, NULL, 0, &error);
> +	if (error != 0) {
> +		DBG_DEBUG("lp_ulonglong(%s): conversion failed\n",s);
> +		return -1;
> +	}
> +
> +	return ret;
>  }
>  
>  /**
> diff --git a/lib/util/access.c b/lib/util/access.c
> index 7da0573a74d..7d52bc0278f 100644
> --- a/lib/util/access.c
> +++ b/lib/util/access.c
> @@ -71,8 +71,10 @@ static bool masked_match(const char *tok, const char *slash, const char *s)
>  		}
>          } else {
>  		char *endp = NULL;
> -		unsigned long val = strtoul(slash+1, &endp, 0);
> -		if (slash+1 == endp || (endp && *endp != '\0')) {
> +		int error;
> +		unsigned long val = strtoul_err(slash+1, &endp, 0, &error);
> +
> +		if (slash+1 == endp || (endp && *endp != '\0') || error != 0) {
>  			return false;
>  		}
>  		if (!make_netmask(&ss_mask, &ss_tok, val)) {
> diff --git a/lib/util/asn1.c b/lib/util/asn1.c
> index 60ddfa09bcf..736ca9cfe9f 100644
> --- a/lib/util/asn1.c
> +++ b/lib/util/asn1.c
> @@ -273,15 +273,20 @@ bool ber_write_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *OID)
>  	const char *p = (const char *)OID;
>  	char *newp;
>  	int i;
> +	int error;
>  
>  	if (!isdigit(*p)) return false;
> -	v = strtoul(p, &newp, 10);
> -	if (newp[0] != '.') return false;
> +	v = strtoul_err(p, &newp, 10, &error);
> +	if (newp[0] != '.' || error != 0) {
> +		return false;
> +	}
>  	p = newp + 1;
>  
>  	if (!isdigit(*p)) return false;
> -	v2 = strtoul(p, &newp, 10);
> -	if (newp[0] != '.') return false;
> +	v2 = strtoul_err(p, &newp, 10, &error);
> +	if (newp[0] != '.' || error != 0) {
> +		return false;
> +	}
>  	p = newp + 1;
>  
>  	/*the ber representation can't use more space than the string one */
> @@ -293,8 +298,8 @@ bool ber_write_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *OID)
>  	i = 1;
>  	while (*p) {
>  		if (!isdigit(*p)) return false;
> -		v = strtoul(p, &newp, 10);
> -		if (newp[0] == '.') {
> +		v = strtoul_err(p, &newp, 10, &error);
> +		if (newp[0] == '.' || error != 0) {
>  			p = newp + 1;
>  			/* check for empty last component */
>  			if (!*p) return false;
> diff --git a/lib/util/util_str.c b/lib/util/util_str.c
> index c7d91ca3744..7368f6f9c3f 100644
> --- a/lib/util/util_str.c
> +++ b/lib/util/util_str.c
> @@ -63,13 +63,14 @@ _PUBLIC_ bool conv_str_size_error(const char * str, uint64_t * val)
>  {
>  	char *		    end = NULL;
>  	unsigned long long  lval;
> +	int error;
>  
>  	if (str == NULL || *str == '\0') {
>  		return false;
>  	}
>  
> -	lval = strtoull(str, &end, 10 /* base */);
> -	if (end == NULL || end == str) {
> +	lval = strtoull_err(str, &end, 10, &error);
> +	if (end == NULL || end == str || error != 0) {
>  		return false;
>  	}
>  
> @@ -104,13 +105,14 @@ _PUBLIC_ bool conv_str_u64(const char * str, uint64_t * val)
>  {
>  	char *		    end = NULL;
>  	unsigned long long  lval;
> +	int error;
>  
>  	if (str == NULL || *str == '\0') {
>  		return false;
>  	}
>  
> -	lval = strtoull(str, &end, 10 /* base */);
> -	if (end == NULL || *end != '\0' || end == str) {
> +	lval = strtoull_err(str, &end, 10, &error);
> +	if (end == NULL || *end != '\0' || end == str || error != 0) {
>  		return false;
>  	}
>  
> -- 
> 2.20.1
> 
> 
> From 24fbd4b0c0c3981d917aab13c5366e48acab98e7 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Wed, 30 Jan 2019 08:39:15 +0100
> Subject: [PATCH 15/19] libcli: Use wrapper for string to integer conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  libcli/security/dom_sid.c | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
> 
> diff --git a/libcli/security/dom_sid.c b/libcli/security/dom_sid.c
> index 2a0b60c3dd7..f36bd7016bc 100644
> --- a/libcli/security/dom_sid.c
> +++ b/libcli/security/dom_sid.c
> @@ -24,6 +24,7 @@
>  #include "lib/util/data_blob.h"
>  #include "system/locale.h"
>  #include "lib/util/debug.h"
> +#include "lib/util/util.h"
>  #include "librpc/gen_ndr/security.h"
>  #include "dom_sid.h"
>  
> @@ -132,6 +133,7 @@ bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
>  	char *q;
>  	/* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
>  	uint64_t conv;
> +	int error;
>  
>  	ZERO_STRUCTP(sidout);
>  
> @@ -146,8 +148,8 @@ bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
>  		goto format_error;
>  	}
>  
> -	conv = strtoul(p, &q, 10);
> -	if (!q || (*q != '-') || conv > UINT8_MAX) {
> +	conv = strtoul_err(p, &q, 10, &error);
> +	if (!q || (*q != '-') || conv > UINT8_MAX || error != 0) {
>  		goto format_error;
>  	}
>  	sidout->sid_rev_num = (uint8_t) conv;
> @@ -158,8 +160,8 @@ bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
>  	}
>  
>  	/* get identauth */
> -	conv = strtoull(q, &q, 0);
> -	if (!q || conv & AUTHORITY_MASK) {
> +	conv = strtoull_err(q, &q, 0, &error);
> +	if (!q || conv & AUTHORITY_MASK || error != 0) {
>  		goto format_error;
>  	}
>  
> @@ -187,8 +189,8 @@ bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
>  			goto format_error;
>  		}
>  
> -		conv = strtoull(q, &end, 10);
> -		if (end == q || conv > UINT32_MAX) {
> +		conv = strtoull_err(q, &end, 10, &error);
> +		if (end == q || conv > UINT32_MAX || error != 0) {
>  			goto format_error;
>  		}
>  
> -- 
> 2.20.1
> 
> 
> From f65ee583e5bd0887cea16188b9f74596077ffc13 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Wed, 30 Jan 2019 09:31:34 +0100
> Subject: [PATCH 16/19] source4: Use wrapper for string to integer conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  source4/dns_server/dlz_bind9.c                |  6 +++++-
>  source4/dsdb/common/dsdb_dn.c                 |  5 +++--
>  source4/dsdb/common/util.c                    | 17 ++++++++++++----
>  source4/dsdb/samdb/ldb_modules/dirsync.c      | 15 +++++++++++++-
>  .../samdb/ldb_modules/partition_metadata.c    |  7 ++++++-
>  source4/dsdb/samdb/ldb_modules/samldb.c       |  5 +++--
>  source4/dsdb/samdb/ldb_modules/schema_load.c  |  8 +++++++-
>  source4/dsdb/schema/schema_prefixmap.c        |  6 +++++-
>  source4/lib/registry/ldb.c                    | 20 +++++++++++++++++--
>  source4/lib/socket/interface.c                |  6 ++++--
>  source4/libcli/resolve/dns_ex.c               |  5 +++--
>  source4/nbt_server/wins/winsdb.c              | 12 ++++++++++-
>  source4/rpc_server/lsa/dcesrv_lsa.c           |  9 ++++++---
>  source4/torture/nbench/nbench.c               |  8 +++++++-
>  source4/torture/smb2/sharemode.c              |  7 ++++++-
>  source4/web_server/web_server.c               |  7 ++++++-
>  16 files changed, 117 insertions(+), 26 deletions(-)
> 
> diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c
> index 82c72111a00..83f11aa6669 100644
> --- a/source4/dns_server/dlz_bind9.c
> +++ b/source4/dns_server/dlz_bind9.c
> @@ -307,8 +307,12 @@ static bool b9_dns_type(const char *type, enum dns_record_type *dtype)
>  
>  #define DNS_PARSE_UINT(ret, str, sep, saveptr) do {  \
>  	char *istr = strtok_r(str, sep, &saveptr); \
> +	int error;\
>  	if ((istr) == NULL) return false; \
> -	(ret) = strtoul(istr, NULL, 10); \
> +	(ret) = strtoul_err(istr, NULL, 10, &error); \
> +	if (error != 0) {\
> +		return false;\
> +	}\
>  	} while (0)
>  
>  /*
> diff --git a/source4/dsdb/common/dsdb_dn.c b/source4/dsdb/common/dsdb_dn.c
> index 900c6e2df63..2ec02307e40 100644
> --- a/source4/dsdb/common/dsdb_dn.c
> +++ b/source4/dsdb/common/dsdb_dn.c
> @@ -84,6 +84,7 @@ struct dsdb_dn *dsdb_dn_parse_trusted(TALLOC_CTX *mem_ctx, struct ldb_context *l
>  	struct ldb_val bval;
>  	struct ldb_val dval;
>  	char *dn_str;
> +	int error;
>  
>  	enum dsdb_dn_format dn_format = dsdb_dn_oid_to_format(dn_oid);
>  
> @@ -134,8 +135,8 @@ struct dsdb_dn *dsdb_dn_parse_trusted(TALLOC_CTX *mem_ctx, struct ldb_context *l
>  	}
>  
>  	errno = 0;
> -	blen = strtoul(p1, &p2, 10);
> -	if (errno != 0) {
> +	blen = strtoul_err(p1, &p2, 10, &error);
> +	if (error != 0) {
>  		DEBUG(10, (__location__ ": failed\n"));
>  		goto failed;
>  	}
> diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
> index d173a75ebb7..328750be81a 100644
> --- a/source4/dsdb/common/util.c
> +++ b/source4/dsdb/common/util.c
> @@ -3842,6 +3842,7 @@ NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const c
>  NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
>  {
>  	const struct ldb_val *v;
> +	int error;
>  
>  	v = ldb_dn_get_extended_component(dn, component_name);
>  	if (v == NULL) {
> @@ -3856,7 +3857,10 @@ NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const cha
>  		memcpy(s, v->data, v->length);
>  		s[v->length] = 0;
>  
> -		*val = strtoull(s, NULL, 0);
> +		*val = strtoull_err(s, NULL, 0, &error);
> +		if (error != 0) {
> +			return NT_STATUS_INVALID_PARAMETER;
> +		}
>  	}
>  	return NT_STATUS_OK;
>  }
> @@ -3875,6 +3879,7 @@ NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const ch
>  NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
>  {
>  	const struct ldb_val *v;
> +	int error;
>  
>  	v = ldb_dn_get_extended_component(dn, component_name);
>  	if (v == NULL) {
> @@ -3888,7 +3893,10 @@ NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const cha
>  		char s[v->length + 1];
>  		memcpy(s, v->data, v->length);
>  		s[v->length] = 0;
> -		*val = strtoul(s, NULL, 0);
> +		*val = strtoul_err(s, NULL, 0, &error);
> +		if (error != 0) {
> +			return NT_STATUS_INVALID_PARAMETER;
> +		}
>  	}
>  
>  	return NT_STATUS_OK;
> @@ -3942,6 +3950,7 @@ uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
>  	const char *p;
>  	uint32_t flags;
>  	char *end;
> +	int error;
>  
>  	if (val->length < 13) {
>  		return 0;
> @@ -3950,8 +3959,8 @@ uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
>  	if (!p) {
>  		return 0;
>  	}
> -	flags = strtoul(p+11, &end, 10);
> -	if (!end || *end != '>') {
> +	flags = strtoul_err(p+11, &end, 10, &error);
> +	if (!end || *end != '>' || error != 0) {
>  		/* it must end in a > */
>  		return 0;
>  	}
> diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c
> index 2a9895ae641..5f60be14af7 100644
> --- a/source4/dsdb/samdb/ldb_modules/dirsync.c
> +++ b/source4/dsdb/samdb/ldb_modules/dirsync.c
> @@ -157,11 +157,24 @@ static int dirsync_filter_entry(struct ldb_request *req,
>  	for (i = msg->num_elements - 1; i >= 0; i--) {
>  		attr = dsdb_attribute_by_lDAPDisplayName(dsc->schema, msg->elements[i].name);
>  		if (ldb_attr_cmp(msg->elements[i].name, "uSNChanged") == 0) {
> +			int error;
>  			/* Read the USN it will used at the end of the filtering
>  			 * to update the max USN in the cookie if we
>  			 * decide to keep this entry
>  			 */
> -			val = strtoull((const char*)msg->elements[i].values[0].data, NULL, 0);
> +			val = strtoull_err(
> +				(const char*)msg->elements[i].values[0].data,
> +				NULL,
> +				0,
> +				&error);
> +			if (error != 0) {
> +				ldb_set_errstring(ldb,
> +						  "Failed to convert USN");
> +				return ldb_module_done(dsc->req,
> +						       NULL,
> +						       NULL,
> +						       LDB_ERR_OPERATIONS_ERROR);
> +			}
>  			continue;
>  		}
>  
> diff --git a/source4/dsdb/samdb/ldb_modules/partition_metadata.c b/source4/dsdb/samdb/ldb_modules/partition_metadata.c
> index 197e7b092e0..ad145ea7847 100644
> --- a/source4/dsdb/samdb/ldb_modules/partition_metadata.c
> +++ b/source4/dsdb/samdb/ldb_modules/partition_metadata.c
> @@ -36,6 +36,7 @@ static int partition_metadata_get_uint64(struct ldb_module *module,
>  	TDB_DATA tdb_key, tdb_data;
>  	char *value_str;
>  	TALLOC_CTX *tmp_ctx;
> +	int error;
>  
>  	data = talloc_get_type_abort(ldb_module_get_private(module),
>  				     struct partition_private_data);
> @@ -73,7 +74,11 @@ static int partition_metadata_get_uint64(struct ldb_module *module,
>  		return ldb_module_oom(module);
>  	}
>  
> -	*value = strtoull(value_str, NULL, 10);
> +	*value = strtoull_err(value_str, NULL, 10, &error);
> +	if (error != 0) {
> +		return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
> +					"partition_metadata: converision failed");
> +	}
>  
>  	SAFE_FREE(tdb_data.dptr);
>  	talloc_free(tmp_ctx);
> diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
> index e69228c32c7..8615baff363 100644
> --- a/source4/dsdb/samdb/ldb_modules/samldb.c
> +++ b/source4/dsdb/samdb/ldb_modules/samldb.c
> @@ -3313,6 +3313,7 @@ static int verify_cidr(const char *cidr)
>  	char *address_redux = NULL;
>  	unsigned int address_len;
>  	TALLOC_CTX *frame = NULL;
> +	int error;
>  
>  	DBG_DEBUG("CIDR is %s\n", cidr);
>  	frame = talloc_stackframe();
> @@ -3329,14 +3330,14 @@ static int verify_cidr(const char *cidr)
>  	/* terminate the address for strchr, inet_pton */
>  	*slash = '\0';
>  
> -	mask = strtoul(slash + 1, &endptr, 10);
> +	mask = strtoul_err(slash + 1, &endptr, 10, &error);
>  	if (mask == 0){
>  		DBG_INFO("Windows does not like the zero mask, "
>  			 "so nor do we: %s\n", cidr);
>  		goto error;
>  	}
>  
> -	if (*endptr != '\0' || endptr == slash + 1){
> +	if (*endptr != '\0' || endptr == slash + 1 || error != 0){
>  		DBG_INFO("CIDR mask is not a proper integer: %s\n", cidr);
>  		goto error;
>  	}
> diff --git a/source4/dsdb/samdb/ldb_modules/schema_load.c b/source4/dsdb/samdb/ldb_modules/schema_load.c
> index 473a2e0a1f7..46306820f16 100644
> --- a/source4/dsdb/samdb/ldb_modules/schema_load.c
> +++ b/source4/dsdb/samdb/ldb_modules/schema_load.c
> @@ -117,6 +117,7 @@ static int schema_metadata_get_uint64(struct schema_load_private_data *data,
>  	char *value_str;
>  	TALLOC_CTX *tmp_ctx;
>  	int tdb_seqnum;
> +	int error;
>  
>  	if (!data) {
>  		*value = default_value;
> @@ -169,7 +170,12 @@ static int schema_metadata_get_uint64(struct schema_load_private_data *data,
>  	 * next time
>  	 */
>  	data->tdb_seqnum = tdb_seqnum;
> -	data->schema_seq_num_cache = strtoull(value_str, NULL, 10);
> +	data->schema_seq_num_cache = strtoull_err(value_str, NULL, 10, &error);
> +	if (error != 0) {
> +		talloc_free(tmp_ctx);
> +		return ldb_module_error(data->module, LDB_ERR_OPERATIONS_ERROR,
> +					"Failed to convert value");
> +	}
>  
>  	*value = data->schema_seq_num_cache;
>  
> diff --git a/source4/dsdb/schema/schema_prefixmap.c b/source4/dsdb/schema/schema_prefixmap.c
> index c30aecc0ec2..2be23087a12 100644
> --- a/source4/dsdb/schema/schema_prefixmap.c
> +++ b/source4/dsdb/schema/schema_prefixmap.c
> @@ -216,6 +216,7 @@ static WERROR _dsdb_pfm_make_binary_oid(const char *full_oid, TALLOC_CTX *mem_ct
>  {
>  	uint32_t last_subid;
>  	const char *oid_subid;
> +	int error;
>  
>  	/* make last sub-identifier value */
>  	oid_subid = strrchr(full_oid, '.');
> @@ -223,7 +224,10 @@ static WERROR _dsdb_pfm_make_binary_oid(const char *full_oid, TALLOC_CTX *mem_ct
>  		return WERR_INVALID_PARAMETER;
>  	}
>  	oid_subid++;
> -	last_subid = strtoul(oid_subid, NULL, 10);
> +	last_subid = strtoul_err(oid_subid, NULL, 10, &error);
> +	if (error != 0) {
> +		return WERR_INVALID_PARAMETER;
> +	}
>  
>  	/* encode oid in BER format */
>  	if (!ber_write_OID_String(mem_ctx, _bin_oid, full_oid)) {
> diff --git a/source4/lib/registry/ldb.c b/source4/lib/registry/ldb.c
> index 8bb6fd5c10f..e1ec4b31c31 100644
> --- a/source4/lib/registry/ldb.c
> +++ b/source4/lib/registry/ldb.c
> @@ -75,8 +75,15 @@ static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx,
>  	case REG_DWORD:
>  	case REG_DWORD_BIG_ENDIAN:
>  		if (val != NULL) {
> +			int error;
>  			/* The data is a plain DWORD */
> -			uint32_t tmp = strtoul((char *)val->data, NULL, 0);
> +			uint32_t tmp =
> +				strtoul_err((char *)val->data, NULL, 0, &error);
> +			if (error != 0) {
> +				data->data = NULL;
> +				data->length = 0;
> +				break;
> +			}
>  			data->data = talloc_size(mem_ctx, sizeof(uint32_t));
>  			if (data->data != NULL) {
>  				SIVAL(data->data, 0, tmp);
> @@ -90,8 +97,17 @@ static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx,
>  
>  	case REG_QWORD:
>  		if (val != NULL) {
> +			int error;
>  			/* The data is a plain QWORD */
> -			uint64_t tmp = strtoull((char *)val->data, NULL, 0);
> +			uint64_t tmp = strtoull_err((char *)val->data,
> +						    NULL,
> +						    0,
> +						    &error);
> +			if (error != 0) {
> +				data->data = NULL;
> +				data->length = 0;
> +				break;
> +			}
>  			data->data = talloc_size(mem_ctx, sizeof(uint64_t));
>  			if (data->data != NULL) {
>  				SBVAL(data->data, 0, tmp);
> diff --git a/source4/lib/socket/interface.c b/source4/lib/socket/interface.c
> index 594df1a0526..d6500874e0d 100644
> --- a/source4/lib/socket/interface.c
> +++ b/source4/lib/socket/interface.c
> @@ -225,8 +225,10 @@ static void interpret_interface(TALLOC_CTX *mem_ctx,
>  		}
>  	} else {
>  		char *endp = NULL;
> -		unsigned long val = strtoul(p, &endp, 0);
> -		if (p == endp || (endp && *endp != '\0')) {
> +		int error;
> +
> +		unsigned long val = strtoul_err(p, &endp, 0, &error);
> +		if (p == endp || (endp && *endp != '\0') || error != 0) {
>  			DEBUG(2,("interpret_interface: "
>  				"can't determine netmask value from %s\n",
>  				p));
> diff --git a/source4/libcli/resolve/dns_ex.c b/source4/libcli/resolve/dns_ex.c
> index 6174b617cb3..d76b0f819c7 100644
> --- a/source4/libcli/resolve/dns_ex.c
> +++ b/source4/libcli/resolve/dns_ex.c
> @@ -514,6 +514,7 @@ static void pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
>  		uint32_t port = 0;
>  		char *p = strrchr(addrs[i], '@');
>  		char *n;
> +		int error;
>  
>  		if (!p) {
>  			composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
> @@ -536,8 +537,8 @@ static void pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
>  			composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
>  			return;
>  		}
> -		port = strtoul(p, NULL, 10);
> -		if (port > UINT16_MAX) {
> +		port = strtoul_err(p, NULL, 10, &error);
> +		if (port > UINT16_MAX || error != 0) {
>  			composite_error(c, NT_STATUS_OBJECT_NAME_NOT_FOUND);
>  			return;
>  		}
> diff --git a/source4/nbt_server/wins/winsdb.c b/source4/nbt_server/wins/winsdb.c
> index fa9a6154b9a..abd3c49bb50 100644
> --- a/source4/nbt_server/wins/winsdb.c
> +++ b/source4/nbt_server/wins/winsdb.c
> @@ -148,6 +148,7 @@ static NTSTATUS winsdb_nbt_name(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct n
>  	struct nbt_name *name;
>  	unsigned int comp_num;
>  	uint32_t cur = 0;
> +	int error;
>  
>  	name = talloc(mem_ctx, struct nbt_name);
>  	if (!name) {
> @@ -181,7 +182,16 @@ static NTSTATUS winsdb_nbt_name(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct n
>  	}
>  
>  	if (comp_num > cur && strcasecmp("type", ldb_dn_get_component_name(dn, cur)) == 0) {
> -		name->type	= strtoul((char *)ldb_dn_get_component_val(dn, cur)->data, NULL, 0);
> +		name->type =
> +			strtoul_err(
> +				(char *)ldb_dn_get_component_val(dn, cur)->data,
> +				NULL,
> +				0,
> +				&error);
> +		if (error != 0) {
> +			status = NT_STATUS_INTERNAL_DB_CORRUPTION;
> +			goto failed;
> +		}
>  		cur++;
>  	} else {
>  		status = NT_STATUS_INTERNAL_DB_CORRUPTION;
> diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c
> index cbbd9f482f2..1d7410c2dfb 100644
> --- a/source4/rpc_server/lsa/dcesrv_lsa.c
> +++ b/source4/rpc_server/lsa/dcesrv_lsa.c
> @@ -1698,6 +1698,7 @@ static NTSTATUS update_uint32_t_value(TALLOC_CTX *mem_ctx,
>  	uint32_t orig_uint = 0;
>  	unsigned int flags = 0;
>  	int ret;
> +	int error;
>  
>  	orig_val = ldb_msg_find_ldb_val(orig, attribute);
>  	if (!orig_val || !orig_val->data) {
> @@ -1705,9 +1706,11 @@ static NTSTATUS update_uint32_t_value(TALLOC_CTX *mem_ctx,
>  		flags = LDB_FLAG_MOD_ADD;
>  
>  	} else {
> -		errno = 0;
> -		orig_uint = strtoul((const char *)orig_val->data, NULL, 0);
> -		if (errno != 0 || orig_uint != value) {
> +		orig_uint = strtoul_err((const char *)orig_val->data,
> +					NULL,
> +					0,
> +					&error);
> +		if (error != 0 || orig_uint != value) {
>  			/* replace also if can't get value */
>  			flags = LDB_FLAG_MOD_REPLACE;
>  		}
> diff --git a/source4/torture/nbench/nbench.c b/source4/torture/nbench/nbench.c
> index 8e4a984c9b5..e48997a779e 100644
> --- a/source4/torture/nbench/nbench.c
> +++ b/source4/torture/nbench/nbench.c
> @@ -96,6 +96,8 @@ again:
>  	while (fgets(line, sizeof(line)-1, f)) {
>  		NTSTATUS status;
>  		const char **params0, **params;
> +		unsigned long int tmp;
> +		int error;
>  
>  		nbench_line_count++;
>  
> @@ -138,7 +140,11 @@ again:
>  
>  		/* accept numeric or string status codes */
>  		if (strncmp(params[i-1], "0x", 2) == 0) {
> -			status = NT_STATUS(strtoul(params[i-1], NULL, 16));
> +			tmp = strtoul_err(params[i-1], NULL, 16, &error);
> +			if (error != 0) {
> +				tmp = error;
> +			}
> +			status = NT_STATUS(tmp);
>  		} else {
>  			status = nt_status_string_to_code(params[i-1]);
>  		}
> diff --git a/source4/torture/smb2/sharemode.c b/source4/torture/smb2/sharemode.c
> index 8c7403c8302..8232e1e5af9 100644
> --- a/source4/torture/smb2/sharemode.c
> +++ b/source4/torture/smb2/sharemode.c
> @@ -186,12 +186,17 @@ bool torture_smb2_check_sharemode(struct torture_context *tctx)
>  	struct smb2_create create = { };
>  	NTSTATUS status;
>  	bool ret = true;
> +	int error;
>  
>  	sharemode_string = torture_setting_string(tctx, "sharemode", "RWD");
>  	sharemode = smb2_util_share_access(sharemode_string);
>  
>  	access_string = torture_setting_string(tctx, "access", "0xf01ff");
> -	access = strtoul(access_string, NULL, 0);
> +	access = strtoul_err(access_string, NULL, 0, &error);
> +	if (error != 0) {
> +		torture_comment(tctx, "Initializing access failed.\n");
> +		return false;
> +	}
>  
>  	filename = torture_setting_string(tctx, "filename", "testfile");
>  	operation = torture_setting_string(tctx, "operation", "WD");
> diff --git a/source4/web_server/web_server.c b/source4/web_server/web_server.c
> index 7c2717368e3..93c147302ef 100644
> --- a/source4/web_server/web_server.c
> +++ b/source4/web_server/web_server.c
> @@ -107,6 +107,8 @@ void websrv_output(struct websrv_context *web, const void *data, size_t length)
>  */
>  NTSTATUS http_parse_header(struct websrv_context *web, const char *line)
>  {
> +	int error;
> +
>  	if (line[0] == 0) {
>  		web->input.end_of_headers = true;
>  	} else if (strncasecmp(line,"GET ", 4)==0) {
> @@ -118,7 +120,10 @@ NTSTATUS http_parse_header(struct websrv_context *web, const char *line)
>  		http_error(web, "400 Bad request", "This server only accepts GET and POST requests");
>  		return NT_STATUS_INVALID_PARAMETER;
>  	} else if (strncasecmp(line, "Content-Length: ", 16)==0) {
> -		web->input.content_length = strtoul(&line[16], NULL, 10);
> +		web->input.content_length = strtoul_err(&line[16], NULL, 10, &error);
> +		if (error != 0) {
> +			return NT_STATUS_INVALID_PARAMETER;
> +		}
>  	} else {
>  		struct http_header *hdr = talloc_zero(web, struct http_header);
>  		char *colon = strchr(line, ':');
> -- 
> 2.20.1
> 
> 
> From dad59e997e6f44d5c05b9d5498abc45e96b35a12 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Wed, 30 Jan 2019 10:23:14 +0100
> Subject: [PATCH 17/19] third_party: Use wrapper for string to integer
>  conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  third_party/nss_wrapper/nss_wrapper.c       | 64 ++++++---------------
>  third_party/nss_wrapper/wscript             |  2 +-
>  third_party/socket_wrapper/socket_wrapper.c | 11 +++-
>  third_party/socket_wrapper/wscript          |  2 +-
>  third_party/uid_wrapper/uid_wrapper.c       | 47 +++++++++++++--
>  third_party/uid_wrapper/wscript             |  2 +-
>  6 files changed, 71 insertions(+), 57 deletions(-)
> 
> diff --git a/third_party/nss_wrapper/nss_wrapper.c b/third_party/nss_wrapper/nss_wrapper.c
> index 81d900c3f42..d602a202a68 100644
> --- a/third_party/nss_wrapper/nss_wrapper.c
> +++ b/third_party/nss_wrapper/nss_wrapper.c
> @@ -60,6 +60,7 @@
>  #include <search.h>
>  #include <assert.h>
>  
> +
>  /*
>   * Defining _POSIX_PTHREAD_SEMANTICS before including pwd.h and grp.h  gives us
>   * the posix getpwnam_r(), getpwuid_r(), getgrnam_r and getgrgid_r calls on
> @@ -138,6 +139,8 @@ typedef nss_status_t NSS_STATUS;
>  #define DNS_NAME_MAX 255
>  #endif
>  
> +#include "lib/util/util.h"
> +
>  /* GCC have printf type attribute check. */
>  #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
>  #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
> @@ -1566,6 +1569,7 @@ static void nwrap_init(void)
>  	char *endptr;
>  	size_t max_hostents_tmp;
>  	int ok;
> +	int error;
>  
>  	NWRAP_LOCK(nwrap_initialized);
>  	if (nwrap_initialized) {
> @@ -1588,9 +1592,11 @@ static void nwrap_init(void)
>  
>  	env = getenv("NSS_WRAPPER_MAX_HOSTENTS");
>  	if (env != NULL) {
> -		max_hostents_tmp = (size_t)strtoul(env, &endptr, 10);
> +		max_hostents_tmp =
> +			(size_t)strtoul_err(env, &endptr, 10, &error);
>  		if ((*env == '\0') ||
>  		    (*endptr != '\0') ||
> +		    (error != 0) ||
>  		    (max_hostents_tmp == 0)) {
>  			NWRAP_LOG(NWRAP_LOG_DEBUG,
>  				  "Error parsing NSS_WRAPPER_MAX_HOSTENTS "
> @@ -1883,6 +1889,7 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
>  	char *e;
>  	struct passwd *pw;
>  	size_t list_size;
> +	int error;
>  
>  	nwrap_pw = (struct nwrap_pw *)nwrap->private_data;
>  
> @@ -1938,23 +1945,11 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
>  	*p = '\0';
>  	p++;
>  	e = NULL;
> -	pw->pw_uid = (uid_t)strtoul(c, &e, 10);
> -	if (c == e) {
> +	pw->pw_uid = (uid_t)strtoul_err(c, &e, 10, &error);
> +	if (c == e || e == NULL || e[0] != '\0' || error != 0) {
>  		NWRAP_LOG(NWRAP_LOG_ERROR,
>  			  "Invalid line[%s]: '%s' - %s",
> -			  line, c, strerror(errno));
> -		return false;
> -	}
> -	if (e == NULL) {
> -		NWRAP_LOG(NWRAP_LOG_ERROR,
> -			  "Invalid line[%s]: '%s' - %s",
> -			  line, c, strerror(errno));
> -		return false;
> -	}
> -	if (e[0] != '\0') {
> -		NWRAP_LOG(NWRAP_LOG_ERROR,
> -			  "Invalid line[%s]: '%s' - %s",
> -			  line, c, strerror(errno));
> +			  line, c, strerror(error));
>  		return false;
>  	}
>  	c = p;
> @@ -1970,23 +1965,11 @@ static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line)
>  	*p = '\0';
>  	p++;
>  	e = NULL;
> -	pw->pw_gid = (gid_t)strtoul(c, &e, 10);
> -	if (c == e) {
> -		NWRAP_LOG(NWRAP_LOG_ERROR,
> -			  "Invalid line[%s]: '%s' - %s",
> -			  line, c, strerror(errno));
> -		return false;
> -	}
> -	if (e == NULL) {
> +	pw->pw_gid = (gid_t)strtoul_err(c, &e, 10, &error);
> +	if (c == e || e == NULL || e[0] != '\0' || error != 0) {
>  		NWRAP_LOG(NWRAP_LOG_ERROR,
>  			  "Invalid line[%s]: '%s' - %s",
> -			  line, c, strerror(errno));
> -		return false;
> -	}
> -	if (e[0] != '\0') {
> -		NWRAP_LOG(NWRAP_LOG_ERROR,
> -			  "Invalid line[%s]: '%s' - %s",
> -			  line, c, strerror(errno));
> +			  line, c, strerror(error));
>  		return false;
>  	}
>  	c = p;
> @@ -2410,6 +2393,7 @@ static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
>  	struct group *gr;
>  	size_t list_size;
>  	unsigned nummem;
> +	int error;
>  
>  	nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
>  
> @@ -2460,23 +2444,11 @@ static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
>  	*p = '\0';
>  	p++;
>  	e = NULL;
> -	gr->gr_gid = (gid_t)strtoul(c, &e, 10);
> -	if (c == e) {
> -		NWRAP_LOG(NWRAP_LOG_ERROR,
> -			  "Invalid line[%s]: '%s' - %s",
> -			  line, c, strerror(errno));
> -		return false;
> -	}
> -	if (e == NULL) {
> -		NWRAP_LOG(NWRAP_LOG_ERROR,
> -			  "Invalid line[%s]: '%s' - %s",
> -			  line, c, strerror(errno));
> -		return false;
> -	}
> -	if (e[0] != '\0') {
> +	gr->gr_gid = (gid_t)strtoul_err(c, &e, 10, &error);
> +	if (c == e || e == NULL || e[0] != '\0' ||error != 0) {
>  		NWRAP_LOG(NWRAP_LOG_ERROR,
>  			  "Invalid line[%s]: '%s' - %s",
> -			  line, c, strerror(errno));
> +			  line, c, strerror(error));
>  		return false;
>  	}
>  	c = p;
> diff --git a/third_party/nss_wrapper/wscript b/third_party/nss_wrapper/wscript
> index 2e9d1db13b1..3b64bebe36a 100644
> --- a/third_party/nss_wrapper/wscript
> +++ b/third_party/nss_wrapper/wscript
> @@ -89,6 +89,6 @@ def build(bld):
>          # breaks preloading!
>          bld.SAMBA_LIBRARY('nss_wrapper',
>                            source='nss_wrapper.c',
> -                          deps='dl',
> +                          deps='dl samba-util',
>                            install=False,
>                            realname='libnss-wrapper.so')
> diff --git a/third_party/socket_wrapper/socket_wrapper.c b/third_party/socket_wrapper/socket_wrapper.c
> index df70df5008d..c41ec51f0ee 100644
> --- a/third_party/socket_wrapper/socket_wrapper.c
> +++ b/third_party/socket_wrapper/socket_wrapper.c
> @@ -237,6 +237,12 @@ enum swrap_dbglvl_e {
>   * without changing the format above */
>  #define MAX_WRAPPED_INTERFACES 64
>  
> +#ifndef _PUBLIC_
> +#define _PUBLIC_
> +#endif
> +
> +#include "lib/util/util.h"
> +
>  struct swrap_address {
>  	socklen_t sa_socklen;
>  	union {
> @@ -1352,6 +1358,7 @@ static size_t socket_wrapper_max_sockets(void)
>  	const char *s;
>  	size_t tmp;
>  	char *endp;
> +	int error;
>  
>  	if (socket_info_max != 0) {
>  		return socket_info_max;
> @@ -1364,11 +1371,11 @@ static size_t socket_wrapper_max_sockets(void)
>  		goto done;
>  	}
>  
> -	tmp = strtoul(s, &endp, 10);
> +	tmp = strtoul_err(s, &endp, 10, &error);
>  	if (s == endp) {
>  		goto done;
>  	}
> -	if (tmp == 0) {
> +	if (tmp == 0 || error != 0) {
>  		tmp = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT;
>  		SWRAP_LOG(SWRAP_LOG_ERROR,
>  			  "Invalid number of sockets specified, "
> diff --git a/third_party/socket_wrapper/wscript b/third_party/socket_wrapper/wscript
> index 3cca13cc6fb..8f178ad8c40 100644
> --- a/third_party/socket_wrapper/wscript
> +++ b/third_party/socket_wrapper/wscript
> @@ -85,6 +85,6 @@ def build(bld):
>          # breaks preloading!
>          bld.SAMBA_LIBRARY('socket_wrapper',
>                            source='socket_wrapper.c',
> -                          deps='dl pthread tirpc',
> +                          deps='dl pthread tirpc samba-util',
>                            install=False,
>                            realname='libsocket-wrapper.so')
> diff --git a/third_party/uid_wrapper/uid_wrapper.c b/third_party/uid_wrapper/uid_wrapper.c
> index 8f41ed92cb9..088b6190d0e 100644
> --- a/third_party/uid_wrapper/uid_wrapper.c
> +++ b/third_party/uid_wrapper/uid_wrapper.c
> @@ -122,6 +122,16 @@
>  #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
>  #endif
>  
> +#ifndef _PUBLIC_
> +#define _PUBLIC_
> +#endif
> +
> +#ifndef uint8_t
> +typedef unsigned char uint8_t;
> +#endif
> +
> +#include "lib/util/util.h"
> +
>  /*****************
>   * LOGGING
>   *****************/
> @@ -980,46 +990,65 @@ static void uwrap_init_env(struct uwrap_thread *id)
>  {
>  	const char *env;
>  	int ngroups = 0;
> +	int error;
>  
>  	env = getenv("UID_WRAPPER_INITIAL_RUID");
>  	if (env != NULL && env[0] != '\0') {
>  		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize ruid with %s", env);
> -		id->ruid = strtoul(env, (char **)NULL, 10);
> +		id->ruid = strtoul_err(env, (char **)NULL, 10, &error);
> +		if (error != 0) {
> +			goto error;
> +		}
>  		unsetenv("UID_WRAPPER_INITIAL_RUID");
>  	}
>  
>  	env = getenv("UID_WRAPPER_INITIAL_EUID");
>  	if (env != NULL && env[0] != '\0') {
>  		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize euid with %s", env);
> -		id->euid = strtoul(env, (char **)NULL, 10);
> +		id->euid = strtoul_err(env, (char **)NULL, 10, &error);
> +		if (error != 0) {
> +			goto error;
> +		}
>  		unsetenv("UID_WRAPPER_INITIAL_EUID");
>  	}
>  
>  	env = getenv("UID_WRAPPER_INITIAL_SUID");
>  	if (env != NULL && env[0] != '\0') {
>  		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize suid with %s", env);
> -		id->suid = strtoul(env, (char **)NULL, 10);
> +		id->suid = strtoul_err(env, (char **)NULL, 10, &error);
> +		if (error != 0) {
> +			goto error;
> +		}
>  		unsetenv("UID_WRAPPER_INITIAL_SUID");
>  	}
>  
>  	env = getenv("UID_WRAPPER_INITIAL_RGID");
>  	if (env != NULL && env[0] != '\0') {
>  		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize ruid with %s", env);
> -		id->rgid = strtoul(env, (char **)NULL, 10);
> +		id->rgid = strtoul_err(env, (char **)NULL, 10, &error);
> +		if (error != 0) {
> +			goto error;
> +		}
>  		unsetenv("UID_WRAPPER_INITIAL_RGID");
>  	}
>  
>  	env = getenv("UID_WRAPPER_INITIAL_EGID");
>  	if (env != NULL && env[0] != '\0') {
>  		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize egid with %s", env);
> -		id->egid = strtoul(env, (char **)NULL, 10);
> +		id->egid = strtoul_err(env, (char **)NULL, 10, &error);
> +		if (error != 0) {
> +			goto error;
> +		}
>  		unsetenv("UID_WRAPPER_INITIAL_EGID");
>  	}
>  
>  	env = getenv("UID_WRAPPER_INITIAL_SGID");
>  	if (env != NULL && env[0] != '\0') {
>  		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize sgid with %s", env);
> -		id->sgid = strtoul(env, (char **)NULL, 10);
> +		id->sgid = strtoul_err(env, (char **)NULL, 10, &error);
> +		if (error != 0) {
> +			goto error;
> +		}
>  		unsetenv("UID_WRAPPER_INITIAL_SGID");
>  	}
>  
> @@ -1090,6 +1119,12 @@ static void uwrap_init_env(struct uwrap_thread *id)
>  		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
>  		id->ngroups = ngroups;
>  	}
> +
> +	return;
> +
> +error:
> +	UWRAP_LOG(UWRAP_LOG_ERROR, "Init failed.");
> +	exit(-1);
>  }
>  
>  static void uwrap_init(void)
> diff --git a/third_party/uid_wrapper/wscript b/third_party/uid_wrapper/wscript
> index 61d8a189625..c7b2b003eaf 100644
> --- a/third_party/uid_wrapper/wscript
> +++ b/third_party/uid_wrapper/wscript
> @@ -119,6 +119,6 @@ def build(bld):
>          # breaks preloading!
>          bld.SAMBA_LIBRARY('uid_wrapper',
>                            source='uid_wrapper.c',
> -                          deps='dl',
> +                          deps='dl samba-util',
>                            install=False,
>                            realname='libuid-wrapper.so')
> -- 
> 2.20.1
> 
> 
> From 9ecbd01ab1fc77b66f119050778379b13f3c0799 Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Wed, 30 Jan 2019 10:28:52 +0100
> Subject: [PATCH 18/19] ctdb-utils: Use wrapper for string to integer
>  conversion
> 
> In order to detect an error during the string to integer
> conversion with strtoul/strtoull, the errno variable must
> be set to zero before the execution and checked after the
> conversion is performed. This is achieved by using the
> wrapper function strtoul_err and strtoull_err.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c b/ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c
> index 7ef76c26e02..a7038f2dfce 100644
> --- a/ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c
> +++ b/ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c
> @@ -301,10 +301,14 @@ int main(int argc, char *argv[])
>  	cmr_state->pool_name = argv[3];
>  	cmr_state->object = argv[4];
>  	if (argc == 6) {
> +		int error;
>  		/* optional lock duration provided */
>  		char *endptr = NULL;
> -		cmr_state->lock_duration_s = strtoull(argv[5], &endptr, 0);
> -		if ((endptr == argv[5]) || (*endptr != '\0')) {
> +		cmr_state->lock_duration_s = strtoull_err(argv[5],
> +							  &endptr,
> +							  0,
> +							  &error);
> +		if ((endptr == argv[5]) || (*endptr != '\0') || (error != 0)) {
>  			fprintf(stdout, CTDB_MUTEX_STATUS_ERROR);
>  			ret = -EINVAL;
>  			goto err_ctx_cleanup;
> -- 
> 2.20.1
> 
> 
> From 8d42054e3609ce111c5b5d684c9ffc56fe797c7a Mon Sep 17 00:00:00 2001
> From: Swen Schillig <swen at linux.ibm.com>
> Date: Tue, 5 Feb 2019 08:39:14 +0100
> Subject: [PATCH 19/19] lib: modify string conversion wrapper to handle signed
>  input
> 
> The standard string conversion routines convert a "signed string"
> into the positive representation of the resulting value.
> This is not wanted and therefore now detected and flag'ed as an error.
> 
> Signed-off-by: Swen Schillig <swen at linux.ibm.com>
> ---
>  lib/util/util.c | 44 +++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 41 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/util/util.c b/lib/util/util.c
> index d2f7160e02e..428bad7d285 100644
> --- a/lib/util/util.c
> +++ b/lib/util/util.c
> @@ -52,10 +52,29 @@ strtoul_err(const char *nptr, char **endptr, int base, int *err)
>  {
>  	unsigned long int val;
>  	int saved_errno = errno;
> +	char *needle = NULL;
> +	char *tmp_endptr = NULL;
>  
>  	errno = 0;
> -	val = strtoul(nptr, endptr, base);
> -	*err = errno;
> +	*err = 0;
> +
> +	val = strtoul(nptr, &tmp_endptr, base);
> +
> +	if (endptr != NULL) {
> +		*endptr = tmp_endptr;
> +	}
> +
> +	if (errno != 0) {
> +		*err = errno;
> +		errno = saved_errno;
> +		return val;
> +	}
> +
> +	/* did we convert a negative "number" ? */
> +	needle = strchr(nptr, '-');
> +	if (needle != NULL && needle < tmp_endptr) {
> +		*err = EINVAL;
> +	}
>  
>  	errno = saved_errno;
>  	return val;
> @@ -66,10 +85,29 @@ strtoull_err(const char *nptr, char **endptr, int base, int *err)
>  {
>  	unsigned long long int val;
>  	int saved_errno = errno;
> +	char *needle = NULL;
> +	char *tmp_endptr = NULL;
>  
>  	errno = 0;
> +	*err = 0;
> +
>  	val = strtoull(nptr, endptr, base);
> -	*err = errno;
> +
> +	if (endptr != NULL) {
> +		*endptr = tmp_endptr;
> +	}
> +
> +	if (errno != 0) {
> +		*err = errno;
> +		errno = saved_errno;
> +		return val;
> +	}
> +
> +	/* did we convert a negative "number" ? */
> +	needle = strchr(nptr, '-');
> +	if (needle != NULL && needle < tmp_endptr) {
> +		*err = EINVAL;
> +	}
>  
>  	errno = saved_errno;
>  	return val;
> -- 
> 2.20.1
> 






More information about the samba-technical mailing list