summaryrefslogtreecommitdiff
path: root/source3/nsswitch
diff options
context:
space:
mode:
authorTim Potter <tpot@samba.org>2003-09-08 05:51:57 +0000
committerTim Potter <tpot@samba.org>2003-09-08 05:51:57 +0000
commitf87bd754231387825924454836de23b9777dcaa0 (patch)
tree16cb02a2b35ed52a96cc6dfdb0c871dd9495d234 /source3/nsswitch
parent605281ef4be0547e0f97b151b34e45b9d95eef22 (diff)
downloadsamba-f87bd754231387825924454836de23b9777dcaa0.tar.gz
samba-f87bd754231387825924454836de23b9777dcaa0.tar.bz2
samba-f87bd754231387825924454836de23b9777dcaa0.zip
Fix for bug #299.
There was some confusion over dynamically allocated lists of pointers (i.e you have to make space for the list of pointers and what they are pointing too) in the memory buffer passed in from libc. Valgrind is much happer now and as a bonus there is no segfault. (This used to be commit 7907c44414acb841a9001e82285790eece73d032)
Diffstat (limited to 'source3/nsswitch')
-rw-r--r--source3/nsswitch/wins.c110
1 files changed, 80 insertions, 30 deletions
diff --git a/source3/nsswitch/wins.c b/source3/nsswitch/wins.c
index 87dac60192..0fc4e46cdb 100644
--- a/source3/nsswitch/wins.c
+++ b/source3/nsswitch/wins.c
@@ -260,54 +260,105 @@ int lookup(nsd_file_t *rq)
}
#else
+
+/* Allocate some space from the nss static buffer. The buffer and buflen
+ are the pointers passed in by the C library to the _nss_*_*
+ functions. */
+
+static char *get_static(char **buffer, int *buflen, int len)
+{
+ char *result;
+
+ /* Error check. We return false if things aren't set up right, or
+ there isn't enough buffer space left. */
+
+ if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
+ return NULL;
+ }
+
+ /* Return an index into the static buffer */
+
+ result = *buffer;
+ *buffer += len;
+ *buflen -= len;
+
+ return result;
+}
+
/****************************************************************************
gethostbyname() - we ignore any domain portion of the name and only
handle names that are at most 15 characters long
**************************************************************************/
NSS_STATUS
-_nss_wins_gethostbyname_r(const char *name, struct hostent *he,
- char *buffer, size_t buflen, int *errnop,
- int *h_errnop)
+_nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
+ char *buffer, size_t buflen, int *h_errnop)
{
- char **host_addresses;
struct in_addr *ip_list;
int i, count;
- size_t namelen = strlen(name) + 1;
+ fstring name;
+ size_t namelen;
memset(he, '\0', sizeof(*he));
+ fstrcpy(name, hostname);
+
+ /* Do lookup */
ip_list = lookup_byname_backend(name, &count);
- if (!ip_list) {
- return NSS_STATUS_NOTFOUND;
- }
- if (buflen < namelen + (2*count+1)*INADDRSZ) {
- /* no ENOMEM error type?! */
+ if (!ip_list)
return NSS_STATUS_NOTFOUND;
- }
+ /* Copy h_name */
- host_addresses = (char **)buffer;
- he->h_addr_list = host_addresses;
- host_addresses[count] = NULL;
- buffer += (count + 1) * INADDRSZ;
- buflen += (count + 1) * INADDRSZ;
- he->h_addrtype = AF_INET;
- he->h_length = INADDRSZ;
+ namelen = strlen(name) + 1;
+
+ if ((he->h_name = get_static(&buffer, &buflen, namelen)) == NULL)
+ return NSS_STATUS_TRYAGAIN;
+
+ memcpy(he->h_name, name, namelen);
+
+ /* Copy h_addr_list, align to pointer boundary first */
- for (i=0;i<count;i++) {
- memcpy(buffer, &ip_list[i].s_addr, INADDRSZ);
- *host_addresses = buffer;
- buffer += INADDRSZ;
- buflen -= INADDRSZ;
- host_addresses++;
+ if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
+ i = sizeof(char*) - i;
+
+ if (get_static(&buffer, &buflen, i) == NULL)
+ return NSS_STATUS_TRYAGAIN;
+
+ if ((he->h_addr_list = (char **)get_static(
+ &buffer, &buflen, (count + 1) * sizeof(char *))) == NULL)
+ return NSS_STATUS_TRYAGAIN;
+
+ for (i = 0; i < count; i++) {
+ if ((he->h_addr_list[i] = get_static(&buffer, &buflen,
+ INADDRSZ)) == NULL)
+ return NSS_STATUS_TRYAGAIN;
+ memcpy(he->h_addr_list[i], &ip_list[i], INADDRSZ);
}
+ he->h_addr_list[count] = NULL;
+
if (ip_list)
free(ip_list);
- memcpy(buffer, name, namelen);
- he->h_name = buffer;
+ /* Set h_addr_type and h_length */
+
+ he->h_addrtype = AF_INET;
+ he->h_length = INADDRSZ;
+
+ /* Set h_aliases */
+
+ if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
+ i = sizeof(char*) - i;
+
+ if (get_static(&buffer, &buflen, i) == NULL)
+ return NSS_STATUS_TRYAGAIN;
+
+ if ((he->h_aliases = (char **)get_static(
+ &buffer, &buflen, sizeof(char *))) == NULL)
+ return NSS_STATUS_TRYAGAIN;
+
+ he->h_aliases[0] = NULL;
return NSS_STATUS_SUCCESS;
}
@@ -315,15 +366,14 @@ _nss_wins_gethostbyname_r(const char *name, struct hostent *he,
NSS_STATUS
_nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
- char *buffer, size_t buflen, int *errnop,
- int *h_errnop)
+ char *buffer, size_t buflen, int *h_errnop)
{
if(af!=AF_INET) {
*h_errnop = NO_DATA;
- *errnop = EAFNOSUPPORT;
return NSS_STATUS_UNAVAIL;
}
- return _nss_wins_gethostbyname_r(name,he,buffer,buflen,errnop,h_errnop);
+ return _nss_wins_gethostbyname_r(
+ name, he, buffer, buflen, h_errnop);
}
#endif