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, sub_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; + 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; @@ -522,10 +603,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; } @@ -665,8 +746,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 +768,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/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 @@ -697,7 +697,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/usr.sbin/nscd/Makefile b/usr.sbin/nscd/Makefile --- a/usr.sbin/nscd/Makefile +++ b/usr.sbin/nscd/Makefile @@ -10,6 +10,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 @@ -28,20 +28,84 @@ #include #include +#include #include #include #include #include +#include #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) { @@ -70,6 +134,7 @@ if ((desired_size > *buffer_size) || (buffer == NULL)) { *buffer_size = desired_size; TRACE_OUT(group_marshal_func); + return (NS_RETURN); } @@ -111,6 +176,7 @@ memcpy(buffer, &new_grp, sizeof(struct group)); TRACE_OUT(group_marshal_func); + return (NS_SUCCESS); } @@ -119,66 +185,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 * @@ -194,19 +277,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 @@ -232,6 +317,7 @@ retval->lookup_func = group_lookup_func; TRACE_OUT(init_group_agent); + return ((struct agent *)retval); } @@ -253,5 +339,81 @@ 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 @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -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) { @@ -66,6 +156,7 @@ if ((*buffer_size < desired_size) || (buffer == NULL)) { *buffer_size = desired_size; TRACE_OUT(passwd_marshal_func); + return (NS_RETURN); } @@ -120,6 +211,7 @@ memcpy(buffer, &new_pwd, sizeof(struct passwd)); TRACE_OUT(passwd_marshal_func); + return (NS_SUCCESS); } @@ -128,65 +220,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 * @@ -202,19 +296,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 @@ -240,6 +336,7 @@ retval->lookup_func = passwd_lookup_func; TRACE_OUT(init_passwd_agent); + return ((struct agent *)retval); } @@ -261,5 +358,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 @@ -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); } } }