Orphaned Response
egray at fthood.UUCP
egray at fthood.UUCP
Sat Oct 21 06:52:00 AEST 1989
Below is a library of routines for working arround the set-user/group-id
problems...
Emmet P. Gray US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray Attn: AFZF-DE-ENV
fthood!egray at uxc.cso.uiuc.edu Directorate of Engineering & Housing
Environmental Management Office
Fort Hood, TX 76544-5057
-----------------------------------------------------------------------------
/*
* This test program demonstrates a problem with v7-derived Unix systems
* where you can't flip-flop back and forth between the real and effective
* UID/GID in a set-user/group-id program.
*
* functions such as link() and unlink() are easy to fix with a fork()
* because they don't return any resources from the child process.
* However for fopen() and open(), this can't be done quite so easily,
* you essentially ignore the set-user/group-id priviledges, and open
* the file if your real id's would allow it.
*
* This file contains:
* uid_fopen(), uid_open(), uid_link(), and uid_unlink()
*/
#define SETUID_BROKE
#define DENIED 0
#define WRITE_OK 1
#define OK_BUT_EXISTS 2
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
main()
{
FILE *fp, *uid_fopen();
char buf[80];
printf("uid=%d, gid=%d, euid=%d, egid=%d\n", getuid(), getgid(), geteuid(), getegid());
if ((fp = uid_fopen("testfile", "r")) == NULL)
perror("uid_fopen");
if (fread(buf, sizeof(char), 80, fp) < 0)
perror("fread");
printf("buf=%s", buf);
if (fclose(fp) < 0)
perror("fclose");
printf("uid=%d, gid=%d, euid=%d, egid=%d\n", getuid(), getgid(), geteuid(), getegid());
exit(0);
}
/*
* Check write permission with the real UID and GID. Returns a 0 on
* permission denied, 1 on OK, and 2 on OK-but the file already exists.
*/
int
can_write(file)
char *file;
{
char *p, path[256], *strcpy(), *strrchr();
strcpy(path, file);
/* dissect the path component */
if (p = strrchr(path, '/'))
*p = '\0';
else
strcpy(path, ".");
/* if it already exists */
if (!access(file, 0)) {
if (!access(file, 2))
return(OK_BUT_EXISTS);
return(DENIED);
}
/* if path is writable */
if (!access(path, 2))
return(WRITE_OK);
return(DENIED);
}
/*
* Open a file if (and only if) your real UID/GID would allow it.
*/
FILE *
uid_fopen(file, mode)
char *file, *mode;
{
FILE *fp;
#ifdef SETUID_BROKE
char flag;
/* the sum of the two characters */
flag = *mode + *(mode+1);
switch (flag) {
case 'r': /* read permission */
if (access(file, 4))
fp = (FILE *) NULL;
else
fp = fopen(file, mode);
break;
case 'r' + '+': /* read & write */
if (access(file, 4) || access(file, 2))
fp = (FILE *) NULL;
else
fp = fopen(file, mode);
break;
case 'w':
case 'a': /* write & create */
switch(can_write(file)) {
case DENIED:
fp = (FILE *) NULL;
break;
case OK_BUT_EXISTS:
fp = fopen(file, mode);
break;
case WRITE_OK:
fp = fopen(file, mode);
/* fix the owner */
chown(file, getuid(), getgid());
break;
}
break;
case 'w' + '+':
case 'a' + '+': /* read & write & create */
switch(can_write(file)) {
case DENIED:
fp = (FILE *) NULL;
break;
case OK_BUT_EXISTS:
if (access(file, 4))
fp = (FILE *) NULL;
else
fp = fopen(file, mode);
break;
case WRITE_OK:
fp = fopen(file, mode);
/* fix the owner */
chown(file, getuid(), getgid());
break;
}
break;
}
#else /* SETUID_BROKE */
int euid, egid;
euid = geteuid();
egid = getegid();
/* abdicate the throne */
setuid(getuid());
setgid(getgid());
fp = fopen(file, mode);
/* put things back */
setuid(euid);
setgid(egid);
#endif /* SETUID_BROKE */
return(fp);
}
/*
* Create a link with real UID/GID.
*/
int
uid_link(path1, path2)
char *path1, *path2;
{
int ret, status, euid, egid;
void _exit();
#ifdef SETUID_BROKE
switch(fork()) {
case 0:
setuid(getuid());
setgid(getgid());
_exit(link(path1, path2));
case -1:
fprintf(stderr, "uid_link: Can't fork\n");
return(-1);
default:
if (wait(&status) == -1) {
fprintf(stderr, "uid_link: wait failed\n");
return(-1);
}
ret = status >> 8;
}
#else /* SETUID_BROKE */
euid = geteuid();
egid = getegid();
setuid(getuid());
setgid(getgid());
ret = link(path1, path2);
setuid(euid);
setgid(egid);
#endif /* SETUID_BROKE */
return(ret);
}
/*
* Unlink a file with real UID/GID.
*/
int
uid_unlink(path)
char *path;
{
int ret, status, euid, egid;
void _exit();
#ifdef SETUID_BROKE
switch(fork()) {
case 0:
setuid(getuid());
setgid(getgid());
_exit(unlink(path));
case -1:
fprintf(stderr, "uid_unlink: Can't fork\n");
return(-1);
default:
if (wait(&status) == -1) {
fprintf(stderr, "uid_unlink: wait failed\n");
return(-1);
}
ret = status >> 8;
}
#else /* SETUID_BROKE */
euid = geteuid();
egid = getegid();
setuid(getuid());
setgid(getgid());
ret = unlink(path);
setuid(euid);
setgid(egid);
#endif /* SETUID_BROKE */
return(ret);
}
More information about the Comp.unix.questions
mailing list