Listing 1: The setdev.c program
/*
* setdev program, used to 'set' yourself to a development area
* this is done by setting your current group id to the special
* development area group id, and then changing your default directory
* to the root of the development area.
*
* What actually happens is that a subshell is started with the proper
* user and group id.
*
* Leaving the development area is simple done by terminating this subshell.
*
* The /etc/setdevd control file has the following layout :
*
* areaname:arearoot:user1<,user2><,user3>
*
* Author :
* Arthur Donkers
* Le Reseau netwerksystemen BV
* Burg. F. v. Ankenweg 5
* NL-9991 AM Middelstum
* The Netherlands
*
* This is an experimental program, use at your own risk
*/
#include <stdio.h>
#include <string.h>
#include <grp.h>
#include <pwd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define CONTROL "/etc/setdevd"
/*
* Globals
*/
/* The id of the calling user */
uid_t caller;
/* Id of user we should run as (temporarily) */
/* Default is root */
uid_t runas = 0;
/* Area name */
char area[255];
int arealen;
/*
* Check areaname and if user may setdev to that. If found, return
* rootdir of development area
*/
char *check( char *line, char *user )
{
char *p;
char *users;
char *rootdir;
if( line[strlen( line )-1] == '\n' ) {
line[strlen( line )-1] = '\0';
}
/* Get the areaname from the line we just read */
if( (p = strchr( line, ':' )) != NULL ) {
*p++ = '\0';
if( strncmp( area, line, arealen ) == 0 ) {
/* We have found the area, check user names */
rootdir = p;
if( (p = strchr( p, ':' )) != NULL ) {
*p++ = '\0';
/* p now points to the userlist */
users = p;
if( ! *p ) {
/* userlist is empty, return immediately */
return NULL;
}
while( users ) {
if( (p = strchr( users, ',' )) != NULL ) {
*p++ = '\0';
}
if( strcmp( user, users ) == 0 ) {
/* We matched the user, OK */
return rootdir;
}
users = p;
}
}
}
}
return NULL;
} /* check */
/*
* Entry point
*
* program has one parameter : the name of the development area
*
*/
main( int argc, char **argv )
{
struct stat fs;
FILE *fd;
char line[255];
char group[32];
struct passwd *pw;
struct group *gr;
char *rootdir;
/* We must at least have the name of a program to run */
if( argc != 2 ) {
fprintf( stderr, "Usage : setdev <areaname>\n" );
exit( 0 );
}
/* First argument */
argc--;
argv++;
/* Save areaname for later */
strcpy( area, *argv );
if( (arealen = strlen( area )) == 0 ) {
fprintf( stderr, "Somehow the area name is empty\n" );
exit( -1 );
}
/* Get real users passwd entry */
caller = getuid( );
if( (pw = getpwuid( caller ) ) == NULL ) {
fprintf( stderr, "Cannot get passwd information for user %d\n", caller );
exit( -1 );
}
/* Open the file setdevd */
if( (fd = fopen( CONTROL, "r" ) ) == NULL ) {
fprintf( stderr, "Cannot open control file %s\n", CONTROL );
exit( -1 );
}
/* Check the user and area with control file */
while( fgets( line, sizeof(line), fd ) ) {
if( (rootdir = check( line, pw->pw_name )) != NULL ) {
break;
}
}
/* Close setdevd file */
fclose( fd );
if( !rootdir ) {
/* User is not allowed to setdef to the development area */
fprintf( stderr, "User %s is not allowed access to area %s\n",
pw->pw_name, area );
exit( -1 );
}
/* Build the groupname */
strcpy( group, area );
strcat( group, "grp" );
/* Get group id based on the name */
if( (gr = getgrnam( group )) == NULL ) {
fprintf( stderr, "Cannot find group %s\n", group );
exit( -1 );
}
/* We have to change to root first */
if( setuid( geteuid( ) ) ) {
fprintf( stderr, "Cannot activate root priv\n" );
exit( -1 );
}
/* Set the group id */
if( setgid( gr->gr_gid ) < 0 ) {
fprintf( stderr, "Cannot change groupid\n" );
setuid( caller );
exit( -1 );
}
/* Now change back to the user we should run as */
if( setuid( caller ) ) {
fprintf( stderr, "Cannot restore priv\n" );
exit( -1 );
}
if( chdir( rootdir ) < 0 ) {
fprintf( stderr, "Cannot change to rootdir %s\n", rootdir );
exit( -1 );
}
/* Execute the program */
execl( "/usr/local/bin/bash", "sh", NULL );
/* NOTREACHED */
exit( 0 );
}
/* End of File */
|