#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define ROOT_UID (uid_t)0
#define WHEEL_GID (gid_t)0
#define TEST_UID_ONE (uid_t)500
#define TEST_GID_ONE (gid_t)500
#define TEST_UID_TWO (uid_t)501
#define TEST_GID_TWO (gid_t)501
struct file_description {
char *fd_name;
uid_t fd_owner;
gid_t fd_group;
mode_t fd_mode;
};
static struct file_description fd_list[] = {
{"test1", ROOT_UID, WHEEL_GID, 0400},
{"test2", TEST_UID_ONE, WHEEL_GID,0400},
{"test3", TEST_UID_TWO, WHEEL_GID, 0400},
{"test4", ROOT_UID, WHEEL_GID, 0040},
{"test5", ROOT_UID, TEST_GID_ONE, 0040},
{"test6", ROOT_UID, TEST_GID_TWO, 0040}};
static int fd_list_count = sizeof(fd_list) /
sizeof(struct file_description);
int
setup(void)
{
int i, error;
for (i = 0; i < fd_list_count; i++) {
error = open(fd_list[i].fd_name, O_CREAT | O_EXCL, fd_list[i].fd_mode);
if (error == -1) {
perror("open");
return (error);
}
close(error);
error = chown(fd_list[i].fd_name, fd_list[i].fd_owner,
fd_list[i].fd_group);
if (error) {
perror("chown");
return (error);
}
}
return (0);
}
int
restoreprivilege(void)
{
int error;
error = setreuid(ROOT_UID, ROOT_UID);
if (error)
return (error);
error = setregid(WHEEL_GID, WHEEL_GID);
if (error)
return (error);
return (0);
}
int
reportprivilege(char *message)
{
uid_t euid, ruid, suid;
gid_t egid, rgid, sgid;
int error;
error = getresuid(&ruid, &euid, &suid);
if (error) {
perror("getresuid");
return (error);
}
error = getresgid(&rgid, &egid, &sgid);
if (error) {
perror("getresgid");
return (error);
}
if (message)
printf("%s: ", message);
printf("ruid: %d, euid: %d, suid: %d, ", ruid, euid, suid);
printf("rgid: %d, egid: %d, sgid: %d\n", rgid, egid, sgid);
return (0);
}
int
cleanup(void)
{
int i, error;
error = restoreprivilege();
if (error) {
perror("restoreprivilege");
return (error);
}
for (i = 0; i < fd_list_count; i++) {
error = unlink(fd_list[i].fd_name);
if (error)
return (error);
}
return (0);
}
int
main(int argc, char *argv[])
{
int error, errorseen;
if (geteuid() != 0) {
fprintf(stderr, "testaccess must run as root.\n");
exit (EXIT_FAILURE);
}
error = setup();
if (error) {
cleanup();
exit (EXIT_FAILURE);
}
error = setresuid(ROOT_UID, ROOT_UID, ROOT_UID);
if (error) {
perror("setresuid");
cleanup();
}
error = setgroups(0, NULL);
if (error) {
perror("setgroups");
cleanup();
}
error = setresgid(WHEEL_GID, WHEEL_GID, WHEEL_GID);
if (error) {
perror("setresgid");
cleanup();
}
error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
if (error) {
perror("setresuid.1");
cleanup();
exit (EXIT_FAILURE);
}
errorseen = 0;
error = access("test1", R_OK);
if (!error) {
fprintf(stderr, "saved uid used instead of real uid\n");
errorseen++;
}
#ifdef EACCESS_AVAILABLE
error = eaccess("test1", R_OK);
if (!error) {
fprintf(stderr, "saved uid used instead of effective uid\n");
errorseen++;
}
#endif
error = restoreprivilege();
if (error) {
perror("restoreprivilege");
cleanup();
exit (EXIT_FAILURE);
}
error = setresuid(TEST_UID_ONE, TEST_UID_TWO, ROOT_UID);
if (error) {
perror("setresid.2");
cleanup();
exit (EXIT_FAILURE);
}
error = access("test2", R_OK);
if (error) {
fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
errorseen++;
}
#ifdef EACCESS_AVAILABLE
error = eaccess("test3", R_OK);
if (error) {
fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
errorseen++;
}
#endif
error = access("test3", R_OK);
if (!error) {
fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
errorseen++;
}
#ifdef EACCESS_AVAILABLE
error = eaccess("test2", R_OK);
if (!error) {
fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
errorseen++;
}
#endif
error = restoreprivilege();
if (error) {
perror("restoreprivilege");
cleanup();
exit (EXIT_FAILURE);
}
error = setresgid(TEST_GID_ONE, TEST_GID_TWO, WHEEL_GID);
if (error) {
perror("setresgid.1");
cleanup();
exit (EXIT_FAILURE);
}
error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
if (error) {
perror("setresuid.3");
cleanup();
exit (EXIT_FAILURE);
}
error = access("test4", R_OK);
if (!error) {
fprintf(stderr, "saved gid used instead of real gid\n");
}
#ifdef EACCESS_AVAILABLE
error = eaccess("test4", R_OK);
if (!error) {
fprintf(stderr, "saved gid used instead of effective gid\n");
errorseen++;
}
#endif
error = access("test5", R_OK);
if (error) {
fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
errorseen++;
}
#ifdef EACCESS_AVAILABLE
error = eaccess("test6", R_OK);
if (error) {
fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
errorseen++;
}
#endif
error = access("test6", R_OK);
if (!error) {
fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
errorseen++;
}
#ifdef EACCESS_AVAILABLE
error = eaccess("test5", R_OK);
if (!error) {
fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
errorseen++;
}
#endif
fprintf(stderr, "%d errors seen.\n", errorseen);
error = cleanup();
if (error) {
perror("cleanup");
exit (EXIT_FAILURE);
}
exit (EXIT_SUCCESS);
}