Cover V05, I09
Article
Figure 1
Figure 2
Figure 3
Figure 4
Listing 1
Listing 2
Listing 3
Sidebar 1

sep96.tar


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 */