Page MenuHomeFreeBSD

D38047.diff
No OneTemporary

D38047.diff

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(&params);
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

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)

Event Timeline