From bcecad33d5c01014fd25da0fc8ca93be19fadee7 Mon Sep 17 00:00:00 2001 From: Thomas Veerman Date: Sun, 20 Dec 2009 21:31:03 +0000 Subject: [PATCH] Fix compilation errors caused by more files not added in previous commit --- lib/other/initgroups.c | 34 ++++ lib/syscall/setgroups.s | 7 + test/test46.c | 355 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 396 insertions(+) create mode 100644 lib/other/initgroups.c create mode 100644 lib/syscall/setgroups.s create mode 100644 test/test46.c diff --git a/lib/other/initgroups.c b/lib/other/initgroups.c new file mode 100644 index 000000000..86a656303 --- /dev/null +++ b/lib/other/initgroups.c @@ -0,0 +1,34 @@ +/* +initgroups.c +*/ +#include +#include +#include +#include + + +int initgroups(const char *name, gid_t basegid) +{ + struct group *gr; + int r, found = 0, n = 0; + gid_t groups[NGROUPS]; + + if((r = setgid(basegid)) < 0) + return(r); + + setgrent(); + while ((gr = getgrent()) != NULL && (n + 1) <= NGROUPS) { + char **mem; + for(mem = gr->gr_mem; mem && *mem; mem++) { + if(!strcmp(name, *mem)) { + groups[n++] = gr->gr_gid; + break; + } + } + } + + endgrent(); + + return setgroups(n, groups); +} + diff --git a/lib/syscall/setgroups.s b/lib/syscall/setgroups.s new file mode 100644 index 000000000..3cf8b500b --- /dev/null +++ b/lib/syscall/setgroups.s @@ -0,0 +1,7 @@ +.sect .text +.extern __setgroups +.define _setgroups +.align 2 + +_setgroups: + jmp __setgroups diff --git a/test/test46.c b/test/test46.c new file mode 100644 index 000000000..7d0d0ac16 --- /dev/null +++ b/test/test46.c @@ -0,0 +1,355 @@ +/* Test46.c + * + * Test getgroups(...) and setgroups system calls + * + * Please note that getgroups is POSIX defined, but setgroups is not. Errors + * related to setgroups are thus not POSIX conformance issues. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +_PROTOTYPE( void api_test, (void) ); +_PROTOTYPE( void e, (int error_no) ); +_PROTOTYPE( void group_test, (void) ); +_PROTOTYPE( void limit_test, (void) ); +_PROTOTYPE( void group_test_1, (void) ); +_PROTOTYPE( void group_test_2, (void) ); +_PROTOTYPE( void group_test_3, (void) ); +_PROTOTYPE( void group_test_4, (void) ); +_PROTOTYPE( void group_test_5, (void) ); +_PROTOTYPE( int dotest, (void (*testfunc)(void)) ); + +int subtest = -1, errorct = 0; +#define ERROR_MAX 5 +#define IMAGINARY_GID 100 +#define IMAGINARY_GID_STR "100" +#define IMAGINARY_UID 101 +#define IMAGINARY_UID_STR "101" +#define SET_CREDENTIALS do { \ + setgid((IMAGINARY_GID) + 1 ); \ + setuid(IMAGINARY_UID); \ + } while(0) + +int main(int argc, char *argv[]) +{ + int superuser; + printf("Test 46 "); + fflush(stdout); + + superuser = (geteuid() == 0); + + if(!superuser) { + if(!(setuid(0) || seteuid(0))) { + printf("Test 46 has to be run as root; test aborted\n"); + exit(1); + } + } + + limit_test(); /* Perform some tests on POSIX limits */ + api_test(); /* Perform some very basic API tests */ + group_test(); /* Perform some tests that mimic actual use */ + + if(errorct > 0) { + printf("%d error(s)\n", errorct); + return(errorct); + } + + printf("ok\n"); + return(0); +} + +void limit_test() { +/* According to POSIX 2008 a process can have up to NGROUPS_MAX simultaneous + * supplementary group IDs. The minimum acceptable value is _POSIX_NGROUPS_MAX. + * In turn, _POSIX_NGROUPS_MAX is defined as 8. */ + + subtest = 1; + if (_POSIX_NGROUPS_MAX < 8) e(1); + if (NGROUPS_MAX < _POSIX_NGROUPS_MAX) e(2); +} + +void api_test() { +/* int getgroups( int gidsetsize, gid_t grouplist[]); + * int setgroups( int size_t size, const gid_t grouplist[]); + */ +/* The getgroups() function shall fill in the array grouplist with the current + * supplementary group IDs of the calling process. It is implementation- + * defined whether getgroups() also returns the effective group ID in the + * grouplist array. + * The gidsetsize argument specifies the number of elements in the array + * grouplist. The actual number of group IDs stored in the array shall be + * returned. The values of array entries with indices greater than or equal to + * the value returned are undefined. + * If gidsetsize is 0, getgroups shall return the number of group IDs that it + * would otherwise return without modifying the array pointed to by grouplist. + * + * setgroups() sets the supplementary group IDs for the calling process. The + * size argument specifies the number of supplementary group IDs in the buffer + * pointed to by grouplist. setgroups() is a privileged operation. + */ + + /* Minix does not return the effective group ID with the supplementary groups. + * Use getegid() to get that value. In order to call setgroups, a process + * must have super user privileges. + */ + + int r, i, nogroups; + gid_t *grouplist, *grouplist2; + long ngroups_max; + + subtest = 2; + + /* Ask the system how many groups we're allowed to set */ + ngroups_max = sysconf(_SC_NGROUPS_MAX); + grouplist = malloc(ngroups_max *sizeof(gid_t)); + grouplist2 = malloc(ngroups_max *sizeof(gid_t)); + + /* Let's invent some imaginary groups */ +#define START_GID 20001 + for (i = START_GID; i < START_GID + ngroups_max; i++) + grouplist[i - START_GID] = i; + + /* Normal usage */ + if (setgroups(ngroups_max, grouplist) != 0) e(1); + + /* Try one less than max supported groups */ + if (setgroups(ngroups_max - 1, grouplist) != 0) e(2); + + /* Try just one group */ + if (setgroups(1, grouplist) != 0) e(3); + + /* Unset all supplementary groups */ + if (setgroups(0, grouplist) != 0) e(4); + + /* Should not be allowed to use a negative set size */ + if (setgroups(-1, grouplist) == 0) e(5); + else if(errno != EINVAL) e(6); /* error must be EINVAL */ + + /* Should not be allowed to set more groups than supported by the system */ + if (setgroups(ngroups_max + 1, grouplist) == 0) e(7); + else if(errno != EINVAL) e(8); /* error must be EINVAL */ + + /* Should not be allowed to provide an invalid grouplist address */ + if (setgroups(ngroups_max, NULL) == 0) e(9); + else if(errno != EFAULT) e(10); /* error must be EFAULT */ + + /* The last time we called setgroups with proper parameters, we effectively + * cleared the list. Verify that with getgroups(). */ + if (getgroups(ngroups_max, grouplist2) != 0) e(11); + + /* Repopulate grouplist with values and read them back */ + if (setgroups(ngroups_max, grouplist) != 0) e(12); + if (getgroups(0, grouplist2) != ngroups_max) e(13); + if (getgroups(ngroups_max, grouplist2) != ngroups_max) e(14); + for (i = 0; i < ngroups_max; i++) { + if(grouplist[i] != grouplist2[i]) { + e(15); + break; /* One error message should be enough here */ + } + } + + /* Should not be able to read less groups than are actually stored. */ + if (getgroups(ngroups_max - 1, grouplist2) != -1) e(16); + + /* Repopulate grouplist with only half the groups and read them back */ + memset(grouplist2, 0, ngroups_max * sizeof(gid_t)); /* Clear array */ +#define HALF_LIST_SIZE ngroups_max / 2 + if (setgroups(HALF_LIST_SIZE, grouplist) != 0) e(17); + if (getgroups(0, grouplist2) != HALF_LIST_SIZE) e(18); + if (getgroups(HALF_LIST_SIZE, grouplist2) != HALF_LIST_SIZE) e(19); + for (i = 0; i < HALF_LIST_SIZE; i++) { + if(grouplist[i] != grouplist2[i]) { + e(20); + break; /* Also here one message ought to be enough */ + } + } + + /* Try to read more groups than we have set */ + memset(grouplist2, 0, ngroups_max * sizeof(gid_t)); /* Clear array */ + if (getgroups(ngroups_max, grouplist2) != HALF_LIST_SIZE) e(21); + for (i = 0; i < HALF_LIST_SIZE; i++) { + /* Anything above indices 'HALF_LIST_SIZE' is undefined */ + if(grouplist[i] != grouplist2[i]) { + e(22); + break; + } + } + + free(grouplist); + free(grouplist2); +} + +void group_test() { +/* To test supplemental group support we're going to create a temporary + * directory that can only be accessed (x bit) by members of our imaginary + * group, read from (r bit) and written to (w bit). + * Then we're going to create a file in that directory that's only readable and + * writable by the owner, also readable, writable, and both (in that order) by + * the imaginary group, and readable, writable, and both by everyone else (2). + */ + + int r, i, round, test_result; + gid_t *grouplist; + long ngroups_max; +#define ROUNDS 8 + + subtest = 3; + + ngroups_max = sysconf(_SC_NGROUPS_MAX); + grouplist = malloc(ngroups_max *sizeof(gid_t)); + + /* Let's invent imaginary groups and user id */ + grouplist = malloc(ngroups_max * sizeof(gid_t)); + + /* Now loop a few tests while using different group set sizes */ + for(round = 0; round < ROUNDS; round++) { + grouplist[round] = IMAGINARY_GID; + for(i = 0; i < ngroups_max; i++) { + if(i == round) continue; + grouplist[i] = IMAGINARY_GID + i + ngroups_max; + } + setgroups(round+1, grouplist); + + system("rm -r DIR_046 > /dev/null 2>&1"); + system("mkdir DIR_046"); + system("chmod u=rwx,g=,o= DIR_046"); /* Only access for superuser */ + system("chgrp "IMAGINARY_GID_STR" DIR_046"); /* Make imaginary group + * owner */ + + /* Test group access on directories */ + if(dotest(group_test_1) != 0) e(1); + system("chmod g+r DIR_046"); /* Allow group read access */ + if(dotest(group_test_1) == 0) e(2); + + system("chmod g= DIR_046"); + if(dotest(group_test_2) != 0) e(3); + system("chmod g+x DIR_046"); /* Allow 'search' (i.e., inode data) + * access */ + if(dotest(group_test_2) == 0) e(4); + + if(dotest(group_test_3) != 0) e(5); + system("chmod g+w DIR_046"); /* Allow group write access */ + if(dotest(group_test_3) == 0) e(6); + + system("chmod g-wx DIR_046"); /* Remove write and 'search' permission */ + if(dotest(group_test_4) != 0) e(7); + system("chmod g+w DIR_046"); /* Add write permission */ + if(dotest(group_test_4) != 0) e(8); + system("chmod g+x DIR_046"); /* Add 'search' permission */ + if(dotest(group_test_4) == 0) e(9); + + /* Subdirectories */ + system("mkdir -p DIR_046/sub"); + system("chmod u=rwx,g=,o= DIR_046"); + system("chmod u=rwx,g=,o= DIR_046/sub"); + system("chgrp "IMAGINARY_GID_STR" DIR_046/sub"); + + if(dotest(group_test_1) != 0) e(10); + if(dotest(group_test_5) != 0) e(11); + + system("chmod g+r DIR_046"); + if(dotest(group_test_1) == 0) e(12); + if(dotest(group_test_5) != 0) e(13); + + system("chmod g= DIR_046"); + if(dotest(group_test_5) != 0) e(14); + system("chmod g+r DIR_046/sub"); + if(dotest(group_test_5) != 0) e(15); /* We need search permission for + * sub directory DIR_046 to be + * able to read the contents of + * DIR_046/sub */ + system("chmod g+x DIR_046"); + if(dotest(group_test_1) != 0) e(16); + if(dotest(group_test_5) == 0) e(17); + system("chmod g+r DIR_046"); + if(dotest(group_test_5) == 0) e(18); + } + system("rm -r DIR_046"); + free(grouplist); +} + +int dotest( void (*func)(void) ) { + int test_result; + + if(fork() == 0) (*func)(); + else wait(&test_result); + + return(test_result); +} + +void group_test_1() { +/* Test x bit for group access. Exit value is 1 when we were able to read from + * the directory and 0 otherwise. */ + DIR *dirp = NULL; + + SET_CREDENTIALS; + + dirp = opendir("DIR_046"); + exit(dirp != NULL); /* If not NULL, we were able to access it */ +} + +void group_test_2() { +/* Test x bit for group access. Exit value is 1 when we were able to access + * inode data of the directory and 0 otherwise. */ + struct stat buf; + int res; + + SET_CREDENTIALS; + + res = stat("DIR_046/.", &buf); + exit(res == 0); +} + +void group_test_3() { +/* Test wx bits for group access. Exit value is 1 when we were able to write to + * the directory and 0 otherwise. */ + int fd; + + SET_CREDENTIALS; + + fd = open("DIR_046/writetest", O_WRONLY|O_CREAT); + + exit(fd != -1); +} + +void group_test_4() { +/* Test w bit for group access. Exit value is 1 when we were able to rename a + * the directory and 0 otherwise. */ + int res; + + SET_CREDENTIALS; + + res = rename("DIR_046/writetest", "DIR_046/renametest"); + + exit(res == 0); +} + +void group_test_5() { +/* Test x bit for group access. Exit value is 1 when we were able to read from + * the directory and 0 otherwise. */ + DIR *dirp = NULL; + + SET_CREDENTIALS; + + dirp = opendir("DIR_046/sub"); + exit(dirp != NULL); /* If not NULL, we were able to access it */ +} + +void e(int error_no) { + printf("Subtest %d, error %d\n", subtest, error_no); + + if (errorct++ > ERROR_MAX) { + printf("Too many errors, test aborted\n"); + exit(1); + } +} + -- 2.44.0