Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102587789
D38047.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
D38047.diff
View Options
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
@@ -151,6 +151,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)
@@ -167,15 +169,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;
@@ -191,6 +193,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:
@@ -203,6 +221,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)
@@ -297,6 +345,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)
@@ -476,7 +556,7 @@
gid_t *groups;
gid_t agroup;
int maxgrp, *grpcnt;
- int i, rv, ret_errno;
+ int i, rv, grp_errno, *ret_errno;
/*
* As this is a fallback method, only provided src
@@ -489,6 +569,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;
@@ -503,12 +584,12 @@
_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", src, 0);
for (;;) {
do {
- ret_errno = 0;
+ grp_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, &grp_errno);
- if (grp_p == NULL && ret_errno == ERANGE) {
+ if (grp_p == NULL && grp_errno == ERANGE) {
free(buf);
if ((bufsize << 1) > GRP_STORAGE_MAX) {
buf = NULL;
@@ -522,10 +603,10 @@
goto out;
}
}
- } while (grp_p == NULL && ret_errno == ERANGE);
+ } while (grp_p == NULL && grp_errno == ERANGE);
- if (ret_errno != 0) {
- errno = ret_errno;
+ if (grp_errno != 0) {
+ *ret_errno = grp_errno;
goto out;
}
@@ -538,6 +619,7 @@
}
}
+ *ret_errno = 0;
_nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", src);
out:
free(buf);
@@ -665,8 +747,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 }
};
@@ -676,9 +769,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
@@ -214,15 +214,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/nscache.c b/lib/libc/net/nscache.c
--- a/lib/libc/net/nscache.c
+++ b/lib/libc/net/nscache.c
@@ -107,8 +107,8 @@
do {
connection = __open_cached_connection(¶ms);
if (connection == NULL) {
- res = -1;
- break;
+ free(buffer);
+ return (NS_UNAVAIL);
}
res = __cached_read(connection, cache_info->entry_name,
cache_data->key, cache_data->key_size, buffer,
@@ -317,11 +317,11 @@
__close_cached_mp_read_session(rs);
rs = INVALID_CACHED_MP_READ_SESSION;
cache_info->set_mp_rs_func(rs);
- return (res == -1 ? NS_RETURN : NS_UNAVAIL);
+ return (res == 1 ? NS_NOTFOUND : NS_UNAVAIL);
}
free(buffer);
- return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
+ return (NS_SUCCESS);
}
int
diff --git a/lib/libc/net/nscachedcli.c b/lib/libc/net/nscachedcli.c
--- a/lib/libc/net/nscachedcli.c
+++ b/lib/libc/net/nscachedcli.c
@@ -538,7 +538,7 @@
goto fin;
if (rec_error_code != 0) {
- error_code = rec_error_code;
+ error_code = -rec_error_code;
goto fin;
}
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
@@ -124,10 +124,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
/*
@@ -394,8 +394,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
@@ -641,6 +641,13 @@
nss_cache_data cache_data;
nss_cache_data *cache_data_p;
int cache_flag;
+ int cache_start;
+ int is_nscd;
+
+ cache_start = 0;
+ cache_flag = 0;
+ cache_data_p = NULL;
+ is_nscd = nss_cache_cycle_prevention_sym != NULL;
#endif
dbt = NULL;
@@ -685,19 +692,28 @@
srclistsize++;
}
+ for (i = 0; i < srclistsize; i++) {
#ifdef NS_CACHING
- cache_data_p = NULL;
- cache_flag = 0;
+ int is_cache;
+
+ is_cache = strcmp(srclist[i].name, NSSRC_CACHE) == 0;
+
+ if (is_cache) {
+ cache_start = 1;
+
+ if (is_nscd) {
+ /* don't try to call nscd inside nscd */
+ continue;
+ }
+ }
#endif
- for (i = 0; i < srclistsize; i++) {
result = NS_NOTFOUND;
method = nss_method_lookup(srclist[i].name, database,
method_name, disp_tab, &mdata);
if (method != NULL) {
#ifdef NS_CACHING
- if (strcmp(srclist[i].name, NSSRC_CACHE) == 0 &&
- nss_cache_cycle_prevention_func == NULL) {
+ if (is_cache) {
#ifdef NS_STRICT_LIBC_EID_CHECKING
if (issetugid() != 0)
continue;
@@ -733,8 +749,6 @@
va_end(ap);
#endif /* NS_CACHING */
- if (result & (srclist[i].flags))
- break;
} else {
if (fb_method != NULL) {
saved_depth = st->fallback_depth;
@@ -749,10 +763,12 @@
"and no fallback provided",
srclist[i].name, database, method_name);
}
+ if (result & (srclist[i].flags))
+ break;
}
#ifdef NS_CACHING
- if (cache_data_p != NULL &&
+ if (!is_nscd && cache_start && cache_data_p != NULL &&
(result & (NS_NOTFOUND | NS_SUCCESS)) && cache_flag == 0) {
va_start(ap, defaults);
if (result == NS_SUCCESS) {
diff --git a/usr.sbin/nscd/Makefile b/usr.sbin/nscd/Makefile
--- a/usr.sbin/nscd/Makefile
+++ b/usr.sbin/nscd/Makefile
@@ -9,6 +9,10 @@
CFLAGS+= -DCONFIG_PATH="\"${PREFIX}/etc/nscd.conf\""
LIBADD= util pthread
+# This is needed to have the _nss_cache_cycle_prevention_symbol
+# visible to dlsym() 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
@@ -28,20 +28,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)
{
@@ -119,15 +183,14 @@
size_t *buffer_size)
{
enum nss_lookup_type lookup_type;
- char *name;
+ st_key stkey;
size_t size;
- gid_t gid;
-
- struct group *result;
+ int gr_errno;
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);
@@ -137,48 +200,67 @@
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);
+ gr_errno = errno;
+ 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);
+ gr_errno = errno;
- 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);
+ 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);
+ gr_errno = errno;
- switch (lookup_type) {
- case nss_lt_name:
- TRACE_STR(name);
- result = getgrnam(name);
- free(name);
- break;
- case nss_lt_id:
- result = getgrgid(gid);
break;
default:
- /* SHOULD NOT BE REACHED */
- break;
- }
-
- if (result != NULL) {
- group_marshal_func(result, NULL, buffer_size);
- *buffer = malloc(*buffer_size);
- assert(*buffer != NULL);
- group_marshal_func(result, *buffer, buffer_size);
+ TRACE_OUT(group_lookup_func);
+ return (NS_UNAVAIL);
}
TRACE_OUT(group_lookup_func);
- return (result == NULL ? NS_NOTFOUND : NS_SUCCESS);
+ return (*buffer == NULL ?
+ (gr_errno == 0 ? NS_NOTFOUND : NS_UNAVAIL) :
+ NS_SUCCESS);
}
static void *
@@ -194,19 +276,20 @@
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
@@ -255,3 +338,83 @@
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 = NULL;
+ int ngids = 0;
+ char *buffer;
+
+ errno = 0;
+ return_value = getgrouplist(skey.name, skey.gid, gids, &ngids);
+
+ while (return_value == -1 && errno == 0) {
+ gids = realloc(gids, ngids * sizeof(gid_t));
+ assert (gids != NULL);
+ errno=0;
+ return_value=getgrouplist(skey.name, skey.gid, gids, &ngids);
+ }
+
+ if (errno != 0) {
+ free (gids);
+ 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
@@ -28,6 +28,7 @@
#include <sys/types.h>
#include <assert.h>
+#include <errno.h>
#include <nsswitch.h>
#include <pwd.h>
#include <stdlib.h>
@@ -36,12 +37,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)
{
@@ -128,15 +218,14 @@
size_t *buffer_size)
{
enum nss_lookup_type lookup_type;
- char *login;
+ u_key ukey;
size_t size;
- uid_t uid;
-
- struct passwd *result;
+ int pw_errno;
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);
@@ -146,10 +235,24 @@
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);
+ pw_errno = errno;
+ free(ukey.login);
+
break;
case nss_lt_id:
if (key_size < sizeof(enum nss_lookup_type) +
@@ -158,35 +261,23 @@
return (NS_UNAVAIL);
}
- memcpy(&uid, key + sizeof(enum nss_lookup_type), sizeof(uid_t));
+ memcpy(&ukey.uid, key + sizeof(enum nss_lookup_type),
+ sizeof(uid_t));
+ errno = 0;
+ *buffer = getpw(wrap_getpwuid_r, ukey, buffer_size);
+ pw_errno = errno;
+
break;
default:
TRACE_OUT(passwd_lookup_func);
return (NS_UNAVAIL);
}
- 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;
- }
-
- if (result != NULL) {
- passwd_marshal_func(result, NULL, buffer_size);
- *buffer = malloc(*buffer_size);
- assert(*buffer != NULL);
- passwd_marshal_func(result, *buffer, buffer_size);
- }
-
TRACE_OUT(passwd_lookup_func);
- return (result == NULL ? NS_NOTFOUND : NS_SUCCESS);
+
+ return (*buffer == NULL ?
+ (pw_errno == 0 ? NS_NOTFOUND : NS_UNAVAIL) :
+ NS_SUCCESS);
}
static void *
@@ -202,19 +293,20 @@
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
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
@@ -577,17 +577,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
@@ -800,8 +800,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, Nov 15, 11:02 AM (14 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14641240
Default Alt Text
D38047.diff (25 KB)
Attached To
Mode
D38047: Multiple fixes to the NSS caching system
Attached
Detach File
Event Timeline
Log In to Comment