#include "config.h"
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
/*
* Defining _POSIX_PTHREAD_SEMANTICS before including pwd.h and grp.h gives us
* the posix getpwnam_r(), getpwuid_r(), getgrnam_r and getgrgid_r calls on
* Solaris
*/
#ifndef _POSIX_PTHREAD_SEMANTICS
#define _POSIX_PTHREAD_SEMANTICS
#endif
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef NDEBUG
#define DEBUG(...)
#else
#define DEBUG(...) printf(__VA_ARGS__)
#endif
#ifndef SAFE_FREE
#define SAFE_FREE(x) do { if ((x) != NULL) {free((x)); (x)=NULL;} } while(0)
#endif
static void assert_passwd_equal(const struct passwd *p1,
const struct passwd *p2)
{
assert_string_equal(p1->pw_name, p2->pw_name);
assert_string_equal(p1->pw_passwd, p2->pw_passwd);
assert_int_equal(p1->pw_uid, p2->pw_uid);
assert_int_equal(p1->pw_gid, p2->pw_gid);
assert_string_equal(p1->pw_gecos, p2->pw_gecos);
assert_string_equal(p1->pw_dir, p2->pw_dir);
assert_string_equal(p1->pw_shell, p2->pw_shell);
}
static void assert_group_equal(const struct group *g1,
const struct group *g2)
{
int i;
assert_string_equal(g1->gr_name, g2->gr_name);
assert_string_equal(g1->gr_passwd, g2->gr_passwd);
assert_int_equal(g1->gr_gid, g2->gr_gid);
assert_false(g1->gr_mem != NULL && g2->gr_mem == NULL);
assert_false(g1->gr_mem == NULL && g2->gr_mem != NULL);
if (g1->gr_mem == NULL && g2->gr_mem == NULL) {
return;
}
for (i=0; g1->gr_mem[i] && g2->gr_mem[i]; i++) {
assert_string_equal(g1->gr_mem[i], g2->gr_mem[i]);
}
}
static bool copy_passwd(const struct passwd *pwd, struct passwd *p)
{
p->pw_name = strdup(pwd->pw_name);
p->pw_passwd = strdup(pwd->pw_passwd);
p->pw_uid = pwd->pw_uid;
p->pw_gid = pwd->pw_gid;
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
p->pw_class = strdup(pwd->pw_class);
#endif
#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
p->pw_change = pwd->pw_change;
#endif
#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
p->pw_expire = pwd->pw_expire;
#endif
p->pw_gecos = strdup(pwd->pw_gecos);
p->pw_dir = strdup(pwd->pw_dir);
p->pw_shell = strdup(pwd->pw_shell);
return true;
}
static void free_passwd(struct passwd *p)
{
SAFE_FREE(p->pw_name);
SAFE_FREE(p->pw_passwd);
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
SAFE_FREE(p->pw_class);
#endif
SAFE_FREE(p->pw_gecos);
SAFE_FREE(p->pw_dir);
SAFE_FREE(p->pw_shell);
}
static void free_passwds(struct passwd *pwds, size_t num_pwds)
{
size_t i;
for(i = 0; i < num_pwds; i++) {
free_passwd(&pwds[i]);
}
free(pwds);
}
static void print_passwd(struct passwd *pwd)
{
(void)pwd;
DEBUG("%s:%s:%lu:%lu:%s:%s:%s\n",
pwd->pw_name,
pwd->pw_passwd,
(unsigned long)pwd->pw_uid,
(unsigned long)pwd->pw_gid,
pwd->pw_gecos,
pwd->pw_dir,
pwd->pw_shell);
}
static bool test_nwrap_getpwnam(const char *name, struct passwd *pwd_p)
{
struct passwd *pwd = NULL;
bool ok;
DEBUG("Testing getpwnam: %s\n", name);
pwd = getpwnam(name);
if (pwd == NULL) {
return false;
}
print_passwd(pwd);
if (pwd_p == NULL) {
return true;
}
ok = copy_passwd(pwd, pwd_p);
return ok;
}
static void test_nwrap_getpwnam_r(const char *name,
struct passwd *pwd_p)
{
struct passwd pwd, *pwdp;
char buffer[4096];
int ret;
DEBUG("Testing getpwnam_r: %s\n", name);
ret = getpwnam_r(name, &pwd, buffer, sizeof(buffer), &pwdp);
if (ret != 0) {
if (ret != ENOENT) {
DEBUG("got %d return code\n", ret);
}
assert_true(ret);
}
assert_ptr_equal(&pwd, pwdp);
print_passwd(&pwd);
if (pwd_p) {
copy_passwd(&pwd, pwd_p);
}
}
static bool test_nwrap_getpwuid(uid_t uid,
struct passwd *pwd_p)
{
struct passwd *pwd = NULL;
bool ok;
DEBUG("Testing getpwuid: %lu\n", (unsigned long)uid);
pwd = getpwuid(uid);
if (pwd == NULL) {
return false;
}
print_passwd(pwd);
if (pwd_p == NULL) {
return true;
}
ok = copy_passwd(pwd, pwd_p);
return ok;
}
static bool test_nwrap_getpwuid_r(uid_t uid,
struct passwd *pwd_p)
{
struct passwd pwd, *pwdp;
char buffer[4096];
int ret;
DEBUG("Testing getpwuid_r: %lu\n", (unsigned long)uid);
ret = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &pwdp);
if (ret != 0) {
if (ret != ENOENT) {
DEBUG("got %d return code\n", ret);
}
assert_true(ret);
}
assert_ptr_equal(&pwd, pwdp);
print_passwd(&pwd);
if (pwd_p) {
copy_passwd(&pwd, pwd_p);
}
return true;
}
static bool copy_group(const struct group *grp,
struct group *g)
{
int i;
g->gr_name = strdup(grp->gr_name);
g->gr_passwd = strdup(grp->gr_passwd);
g->gr_gid = grp->gr_gid;
g->gr_mem = NULL;
for (i = 0; grp->gr_mem != NULL && grp->gr_mem[i] != NULL; i++) {
char **mem;
mem = realloc(g->gr_mem, sizeof(char *) * (i + 2));
assert_non_null(mem);
g->gr_mem = mem;
g->gr_mem[i] = strdup(grp->gr_mem[i]);
assert_non_null(g->gr_mem[i]);
g->gr_mem[i + 1] = NULL;
}
return true;
}
static void free_group(struct group *g)
{
SAFE_FREE(g->gr_name);
SAFE_FREE(g->gr_passwd);
if (g->gr_mem != NULL) {
int i;
for (i = 0; g->gr_mem[i] != NULL; i++) {
SAFE_FREE(g->gr_mem[i]);
}
SAFE_FREE(g->gr_mem);
}
}
static void free_groups(struct group *grps, size_t num_grps)
{
size_t i;
for(i = 0; i < num_grps; i++) {
free_group(&grps[i]);
}
free(grps);
}
static void print_group(struct group *grp)
{
int i;
DEBUG("%s:%s:%lu:",
grp->gr_name,
grp->gr_passwd,
(unsigned long)grp->gr_gid);
if ((grp->gr_mem == NULL) || !grp->gr_mem[0]) {
DEBUG("\n");
return;
}
for (i=0; grp->gr_mem[i+1]; i++) {
DEBUG("%s,", grp->gr_mem[i]);
}
DEBUG("%s\n", grp->gr_mem[i]);
}
static bool test_nwrap_getgrnam(const char *name,
struct group *grp_p)
{
struct group *grp = NULL;
bool ok;
DEBUG("Testing getgrnam: %s\n", name);
grp = getgrnam(name);
if (grp == NULL) {
return false;
}
print_group(grp);
if (grp_p == NULL) {
return true;
}
ok = copy_group(grp, grp_p);
return ok;
}
static bool test_nwrap_getgrnam_r(const char *name,
struct group *grp_p)
{
struct group grp, *grpp;
char buffer[4096];
int ret;
DEBUG("Testing getgrnam_r: %s\n", name);
ret = getgrnam_r(name, &grp, buffer, sizeof(buffer), &grpp);
if (ret != 0) {
if (ret != ENOENT) {
DEBUG("got %d return code\n", ret);
}
assert_true(ret);
}
assert_ptr_equal(&grp, grpp);
print_group(&grp);
if (grp_p) {
copy_group(&grp, grp_p);
}
return true;
}
static bool test_nwrap_getgrgid(gid_t gid,
struct group *grp_p)
{
struct group *grp = NULL;
bool ok;
DEBUG("Testing getgrgid: %lu\n", (unsigned long)gid);
grp = getgrgid(gid);
if (grp == NULL) {
return false;
}
print_group(grp);
if (grp_p == NULL) {
return true;
}
ok = copy_group(grp, grp_p);
return ok;
}
static bool test_nwrap_getgrgid_r(gid_t gid,
struct group *grp_p)
{
struct group grp, *grpp;
char buffer[4096];
int ret;
DEBUG("Testing getgrgid_r: %lu\n", (unsigned long)gid);
ret = getgrgid_r(gid, &grp, buffer, sizeof(buffer), &grpp);
if (ret != 0) {
if (ret != ENOENT) {
DEBUG("got %d return code\n", ret);
}
assert_true(ret);
}
assert_ptr_equal(&grp, grpp);
print_group(&grp);
if (grp_p) {
copy_group(&grp, grp_p);
}
return true;
}
static bool test_nwrap_enum_passwd(struct passwd **pwd_array_p,
size_t *num_pwd_p)
{
struct passwd *pwd;
struct passwd *pwd_array = NULL;
size_t num_pwd = 0;
DEBUG("Testing setpwent\n");
setpwent();
while ((pwd = getpwent()) != NULL) {
DEBUG("Testing getpwent\n");
print_passwd(pwd);
if (pwd_array_p && num_pwd_p) {
pwd_array = realloc(pwd_array, sizeof(struct passwd) * (num_pwd + 1));
assert_non_null(pwd_array);
copy_passwd(pwd, &pwd_array[num_pwd]);
num_pwd++;
}
}
DEBUG("Testing endpwent\n");
endpwent();
if (pwd_array_p) {
*pwd_array_p = pwd_array;
}
if (num_pwd_p) {
*num_pwd_p = num_pwd;
}
return true;
}
static bool test_nwrap_enum_r_passwd(struct passwd **pwd_array_p,
size_t *num_pwd_p)
{
struct passwd *pwd_array = NULL;
size_t num_pwd = 0;
/* Skip these tests if the platform does not provide getpwent_r() */
#ifdef HAVE_GETPWENT_R
struct passwd pwd, *pwdp;
char buffer[4096];
int ret;
DEBUG("Testing setpwent\n");
setpwent();
while (1) {
DEBUG("Testing getpwent_r\n");
#ifdef HAVE_SOLARIS_GETPWENT_R
pwdp = getpwent_r(&pwd, buffer, sizeof(buffer));
if (pwdp == NULL) {
break;
}
#else /* HAVE_SOLARIS_GETPWENT_R */
ret = getpwent_r(&pwd, buffer, sizeof(buffer), &pwdp);
if (ret != 0) {
if (ret != ENOENT) {
DEBUG("got %d return code\n", ret);
}
break;
}
#endif /* HAVE_SOLARIS_GETPWENT_R */
print_passwd(&pwd);
if (pwd_array_p && num_pwd_p) {
pwd_array = realloc(pwd_array, sizeof(struct passwd) * (num_pwd + 1));
assert_non_null(pwd_array);
copy_passwd(&pwd, &pwd_array[num_pwd]);
num_pwd++;
}
}
DEBUG("Testing endpwent\n");
endpwent();
#endif /* HAVE_GETPWENT_R */
if (pwd_array_p) {
*pwd_array_p = pwd_array;
}
if (num_pwd_p) {
*num_pwd_p = num_pwd;
}
return true;
}
static bool test_nwrap_passwd(void)
{
struct passwd *pwd, pwd1, pwd2;
size_t i, num_pwd;
test_nwrap_enum_passwd(&pwd, &num_pwd);
for (i=0; i < num_pwd; i++) {
test_nwrap_getpwnam(pwd[i].pw_name, &pwd1);
assert_passwd_equal(&pwd[i], &pwd1);
test_nwrap_getpwuid(pwd[i].pw_uid, &pwd2);
assert_passwd_equal(&pwd[i], &pwd2);
assert_passwd_equal(&pwd1, &pwd2);
free_passwd(&pwd1);
free_passwd(&pwd2);
}
free_passwds(pwd, num_pwd);
return true;
}
static void test_nwrap_passwd_r(void)
{
struct passwd *pwd, pwd1, pwd2;
size_t i, num_pwd;
test_nwrap_enum_r_passwd(&pwd, &num_pwd);
for (i=0; i < num_pwd; i++) {
test_nwrap_getpwnam_r(pwd[i].pw_name, &pwd1);
assert_passwd_equal(&pwd[i], &pwd1);
test_nwrap_getpwuid_r(pwd[i].pw_uid, &pwd2);
assert_passwd_equal(&pwd[i], &pwd2);
assert_passwd_equal(&pwd1, &pwd2);
free_passwd(&pwd1);
free_passwd(&pwd2);
}
free_passwds(pwd, num_pwd);
}
static bool test_nwrap_passwd_r_cross(void)
{
struct passwd *pwd, pwd1, pwd2, pwd3, pwd4;
size_t i, num_pwd;
test_nwrap_enum_r_passwd(&pwd, &num_pwd);
for (i=0; i < num_pwd; i++) {
test_nwrap_getpwnam_r(pwd[i].pw_name, &pwd1);
assert_passwd_equal(&pwd[i], &pwd1);
test_nwrap_getpwuid_r(pwd[i].pw_uid, &pwd2);
assert_passwd_equal(&pwd[i], &pwd2);
assert_passwd_equal(&pwd1, &pwd2);
test_nwrap_getpwnam(pwd[i].pw_name, &pwd3);
assert_passwd_equal(&pwd[i], &pwd3);
test_nwrap_getpwuid(pwd[i].pw_uid, &pwd4);
assert_passwd_equal(&pwd[i], &pwd4);
assert_passwd_equal(&pwd3, &pwd4);
free_passwd(&pwd1);
free_passwd(&pwd2);
free_passwd(&pwd3);
free_passwd(&pwd4);
}
free_passwds(pwd, num_pwd);
return true;
}
static bool test_nwrap_enum_group(struct group **grp_array_p,
size_t *num_grp_p)
{
struct group *grp;
struct group *grp_array = NULL;
size_t num_grp = 0;
DEBUG("Testing setgrent\n");
setgrent();
while ((grp = getgrent()) != NULL) {
DEBUG("Testing getgrent\n");
print_group(grp);
if (grp_array_p && num_grp_p) {
grp_array = realloc(grp_array, sizeof(struct group) * (num_grp + 1));
assert_non_null(grp_array);
copy_group(grp, &grp_array[num_grp]);
num_grp++;
}
}
DEBUG("Testing endgrent\n");
endgrent();
if (grp_array_p) {
*grp_array_p = grp_array;
}
if (num_grp_p) {
*num_grp_p = num_grp;
}
return true;
}
static bool test_nwrap_enum_r_group(struct group **grp_array_p,
size_t *num_grp_p)
{
struct group *grp_array = NULL;
size_t num_grp = 0;
/* Skip these tests if the platform does not provide getgrent_r() */
#ifdef HAVE_GETGRENT_R
struct group grp, *grpp;
char buffer[4096];
int ret;
DEBUG("Testing setgrent\n");
setgrent();
while (1) {
DEBUG("Testing getgrent_r\n");
#ifdef HAVE_SOLARIS_GETGRENT_R
grpp = getgrent_r(&grp, buffer, sizeof(buffer));
if (grpp == NULL) {
break;
}
#else /* HAVE_SOLARIS_GETGRENT_R */
ret = getgrent_r(&grp, buffer, sizeof(buffer), &grpp);
if (ret != 0) {
if (ret != ENOENT) {
DEBUG("got %d return code\n", ret);
}
break;
}
#endif /* HAVE_SOLARIS_GETGRENT_R */
print_group(&grp);
if (grp_array_p && num_grp_p) {
grp_array = realloc(grp_array, sizeof(struct group) * (num_grp + 1));
assert_non_null(grp_array);
copy_group(&grp, &grp_array[num_grp]);
num_grp++;
}
}
DEBUG("Testing endgrent\n");
endgrent();
#endif /* HAVE_GETGRENT_R */
if (grp_array_p) {
*grp_array_p = grp_array;
}
if (num_grp_p) {
*num_grp_p = num_grp;
}
return true;
}
static bool test_nwrap_group(void)
{
struct group *grp, grp1, grp2;
size_t i, num_grp;
test_nwrap_enum_group(&grp, &num_grp);
for (i=0; i < num_grp; i++) {
test_nwrap_getgrnam(grp[i].gr_name, &grp1);
assert_group_equal(&grp[i], &grp1);
test_nwrap_getgrgid(grp[i].gr_gid, &grp2);
assert_group_equal(&grp[i], &grp2);
assert_group_equal(&grp1, &grp2);
free_group(&grp1);
free_group(&grp2);
}
free_groups(grp, num_grp);
return true;
}
static bool test_nwrap_group_r(void)
{
struct group *grp, grp1, grp2;
size_t i, num_grp;
test_nwrap_enum_r_group(&grp, &num_grp);
for (i=0; i < num_grp; i++) {
test_nwrap_getgrnam_r(grp[i].gr_name, &grp1);
assert_group_equal(&grp[i], &grp1);
test_nwrap_getgrgid_r(grp[i].gr_gid, &grp2);
assert_group_equal(&grp[i], &grp2);
assert_group_equal(&grp1, &grp2);
free_group(&grp1);
free_group(&grp2);
}
free_groups(grp, num_grp);
return true;
}
static bool test_nwrap_group_r_cross(void)
{
struct group *grp, grp1, grp2, grp3, grp4;
size_t i, num_grp;
test_nwrap_enum_r_group(&grp, &num_grp);
for (i=0; i < num_grp; i++) {
test_nwrap_getgrnam_r(grp[i].gr_name, &grp1);
assert_group_equal(&grp[i], &grp1);
test_nwrap_getgrgid_r(grp[i].gr_gid, &grp2);
assert_group_equal(&grp[i], &grp2);
assert_group_equal(&grp1, &grp2);
test_nwrap_getgrnam(grp[i].gr_name, &grp3);
assert_group_equal(&grp[i], &grp3);
test_nwrap_getgrgid(grp[i].gr_gid, &grp4);
assert_group_equal(&grp[i], &grp4);
assert_group_equal(&grp3, &grp4);
free_group(&grp1);
free_group(&grp2);
free_group(&grp3);
free_group(&grp4);
}
free_groups(grp, num_grp);
return true;
}
#ifdef HAVE_GETGROUPLIST
static bool test_nwrap_getgrouplist(const char *user,
gid_t gid,
gid_t **gids_p,
int *num_gids_p)
{
int ret;
int num_groups = 0;
gid_t *groups = NULL;
DEBUG("Testing getgrouplist: %s\n", user);
ret = getgrouplist(user, gid, NULL, &num_groups);
if (ret == -1 || num_groups != 0) {
groups = malloc(sizeof(gid_t) * num_groups);
assert_non_null(groups);
ret = getgrouplist(user, gid, groups, &num_groups);
}
assert_false(ret == -1);
DEBUG("%s is member in %d groups\n", user, num_groups);
if (gids_p) {
*gids_p = groups;
}
if (num_gids_p) {
*num_gids_p = num_groups;
}
return true;
}
static bool test_nwrap_user_in_group(const struct passwd *pwd,
const struct group *grp)
{
int i;
for (i = 0; grp->gr_mem != NULL && grp->gr_mem[i] != NULL; i++) {
if (strcmp(grp->gr_mem[i], pwd->pw_name) == 0) {
return true;
}
}
return false;
}
static bool test_nwrap_membership_user(const struct passwd *pwd,
struct group *grp_array,
size_t num_grp)
{
int num_user_groups = 0;
size_t num_user_groups_from_enum = 0;
gid_t *user_groups = NULL;
size_t i;
int g;
bool primary_group_had_user_member = false;
test_nwrap_getgrouplist(pwd->pw_name,
pwd->pw_gid,
&user_groups,
&num_user_groups);
for (g=0; g < num_user_groups; g++) {
test_nwrap_getgrgid(user_groups[g], NULL);
}
free(user_groups);
for (i=0; i < num_grp; i++) {
struct group grp = grp_array[i];
if (test_nwrap_user_in_group(pwd, &grp)) {
struct group current_grp;
num_user_groups_from_enum++;
test_nwrap_getgrnam(grp.gr_name, ¤t_grp);
if (current_grp.gr_gid == pwd->pw_gid) {
DEBUG("primary group %s of user %s lists user as member\n",
current_grp.gr_name,
pwd->pw_name);
primary_group_had_user_member = true;
}
free_group(¤t_grp);
continue;
}
}
if (!primary_group_had_user_member) {
num_user_groups_from_enum++;
}
assert_int_equal(num_user_groups, num_user_groups_from_enum);
return true;
}
static void test_nwrap_membership(void **state)
{
const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
const char *old_group = getenv("NSS_WRAPPER_GROUP");
struct passwd *pwd;
size_t num_pwd;
struct group *grp;
size_t num_grp;
size_t i;
(void) state; /* unused */
if (!old_pwd || !old_group) {
DEBUG("ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
return;
}
test_nwrap_enum_passwd(&pwd, &num_pwd);
test_nwrap_enum_group(&grp, &num_grp);
for (i=0; i < num_pwd; i++) {
test_nwrap_membership_user(&pwd[i], grp, num_grp);
}
free_passwds(pwd, num_pwd);
free_groups(grp, num_grp);
}
#endif /* HAVE_GETGROUPLIST */
static void test_nwrap_enumeration(void **state)
{
const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
const char *old_group = getenv("NSS_WRAPPER_GROUP");
(void) state; /* unused */
if (!old_pwd || !old_group) {
DEBUG("ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
return;
}
test_nwrap_passwd();
test_nwrap_group();
}
static void test_nwrap_reentrant_enumeration(void **state)
{
const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
const char *old_group = getenv("NSS_WRAPPER_GROUP");
(void) state; /* unused */
if (!old_pwd || !old_group) {
DEBUG("ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
return;
}
DEBUG("Testing re-entrant calls\n");
test_nwrap_passwd_r();
test_nwrap_group_r();
}
static void test_nwrap_reentrant_enumeration_crosschecks(void **state)
{
const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
const char *old_group = getenv("NSS_WRAPPER_GROUP");
(void) state; /* unused */
if (!old_pwd || !old_group) {
DEBUG("ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
return;
}
DEBUG("Testing re-entrant calls with cross checks\n");
test_nwrap_passwd_r_cross();
test_nwrap_group_r_cross();
}
static bool test_nwrap_passwd_duplicates(void)
{
struct passwd *pwd;
size_t d, i, num_pwd;
int duplicates = 0;
test_nwrap_enum_passwd(&pwd, &num_pwd);
for (i=0; i < num_pwd; i++) {
const char *current_name = pwd[i].pw_name;
for (d=0; d < num_pwd; d++) {
const char *dup_name = pwd[d].pw_name;
if (d == i) {
continue;
}
if (strcmp(current_name, dup_name) != 0) {
continue;
}
DEBUG("found duplicate names:");
print_passwd(&pwd[d]);
print_passwd(&pwd[i]);
duplicates++;
}
}
free_passwds(pwd, num_pwd);
assert_false(duplicates);
return true;
}
static bool test_nwrap_group_duplicates(void)
{
struct group *grp;
size_t d, i, num_grp;
int duplicates = 0;
test_nwrap_enum_group(&grp, &num_grp);
for (i=0; i < num_grp; i++) {
const char *current_name = grp[i].gr_name;
for (d=0; d < num_grp; d++) {
const char *dup_name = grp[d].gr_name;
if (d == i) {
continue;
}
if (strcmp(current_name, dup_name) != 0) {
continue;
}
DEBUG("found duplicate names:");
print_group(&grp[d]);
print_group(&grp[i]);
duplicates++;
}
}
free_groups(grp, num_grp);
assert_false(duplicates);
return true;
}
static void test_nwrap_duplicates(void **state)
{
const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
const char *old_group = getenv("NSS_WRAPPER_GROUP");
(void) state; /* unused */
if (!old_pwd || !old_group) {
DEBUG("ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
return;
}
test_nwrap_passwd_duplicates();
test_nwrap_group_duplicates();
}
int main(void) {
int rc;
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_nwrap_enumeration),
cmocka_unit_test(test_nwrap_reentrant_enumeration),
cmocka_unit_test(test_nwrap_reentrant_enumeration_crosschecks),
#ifdef HAVE_GETGROUPLIST
cmocka_unit_test(test_nwrap_membership),
#endif
cmocka_unit_test(test_nwrap_duplicates),
};
rc = cmocka_run_group_tests(tests, NULL, NULL);
return rc;
}