Page MenuHomeFreeBSD

D38047.id125561.diff
No OneTemporary

D38047.id125561.diff

diff --git a/UPDATING b/UPDATING
--- a/UPDATING
+++ b/UPDATING
@@ -12,6 +12,14 @@
/usr/ports/UPDATING. Please read that file before updating system packages
and/or ports.
+20221129:
+ 13.1-RELEASE-p5 FreeBSD-SA-22:15.ping
+ FreeBSD-EN-22:28.heimdal
+
+ Stack overflow in ping [SA-22:15.ping]
+
+ Regression in Heimdal KDC [EN-22:28.heimdal]
+
20221116:
13.1-RELEASE-p4 FreeBSD-SA-22:14.heimdal
diff --git a/crypto/heimdal/lib/asn1/gen_free.c b/crypto/heimdal/lib/asn1/gen_free.c
--- a/crypto/heimdal/lib/asn1/gen_free.c
+++ b/crypto/heimdal/lib/asn1/gen_free.c
@@ -61,13 +61,6 @@
case TNull:
case TGeneralizedTime:
case TUTCTime:
- /*
- * This doesn't do much, but it leaves zeros where garbage might
- * otherwise have been found. Gets us closer to having the equivalent
- * of a memset()-to-zero data structure after calling the free
- * functions.
- */
- fprintf(codefile, "*%s = 0;\n", name);
break;
case TBitString:
if (ASN1_TAILQ_EMPTY(t->members))
diff --git a/include/nsswitch.h b/include/nsswitch.h
--- a/include/nsswitch.h
+++ b/include/nsswitch.h
@@ -190,7 +190,8 @@
enum nss_lookup_type {
nss_lt_name = 1,
nss_lt_id = 2,
- nss_lt_all = 3
+ nss_lt_all = 3,
+ nss_lt_pivot= 4
};
#ifdef _NS_PRIVATE
diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c
--- a/lib/libc/gen/getgrent.c
+++ b/lib/libc/gen/getgrent.c
@@ -154,6 +154,8 @@
static int grp_id_func(char *, size_t *, va_list, void *);
static int grp_marshal_func(char *, size_t *, void *, va_list, void *);
static int grp_unmarshal_func(char *, size_t, void *, va_list, void *);
+static int grplist_marshal_func(char *, size_t *, void *, va_list, void *);
+static int grplist_unmarshal_func(char *, size_t, void *, va_list, void *);
static int
grp_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
@@ -170,15 +172,15 @@
switch (lookup_type) {
case nss_lt_name:
name = va_arg(ap, char *);
- size = strlen(name);
- desired_size = sizeof(enum nss_lookup_type) + size + 1;
+ size = strlen(name) + 1;
+ desired_size = sizeof(enum nss_lookup_type) + size;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
- memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
+ memcpy(buffer + sizeof(enum nss_lookup_type), name, size);
res = NS_SUCCESS;
break;
@@ -194,6 +196,22 @@
memcpy(buffer + sizeof(enum nss_lookup_type), &gid,
sizeof(gid_t));
+ res = NS_SUCCESS;
+ break;
+ case nss_lt_pivot:
+ name = va_arg(ap, char *);
+ gid = va_arg(ap, gid_t);
+ size = strlen(name) + 1;
+
+ desired_size = sizeof(enum nss_lookup_type) + size + sizeof(gid_t);
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof (enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), name, size);
+ memcpy(buffer + sizeof(enum nss_lookup_type) + size, &gid, sizeof(gid_t));
res = NS_SUCCESS;
break;
default:
@@ -206,6 +224,36 @@
return (res);
}
+static int
+grplist_marshal_func(char *buffer, size_t *buffer_size, void *retval,
+ va_list ap, void *cache_mdata)
+{
+ char *name __unused;
+ gid_t basegid __unused;
+ gid_t *groups;
+ int maxgroups __unused, *ngroups;
+ size_t desired_size;
+
+ name = va_arg(ap, char*);
+ basegid = va_arg(ap, gid_t);
+ groups = va_arg(ap, gid_t *);
+ maxgroups = va_arg(ap, int);
+ ngroups = va_arg(ap, int *);
+
+ desired_size = sizeof(int) + (sizeof(gid_t) * (*ngroups));
+
+ if (buffer == NULL || desired_size > *buffer_size) {
+ *buffer_size = desired_size;
+ return (NS_RETURN);
+ }
+
+ *buffer_size = desired_size;
+ memcpy(buffer, ngroups, sizeof(int));
+ memcpy(buffer + sizeof(int), groups, sizeof(gid_t) * (*ngroups));
+
+ return (NS_SUCCESS);
+}
+
static int
grp_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
void *cache_mdata)
@@ -300,6 +348,38 @@
return (NS_SUCCESS);
}
+static int
+grplist_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
+ va_list ap, void *cache_mdata)
+{
+ char *name __unused;
+ gid_t basegid __unused;
+ gid_t *groups;
+ int *pngroups, maxgroups, original_ngroups;
+ int *ret_errno;
+
+ name = va_arg(ap, char *);
+ basegid = va_arg(ap, gid_t);
+ groups = va_arg(ap, gid_t *);
+ maxgroups = va_arg(ap, int);
+ pngroups = va_arg(ap, int *);
+ ret_errno = va_arg(ap, int *);
+
+ if (buffer_size < sizeof(int)) {
+ *ret_errno = 0;
+ return (NS_NOTFOUND);
+ }
+ memcpy(&original_ngroups, buffer, sizeof(int));
+ if (buffer_size < sizeof(int) + (original_ngroups * sizeof(gid_t))) {
+ return NS_UNAVAIL;
+ }
+ memcpy(groups, buffer + sizeof(int), sizeof(gid_t) *
+ ((original_ngroups > maxgroups) ? maxgroups : original_ngroups));
+ *pngroups = original_ngroups;
+ *ret_errno = 0;
+ return NS_SUCCESS;
+}
+
static int
grp_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
void *cache_mdata)
@@ -479,7 +559,7 @@
gid_t *groups;
gid_t agroup;
int maxgrp, *grpcnt;
- int i, rv, ret_errno;
+ int i, rv, sub_errno, *ret_errno;
/*
* As this is a fallback method, only provided src
@@ -492,6 +572,7 @@
groups = va_arg(ap, gid_t *);
maxgrp = va_arg(ap, int);
grpcnt = va_arg(ap, int *);
+ ret_errno = va_arg(ap, int *);
rv = NS_UNAVAIL;
@@ -506,12 +587,12 @@
_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", src, 0);
for (;;) {
do {
- ret_errno = 0;
+ sub_errno = 0;
grp_p = NULL;
rv = _nsdispatch(&grp_p, getgrent_r_dtab, NSDB_GROUP,
- "getgrent_r", src, &grp, buf, bufsize, &ret_errno);
+ "getgrent_r", src, &grp, buf, bufsize, &sub_errno);
- if (grp_p == NULL && ret_errno == ERANGE) {
+ if (grp_p == NULL && sub_errno == ERANGE) {
free(buf);
if ((bufsize << 1) > GRP_STORAGE_MAX) {
buf = NULL;
@@ -525,10 +606,10 @@
goto out;
}
}
- } while (grp_p == NULL && ret_errno == ERANGE);
+ } while (grp_p == NULL && sub_errno == ERANGE);
- if (ret_errno != 0) {
- errno = ret_errno;
+ if (sub_errno != 0) {
+ *ret_errno = sub_errno;
goto out;
}
@@ -668,8 +749,19 @@
__getgroupmembership(const char *uname, gid_t agroup, gid_t *groups,
int maxgrp, int *grpcnt)
{
+ int ret_errno = 0;
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_pivot,
+ grp_id_func, grplist_marshal_func, grplist_unmarshal_func);
+#endif
+
static const ns_dtab dtab[] = {
NS_FALLBACK_CB(getgroupmembership_fallback)
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
{ NULL, NULL, NULL }
};
@@ -679,9 +771,10 @@
*grpcnt = 0;
(void)_nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership",
- defaultsrc, uname, agroup, groups, maxgrp, grpcnt);
+ defaultsrc, uname, agroup, groups, maxgrp, grpcnt, &ret_errno);
/* too many groups found? */
+ errno = ret_errno;
return (*grpcnt > maxgrp ? -1 : 0);
}
diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c
--- a/lib/libc/gen/getpwent.c
+++ b/lib/libc/gen/getpwent.c
@@ -217,15 +217,15 @@
switch (lookup_type) {
case nss_lt_name:
name = va_arg(ap, char *);
- size = strlen(name);
- desired_size = sizeof(enum nss_lookup_type) + size + 1;
+ size = strlen(name) + 1;
+ desired_size = sizeof(enum nss_lookup_type) + size;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
- memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
+ memcpy(buffer + sizeof(enum nss_lookup_type), name, size);
res = NS_SUCCESS;
break;
diff --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c
--- a/lib/libc/net/nsdispatch.c
+++ b/lib/libc/net/nsdispatch.c
@@ -127,10 +127,10 @@
#ifdef NS_CACHING
/*
- * Cache lookup cycle prevention function - if !NULL then no cache lookups
+ * Cache lookup cycle prevention symbol - if !NULL then no cache lookups
* will be made
*/
-static void *nss_cache_cycle_prevention_func = NULL;
+static void *nss_cache_cycle_prevention_sym = NULL;
#endif
/*
@@ -397,8 +397,8 @@
#ifdef NS_CACHING
handle = libc_dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
if (handle != NULL) {
- nss_cache_cycle_prevention_func = dlsym(handle,
- "_nss_cache_cycle_prevention_function");
+ nss_cache_cycle_prevention_sym = dlsym(handle,
+ "_nss_cache_cycle_prevention_symbol");
dlclose(handle);
}
#endif
@@ -700,7 +700,7 @@
if (method != NULL) {
#ifdef NS_CACHING
if (strcmp(srclist[i].name, NSSRC_CACHE) == 0 &&
- nss_cache_cycle_prevention_func == NULL) {
+ nss_cache_cycle_prevention_sym == NULL) {
#ifdef NS_STRICT_LIBC_EID_CHECKING
if (issetugid() != 0)
continue;
diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c
--- a/sbin/ping/ping.c
+++ b/sbin/ping/ping.c
@@ -952,6 +952,9 @@
warn("recvmsg");
continue;
}
+ /* If we have a 0 byte read from recvfrom continue */
+ if (cc == 0)
+ continue;
#ifdef SO_TIMESTAMP
if (cmsg != NULL &&
cmsg->cmsg_level == SOL_SOCKET &&
@@ -1133,8 +1136,10 @@
struct icmp icp;
struct ip ip;
const u_char *icmp_data_raw;
+ ssize_t icmp_data_raw_len;
double triptime;
- int dupflag, hlen, i, j, recv_len;
+ int dupflag, i, j, recv_len;
+ uint8_t hlen;
uint16_t seq;
static int old_rrlen;
static char old_rr[MAX_IPOPTLEN];
@@ -1144,15 +1149,27 @@
const u_char *oicmp_raw;
/*
- * Get size of IP header of the received packet. The
- * information is contained in the lower four bits of the
- * first byte.
+ * Get size of IP header of the received packet.
+ * The header length is contained in the lower four bits of the first
+ * byte and represents the number of 4 byte octets the header takes up.
+ *
+ * The IHL minimum value is 5 (20 bytes) and its maximum value is 15
+ * (60 bytes).
*/
memcpy(&l, buf, sizeof(l));
hlen = (l & 0x0f) << 2;
- memcpy(&ip, buf, hlen);
- /* Check the IP header */
+ /* Reject IP packets with a short header */
+ if (hlen < sizeof(struct ip)) {
+ if (options & F_VERBOSE)
+ warn("IHL too short (%d bytes) from %s", hlen,
+ inet_ntoa(from->sin_addr));
+ return;
+ }
+
+ memcpy(&ip, buf, sizeof(struct ip));
+
+ /* Check packet has enough data to carry a valid ICMP header */
recv_len = cc;
if (cc < hlen + ICMP_MINLEN) {
if (options & F_VERBOSE)
@@ -1164,6 +1181,7 @@
#ifndef icmp_data
icmp_data_raw = buf + hlen + offsetof(struct icmp, icmp_ip);
#else
+ icmp_data_raw_len = cc - (hlen + offsetof(struct icmp, icmp_data));
icmp_data_raw = buf + hlen + offsetof(struct icmp, icmp_data);
#endif
@@ -1293,12 +1311,45 @@
* as root to avoid leaking information not normally
* available to those not running as root.
*/
+
+ /*
+ * If we don't have enough bytes for a quoted IP header and an
+ * ICMP header then stop.
+ */
+ if (icmp_data_raw_len <
+ (ssize_t)(sizeof(struct ip) + sizeof(struct icmp))) {
+ if (options & F_VERBOSE)
+ warnx("quoted data too short (%zd bytes) from %s",
+ icmp_data_raw_len, inet_ntoa(from->sin_addr));
+ return;
+ }
+
memcpy(&oip_header_len, icmp_data_raw, sizeof(oip_header_len));
oip_header_len = (oip_header_len & 0x0f) << 2;
- memcpy(&oip, icmp_data_raw, oip_header_len);
+
+ /* Reject IP packets with a short header */
+ if (oip_header_len < sizeof(struct ip)) {
+ if (options & F_VERBOSE)
+ warnx("inner IHL too short (%d bytes) from %s",
+ oip_header_len, inet_ntoa(from->sin_addr));
+ return;
+ }
+
+ /*
+ * Check against the actual IHL length, to protect against
+ * quoated packets carrying IP options.
+ */
+ if (icmp_data_raw_len <
+ (ssize_t)(oip_header_len + sizeof(struct icmp))) {
+ if (options & F_VERBOSE)
+ warnx("inner packet too short (%zd bytes) from %s",
+ icmp_data_raw_len, inet_ntoa(from->sin_addr));
+ return;
+ }
+
+ memcpy(&oip, icmp_data_raw, sizeof(struct ip));
oicmp_raw = icmp_data_raw + oip_header_len;
- memcpy(&oicmp, oicmp_raw, offsetof(struct icmp, icmp_id) +
- sizeof(oicmp.icmp_id));
+ memcpy(&oicmp, oicmp_raw, sizeof(struct icmp));
if (((options & F_VERBOSE) && uid == 0) ||
(!(options & F_QUIET2) &&
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -54,7 +54,7 @@
TYPE="FreeBSD"
REVISION="13.1"
-BRANCH="RELEASE-p4"
+BRANCH="RELEASE-p5"
if [ -n "${BRANCH_OVERRIDE}" ]; then
BRANCH=${BRANCH_OVERRIDE}
fi
diff --git a/usr.sbin/nscd/Makefile b/usr.sbin/nscd/Makefile
--- a/usr.sbin/nscd/Makefile
+++ b/usr.sbin/nscd/Makefile
@@ -11,6 +11,10 @@
CFLAGS+= -DCONFIG_PATH="\"${PREFIX}/etc/nscd.conf\""
LIBADD= util pthread
+# This is needed to have the _nss_cache_cycle_prevention_symbol
+# visible to dlysm() so the caching code can skip cache lookups in the
+# caching daemon. DO NOT REMOVE
+LDFLAGS= -Wl,-export-dynamic
.PATH: ${.CURDIR}/agents
.include "${.CURDIR}/agents/Makefile.inc"
diff --git a/usr.sbin/nscd/agents/group.c b/usr.sbin/nscd/agents/group.c
--- a/usr.sbin/nscd/agents/group.c
+++ b/usr.sbin/nscd/agents/group.c
@@ -31,20 +31,84 @@
#include <sys/param.h>
#include <assert.h>
+#include <errno.h>
#include <grp.h>
#include <nsswitch.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "../debug.h"
#include "group.h"
+#define GROUP_STORAGE_INITIAL (1 << 10)
+#define GROUP_STORAGE_MAX (1 << 20)
+
+typedef struct key {
+ char *name;
+ gid_t gid;
+} st_key;
+
+static int wrap_getgrnam_r(st_key, struct group *, char *, size_t,
+ struct group **);
+static int wrap_getgrgid_r(st_key, struct group *, char *, size_t,
+ struct group **);
+static int wrap_getgrent_r(st_key, struct group *, char *, size_t,
+ struct group **);
+static char *wrap_getgrouplist(st_key, size_t *);
+static char *getgr(int (*)(st_key, struct group *, char *, size_t,
+ struct group **), st_key, size_t *);
+
static int group_marshal_func(struct group *, char *, size_t *);
+static int grouplist_marshal_func(gid_t *, int, char *, size_t *);
static int group_lookup_func(const char *, size_t, char **, size_t *);
static void *group_mp_init_func(void);
static int group_mp_lookup_func(char **, size_t *, void *);
static void group_mp_destroy_func(void *);
+static int
+wrap_getgrnam_r(st_key skey, struct group *group, char *buffer, size_t size,
+ struct group **result)
+{
+ return (getgrnam_r(skey.name, group, buffer, size, result));
+}
+
+static int
+wrap_getgrgid_r(st_key skey, struct group *group, char *buffer, size_t size,
+ struct group **result)
+{
+ return (getgrgid_r(skey.gid, group, buffer, size, result));
+}
+
+static int
+wrap_getgrent_r(st_key skey __unused, struct group *group, char *buffer,
+ size_t size, struct group **result)
+{
+ return (getgrent_r(group, buffer, size, result));
+}
+
+static int
+grouplist_marshal_func(gid_t *gids, int ngids, char *buffer,
+ size_t* buffer_size)
+{
+ size_t desired_size;
+ TRACE_IN(grouplist_marshal_func);
+
+ desired_size = sizeof(int) + (ngids * sizeof(gid_t));
+ if ((buffer == NULL) || (desired_size > *buffer_size)) {
+ *buffer_size = desired_size;
+ TRACE_OUT(grouplist_marshal_func);
+
+ return NS_RETURN;
+ }
+ *buffer_size = desired_size;
+ memcpy(buffer, &ngids, sizeof(ngids));
+ memcpy(buffer + sizeof(ngids), gids, sizeof(gid_t) * ngids);
+ TRACE_OUT(grouplist_marshal_func);
+
+ return (NS_SUCCESS);
+}
+
static int
group_marshal_func(struct group *grp, char *buffer, size_t *buffer_size)
{
@@ -73,6 +137,7 @@
if ((desired_size > *buffer_size) || (buffer == NULL)) {
*buffer_size = desired_size;
TRACE_OUT(group_marshal_func);
+
return (NS_RETURN);
}
@@ -114,6 +179,7 @@
memcpy(buffer, &new_grp, sizeof(struct group));
TRACE_OUT(group_marshal_func);
+
return (NS_SUCCESS);
}
@@ -122,66 +188,83 @@
size_t *buffer_size)
{
enum nss_lookup_type lookup_type;
- char *name;
+ st_key stkey;
size_t size;
- gid_t gid;
-
- struct group *result;
TRACE_IN(group_lookup_func);
assert(buffer != NULL);
assert(buffer_size != NULL);
+ *buffer_size = 0;
if (key_size < sizeof(enum nss_lookup_type)) {
TRACE_OUT(group_lookup_func);
+
return (NS_UNAVAIL);
}
memcpy(&lookup_type, key, sizeof(enum nss_lookup_type));
switch (lookup_type) {
case nss_lt_name:
- size = key_size - sizeof(enum nss_lookup_type) + 1;
- name = calloc(1, size);
- assert(name != NULL);
- memcpy(name, key + sizeof(enum nss_lookup_type), size - 1);
+ if (key_size < sizeof(enum nss_lookup_type) + 2) {
+ TRACE_OUT(group_lookup_func);
+
+ return (NS_UNAVAIL);
+ }
+
+ size = key_size - sizeof(enum nss_lookup_type);
+ stkey.name = malloc(size);
+ assert(stkey.name != NULL);
+
+ memcpy(stkey.name, key + sizeof(enum nss_lookup_type), size);
+ stkey.name[size-1] = 0x00;
+
+ TRACE_STR(stkey.name);
+ errno = 0;
+ *buffer = getgr(wrap_getgrnam_r, stkey, buffer_size);
+ free(stkey.name);
+
break;
case nss_lt_id:
if (key_size < sizeof(enum nss_lookup_type) +
sizeof(gid_t)) {
- TRACE_OUT(passwd_lookup_func);
+ TRACE_OUT(group_lookup_func);
+
return (NS_UNAVAIL);
}
+ memcpy(&(stkey.gid), key + sizeof(enum nss_lookup_type), sizeof(gid_t));
+ errno=0;
+ *buffer = getgr(wrap_getgrgid_r, stkey, buffer_size);
- memcpy(&gid, key + sizeof(enum nss_lookup_type), sizeof(gid_t));
break;
- default:
- TRACE_OUT(group_lookup_func);
- return (NS_UNAVAIL);
- }
+ case nss_lt_pivot:
+ if (key_size < sizeof(enum nss_lookup_type) + 2
+ + sizeof(gid_t)) {
+ TRACE_OUT(group_lookup_func);
- switch (lookup_type) {
- case nss_lt_name:
- TRACE_STR(name);
- result = getgrnam(name);
- free(name);
- break;
- case nss_lt_id:
- result = getgrgid(gid);
+ return (NS_UNAVAIL);
+ }
+ size = key_size - sizeof(enum nss_lookup_type) - sizeof(gid_t);
+ stkey.name = malloc(size);
+ assert(stkey.name != NULL);
+ memcpy(stkey.name, key + sizeof(enum nss_lookup_type), size);
+ stkey.name[size-1]=0x00;
+
+ memcpy (&(stkey.gid), key + sizeof(enum nss_lookup_type) + size, sizeof(gid_t));
+
+ errno = 0;
+ *buffer = wrap_getgrouplist(stkey, buffer_size);
break;
default:
- /* SHOULD NOT BE REACHED */
- break;
- }
+ TRACE_OUT(group_lookup_func);
- if (result != NULL) {
- group_marshal_func(result, NULL, buffer_size);
- *buffer = malloc(*buffer_size);
- assert(*buffer != NULL);
- group_marshal_func(result, *buffer, buffer_size);
+ return (NS_UNAVAIL);
}
TRACE_OUT(group_lookup_func);
- return (result == NULL ? NS_NOTFOUND : NS_SUCCESS);
+
+ return (*buffer == NULL ?
+ (errno == 0 ? NS_NOTFOUND : NS_UNAVAIL) :
+ NS_SUCCESS);
}
static void *
@@ -197,19 +280,21 @@
static int
group_mp_lookup_func(char **buffer, size_t *buffer_size, void *mdata)
{
- struct group *result;
+ st_key stkey;
TRACE_IN(group_mp_lookup_func);
- result = getgrent();
- if (result != NULL) {
- group_marshal_func(result, NULL, buffer_size);
- *buffer = malloc(*buffer_size);
- assert(*buffer != NULL);
- group_marshal_func(result, *buffer, buffer_size);
- }
+ assert(buffer != NULL);
+ assert(buffer_size != NULL);
+ *buffer_size = 0;
+ errno = 0;
+ stkey.name = NULL;
+ *buffer = getgr(wrap_getgrent_r, stkey, buffer_size);
TRACE_OUT(group_mp_lookup_func);
- return (result == NULL ? NS_NOTFOUND : NS_SUCCESS);
+
+ return (*buffer == NULL ?
+ (errno == 0 ? NS_NOTFOUND : NS_UNAVAIL) :
+ NS_SUCCESS);
}
static void
@@ -235,6 +320,7 @@
retval->lookup_func = group_lookup_func;
TRACE_OUT(init_group_agent);
+
return ((struct agent *)retval);
}
@@ -256,5 +342,82 @@
assert(retval->parent.name != NULL);
TRACE_OUT(init_group_mp_agent);
+
return ((struct agent *)retval);
}
+
+static char *wrap_getgrouplist(st_key skey, size_t *buffer_size)
+{
+ int return_value;
+ gid_t *gids;
+ int ngids = 0;
+ char *buffer;
+
+ do {
+ ngids += NGROUPS;
+ gids = malloc(ngids * sizeof(gid_t));
+ assert (gids != NULL);
+ errno=0;
+ return_value=getgrouplist(skey.name, skey.gid, gids, &ngids);
+ } while (return_value == -1 && errno == 0 && (free(gids), 1 == 1));
+ if (errno != 0) {
+
+ return (NULL);
+ }
+ grouplist_marshal_func(gids, ngids, NULL, buffer_size);
+ buffer = malloc(*buffer_size);
+ assert(buffer != NULL);
+ grouplist_marshal_func(gids, ngids, buffer, buffer_size);
+ free(gids);
+
+ return (buffer);
+}
+static char *
+getgr(int (*fn)(st_key, struct group *, char *, size_t, struct group **),
+ st_key skey, size_t *buffer_size)
+{
+ int return_value;
+ struct group group, *result;
+ char *group_storage, *buffer;
+ size_t group_storage_size = GROUP_STORAGE_INITIAL;
+
+ group_storage = malloc(group_storage_size);
+ if (group_storage == NULL) {
+
+ return (NULL);
+ }
+ do {
+ return_value = fn(skey, &group, group_storage, group_storage_size, &result);
+ if (result == NULL && return_value == ERANGE) {
+ free(group_storage);
+ group_storage = NULL;
+ group_storage_size <<= 1;
+ if (group_storage_size > GROUP_STORAGE_MAX) {
+ errno = ERANGE;
+
+ return (NULL);
+ }
+ group_storage = malloc(group_storage_size);
+ if (group_storage == NULL) {
+
+ return (NULL);
+ }
+ }
+ } while (result == NULL && return_value == ERANGE);
+ errno = return_value;
+ if (return_value != 0 || result == NULL) {
+ free(group_storage);
+
+ return (NULL);
+ }
+
+ group_marshal_func(&group, NULL, buffer_size);
+ buffer = malloc(*buffer_size);
+ assert(buffer != NULL);
+ group_marshal_func(&group, buffer, buffer_size);
+
+ free(group_storage);
+
+ return (buffer);
+}
+
diff --git a/usr.sbin/nscd/agents/passwd.c b/usr.sbin/nscd/agents/passwd.c
--- a/usr.sbin/nscd/agents/passwd.c
+++ b/usr.sbin/nscd/agents/passwd.c
@@ -31,6 +31,7 @@
#include <sys/types.h>
#include <assert.h>
+#include <errno.h>
#include <nsswitch.h>
#include <pwd.h>
#include <stdlib.h>
@@ -39,12 +40,101 @@
#include "../debug.h"
#include "passwd.h"
+#define PASSWD_STORAGE_INITIAL (1<<10)
+#define PASSWD_STORAGE_MAX (1<<20)
+
+typedef union key {
+ char *login;
+ uid_t uid;
+} u_key;
+
static int passwd_marshal_func(struct passwd *, char *, size_t *);
static int passwd_lookup_func(const char *, size_t, char **, size_t *);
static void *passwd_mp_init_func(void);
static int passwd_mp_lookup_func(char **, size_t *, void *);
static void passwd_mp_destroy_func(void *mdata);
+static char *getpw(int (*)(u_key, struct passwd *, char *, size_t,
+ struct passwd **), u_key, size_t *);
+static int wrap_getpwnam_r(u_key, struct passwd *, char *, size_t,
+ struct passwd **);
+static int wrap_getpwuid_r(u_key, struct passwd *, char *, size_t,
+ struct passwd **);
+static int wrap_getpwent_r(u_key, struct passwd *, char *, size_t,
+ struct passwd **);
+
+static char *
+getpw(int (*fn)(u_key, struct passwd *, char *, size_t, struct passwd **),
+ u_key ukey, size_t *buffer_size)
+{
+ int return_value;
+ struct passwd passwd, *result;
+ char *passwd_storage, *buffer;
+ size_t passwd_storage_size = PASSWD_STORAGE_INITIAL;
+
+ passwd_storage = malloc(passwd_storage_size);
+ if (passwd_storage == NULL) {
+
+ return (NULL);
+ }
+ do {
+ return_value = fn(ukey, &passwd, passwd_storage,
+ passwd_storage_size, &result);
+ if (result == NULL && return_value == ERANGE) {
+ free(passwd_storage);
+ passwd_storage = NULL;
+ passwd_storage_size <<= 1;
+ if (passwd_storage_size > PASSWD_STORAGE_MAX) {
+ errno = ERANGE;
+
+ return (NULL);
+ }
+ passwd_storage = malloc(passwd_storage_size);
+ if (passwd_storage == NULL) {
+
+ return (NULL);
+ }
+ }
+ } while (result == NULL && return_value == ERANGE);
+ errno = return_value;
+ if (return_value != 0 || result == NULL) {
+ free(passwd_storage);
+
+ return (NULL);
+ }
+
+ *buffer_size = 0;
+ passwd_marshal_func(&passwd, NULL, buffer_size);
+ buffer = malloc(*buffer_size);
+ assert(buffer != NULL);
+ passwd_marshal_func(&passwd, buffer, buffer_size);
+
+ free(passwd_storage);
+
+ return (buffer);
+}
+
+static int
+wrap_getpwnam_r(u_key ukey, struct passwd *pwd, char *buffer, size_t bufsize,
+ struct passwd **res)
+{
+ return (getpwnam_r(ukey.login, pwd, buffer, bufsize, res));
+}
+
+static int
+wrap_getpwuid_r(u_key ukey, struct passwd *pwd, char *buffer, size_t bufsize,
+ struct passwd **res)
+{
+ return (getpwuid_r(ukey.uid, pwd, buffer, bufsize, res));
+}
+
+static int
+wrap_getpwent_r(u_key ukey __unused, struct passwd *pwd, char *buffer,
+ size_t bufsize, struct passwd **res)
+{
+ return (getpwent_r(pwd, buffer, bufsize, res));
+}
+
static int
passwd_marshal_func(struct passwd *pwd, char *buffer, size_t *buffer_size)
{
@@ -69,6 +159,7 @@
if ((*buffer_size < desired_size) || (buffer == NULL)) {
*buffer_size = desired_size;
TRACE_OUT(passwd_marshal_func);
+
return (NS_RETURN);
}
@@ -123,6 +214,7 @@
memcpy(buffer, &new_pwd, sizeof(struct passwd));
TRACE_OUT(passwd_marshal_func);
+
return (NS_SUCCESS);
}
@@ -131,65 +223,67 @@
size_t *buffer_size)
{
enum nss_lookup_type lookup_type;
- char *login;
+ u_key ukey;
size_t size;
- uid_t uid;
-
- struct passwd *result;
TRACE_IN(passwd_lookup_func);
assert(buffer != NULL);
assert(buffer_size != NULL);
+ *buffer_size = 0;
if (key_size < sizeof(enum nss_lookup_type)) {
TRACE_OUT(passwd_lookup_func);
+
return (NS_UNAVAIL);
}
memcpy(&lookup_type, key, sizeof(enum nss_lookup_type));
switch (lookup_type) {
case nss_lt_name:
- size = key_size - sizeof(enum nss_lookup_type) + 1;
- login = calloc(1, size);
- assert(login != NULL);
- memcpy(login, key + sizeof(enum nss_lookup_type), size - 1);
+ if (key_size < sizeof(enum nss_lookup_type) + 2) {
+ TRACE_OUT(passwd_lookup_func);
+
+ return (NS_UNAVAIL);
+ }
+
+ size = key_size - sizeof(enum nss_lookup_type);
+ ukey.login = malloc(size);
+ assert(ukey.login != NULL);
+
+ memcpy(ukey.login, key + sizeof(enum nss_lookup_type), size);
+ ukey.login[size-1]=0x00;
+
+ TRACE_STR(ukey.login);
+ errno = 0;
+ *buffer = getpw(wrap_getpwnam_r, ukey, buffer_size);
+ free(ukey.login);
+
break;
case nss_lt_id:
if (key_size < sizeof(enum nss_lookup_type) +
sizeof(uid_t)) {
TRACE_OUT(passwd_lookup_func);
+
return (NS_UNAVAIL);
}
- memcpy(&uid, key + sizeof(enum nss_lookup_type), sizeof(uid_t));
- break;
- default:
- TRACE_OUT(passwd_lookup_func);
- return (NS_UNAVAIL);
- }
+ memcpy(&ukey.uid, key + sizeof(enum nss_lookup_type),
+ sizeof(uid_t));
+ errno = 0;
+ *buffer = getpw(wrap_getpwuid_r, ukey, buffer_size);
- switch (lookup_type) {
- case nss_lt_name:
- result = getpwnam(login);
- free(login);
- break;
- case nss_lt_id:
- result = getpwuid(uid);
break;
default:
- /* SHOULD NOT BE REACHED */
- break;
- }
+ TRACE_OUT(passwd_lookup_func);
- if (result != NULL) {
- passwd_marshal_func(result, NULL, buffer_size);
- *buffer = malloc(*buffer_size);
- assert(*buffer != NULL);
- passwd_marshal_func(result, *buffer, buffer_size);
+ return (NS_UNAVAIL);
}
TRACE_OUT(passwd_lookup_func);
- return (result == NULL ? NS_NOTFOUND : NS_SUCCESS);
+
+ return (*buffer == NULL ?
+ (errno == 0 ? NS_NOTFOUND : NS_UNAVAIL) :
+ NS_SUCCESS);
}
static void *
@@ -205,19 +299,21 @@
static int
passwd_mp_lookup_func(char **buffer, size_t *buffer_size, void *mdata)
{
- struct passwd *result;
+ u_key ukey;
TRACE_IN(passwd_mp_lookup_func);
- result = getpwent();
- if (result != NULL) {
- passwd_marshal_func(result, NULL, buffer_size);
- *buffer = malloc(*buffer_size);
- assert(*buffer != NULL);
- passwd_marshal_func(result, *buffer, buffer_size);
- }
+ assert(buffer != NULL);
+ assert(buffer_size != NULL);
+ *buffer_size = 0;
+ errno = 0;
+ ukey.uid = 0;
+ *buffer = getpw(wrap_getpwent_r, ukey, buffer_size);
TRACE_OUT(passwd_mp_lookup_func);
- return (result == NULL ? NS_NOTFOUND : NS_SUCCESS);
+
+ return (*buffer == NULL ?
+ (errno == 0 ? NS_NOTFOUND : NS_UNAVAIL) :
+ NS_SUCCESS);
}
static void
@@ -243,6 +339,7 @@
retval->lookup_func = passwd_lookup_func;
TRACE_OUT(init_passwd_agent);
+
return ((struct agent *)retval);
}
@@ -264,5 +361,6 @@
assert(retval->parent.name != NULL);
TRACE_OUT(init_passwd_mp_agent);
+
return ((struct agent *)retval);
}
diff --git a/usr.sbin/nscd/nscd.c b/usr.sbin/nscd/nscd.c
--- a/usr.sbin/nscd/nscd.c
+++ b/usr.sbin/nscd/nscd.c
@@ -581,17 +581,14 @@
}
/*
- * The idea of _nss_cache_cycle_prevention_function is that nsdispatch
+ * The idea of _nss_cache_cycle_prevention_symbol is that nsdispatch
* will search for this symbol in the executable. This symbol is the
* attribute of the caching daemon. So, if it exists, nsdispatch won't try
* to connect to the caching daemon and will just ignore the 'cache'
* source in the nsswitch.conf. This method helps to avoid cycles and
* organize self-performing requests.
- *
- * (not actually a function; it used to be, but it doesn't make any
- * difference, as long as it has external linkage)
*/
-void *_nss_cache_cycle_prevention_function;
+void *_nss_cache_cycle_prevention_symbol;
int
main(int argc, char *argv[])
diff --git a/usr.sbin/nscd/query.c b/usr.sbin/nscd/query.c
--- a/usr.sbin/nscd/query.c
+++ b/usr.sbin/nscd/query.c
@@ -803,8 +803,13 @@
CELT_NEGATIVE);
read_response->error_code = 0;
- read_response->data = NULL;
- read_response->data_size = 0;
+ read_response->data_size =
+ sizeof(negative_data);
+ read_response->data =
+ malloc(read_response->data_size);
+ memcpy(read_response->data,
+ negative_data,
+ read_response->data_size);
}
}
}

File Metadata

Mime Type
text/plain
Expires
Fri, Jan 23, 11:04 PM (19 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27891023
Default Alt Text
D38047.id125561.diff (29 KB)

Event Timeline