Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142740116
D38047.id125561.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
29 KB
Referenced Files
None
Subscribers
None
D38047.id125561.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D38047: Multiple fixes to the NSS caching system
Attached
Detach File
Event Timeline
Log In to Comment