@ -36,21 +36,22 @@ static int perm_set (struct passwd *, struct group *);
static int authenticate ( const char * ) ;
static struct passwd * user_to_passwd ( const char * ) ;
static struct group * group_to_grp ( const char * ) ;
//static int execvpe(const char *, char *const *, char *const *);
// FIXME: misc_conv is a separate library, should stick to plain PAM or make
// our own pam module
static struct pam_conv conv = { misc_conv , NULL } ;
extern char * * environ ;
int main ( int argc , char * argv [ ] )
{
// TODO: Add arguments
// FIXME: change the default program to execute SHELL
char * t_usr = " root " , * t_grp = NULL ;
struct passwd * t_pw ;
struct group * t_gr ;
int opt ;
int shellflag = 0 ;
while ( ( opt = getopt ( argc , argv , " A:u:g:C:s " ) ) ! = - 1 ) {
int opt , err ;
int shellflag = 0 , envflag = 0 ;
while ( ( opt = getopt ( argc , argv , " A:u:g:C:se " ) ) ! = - 1 ) {
switch ( opt ) {
case ' A ' :
printf ( " -A is not yet implemented \n " ) ;
@ -69,6 +70,9 @@ int main (int argc, char *argv[])
case ' s ' :
shellflag = 1 ;
break ;
case ' e ' :
envflag = 1 ;
break ;
case ' ? ' :
usage ( ) ;
exit ( EINVAL ) ;
@ -87,6 +91,12 @@ int main (int argc, char *argv[])
}
uname = my_pw - > pw_name ;
/* Authenticate */
if ( authenticate ( uname ) ! = PAM_SUCCESS )
exit ( EXIT_FAILURE ) ;
/* Get target user and group info */
t_pw = user_to_passwd ( t_usr ) ;
if ( ! t_pw ) {
fprintf ( stderr , " user_to_passwd: %s \n " , strerror ( errno ) ) ;
@ -103,28 +113,86 @@ int main (int argc, char *argv[])
shell = " /bin/sh " ;
/* Set argc and argv */
char * command = NULL ;
int size , popind = optind ;
if ( argc - optind ) {
for ( size = 0 ; optind < argc ; optind + + )
size + = strlen ( argv [ optind ] ) + 1 ;
command = malloc ( sizeof ( char ) * size + 1 ) ;
if ( ! command ) {
int c_argc = argc - optind ;
char * * c_argv ;
if ( c_argc ) {
c_argv = malloc ( sizeof ( char * ) * ( c_argc + 1 ) ) ;
if ( ! c_argv ) {
fprintf ( stderr , " malloc: %s \n " , strerror ( errno ) ) ;
exit ( errno ) ;
}
for ( int i = 0 ; optind < argc ; optind + + , i + + ) {
c_argv [ i ] = strdup ( argv [ optind ] ) ;
if ( ! c_argv [ i ] ) {
fprintf ( stderr , " strdup: %s \n " , strerror ( errno ) ) ;
exit ( errno ) ;
}
}
} else {
c_argc = 1 ;
c_argv = malloc ( sizeof ( char * ) * ( c_argc + 1 ) ) ;
if ( ! c_argv ) {
fprintf ( stderr , " malloc: %s \n " , strerror ( errno ) ) ;
exit ( errno ) ;
}
memset ( command , 0 , size + 1 ) ;
for ( optind = popind ; optind < argc ; optind + + ) {
strcat ( command , argv [ optind ] ) ;
strcat ( command , " " ) ;
c_argv [ 0 ] = strdup ( shell ) ;
if ( ! c_argv [ 0 ] ) {
fprintf ( stderr , " strdup: %s \n " , strerror ( errno ) ) ;
exit ( errno ) ;
}
}
c_argv [ c_argc ] = NULL ;
struct env_elem {
char * name ;
char * value ;
} ;
struct env_elem env_keep [ ] = {
{ " PATH " , NULL } ,
{ " TERM " , NULL } ,
{ " EDITOR " , NULL } ,
{ " VISUAL " , NULL } ,
{ " DISPLAY " , NULL } ,
{ " XAUTHORITY " , NULL } ,
{ NULL , NULL }
} ;
struct env_elem env_mod [ ] = {
{ " USER " , t_pw - > pw_name } ,
{ " LOGNAME " , t_pw - > pw_name } ,
{ " SHELL " , t_pw - > pw_shell } ,
{ " HOME " , t_pw - > pw_dir } ,
{ NULL , NULL }
} ;
if ( envflag ) { /* clear env */
for ( int i = 0 ; env_keep [ i ] . name ; i + + )
env_keep [ i ] . value = strdup ( getenv ( env_keep [ i ] . name ) ) ;
environ = NULL ; // in place of clearenv
}
/* Authenticate */
if ( authenticate ( uname ) ! = PAM_SUCCESS )
exit ( EXIT_FAILURE ) ;
for ( int i = 0 ; env_mod [ i ] . name ; i + + ) {
err = setenv ( env_mod [ i ] . name , env_mod [ i ] . value , 1 ) ;
if ( err = = - 1 ) {
fprintf ( stderr , " setenv: %s \n " , strerror ( errno ) ) ;
goto fail_end ;
}
}
// TODO: clean up env
if ( envflag ) {
for ( int i = 0 ; env_keep [ i ] . name ; i + + ) {
if ( env_keep [ i ] . value ) {
err = setenv ( env_keep [ i ] . name , env_keep [ i ] . value , 1 ) ;
if ( err = = - 1 ) {
fprintf ( stderr , " setenv: %s \n " , strerror ( errno ) ) ;
goto fail_end ;
}
}
}
}
// do not override, we might be under more levels of 'us'
err = setenv ( " US_USER " , my_pw - > pw_name , 0 ) ;
errno = 0 ;
/* Set permissions */
@ -134,18 +202,16 @@ int main (int argc, char *argv[])
}
/* Execute the command */
int err ;
if ( command )
err = execl ( shell , shell , " -c " , command , ( char * ) NULL ) ;
else
err = execl ( shell , shell , ( char * ) NULL ) ;
err = execvp ( c_argv [ 0 ] , c_argv ) ;
if ( err = = - 1 )
fprintf ( stderr , " execl: %s \n " , strerror ( errno ) ) ;
/* Cleanup and return */
fail_end :
/* Free up the copied argv */
free ( command ) ;
for ( int i = 0 ; c_argv [ i ] ; i + + )
free ( c_argv [ i ] ) ;
free ( c_argv ) ;
return errno ;
}
@ -159,7 +225,7 @@ static inline void usage (void)
// -c [file]: manually select config file
// something about environment
// something about non interactiveness
printf ( " usage: us [-s] [-u user] [-g group] command [args] \n " ) ;
printf ( " usage: us [-se ] [-u user] [-g group] command [args] \n " ) ;
}
static int perm_set ( struct passwd * pw , struct group * gr )
@ -189,7 +255,6 @@ static int perm_set (struct passwd *pw, struct group *gr)
return - 1 ;
}
// FIXME: ideally when failing reset the permissions
if ( setregid ( gid , gid ) = = - 1 ) {
printf ( " setregid failed \n " ) ;
return - 1 ;
@ -207,24 +272,29 @@ static int authenticate (const char *uname)
{
pam_handle_t * pamh ;
int pam_err , count = 0 ;
pam_err = pam_start ( " User Switcher " , uname , & conv , & pamh ) ;
if ( pam_err ! = PAM_SUCCESS ) {
fprintf ( stderr , " pam_start: %s \n " , pam_strerror ( pamh , pam_err ) ) ;
return pam_err ;
}
do {
pam_err = pam_start ( " User Switcher " , uname , & conv , & pamh ) ;
if ( pam_err ! = PAM_SUCCESS ) {
fprintf ( stderr , " pam_start: %s \n " , pam_strerror ( pamh , pam_err ) ) ;
return pam_err ;
}
pam_err = pam_authenticate ( pamh , 0 ) ;
if ( pam_err ! = PAM_SUCCESS )
if ( pam_err = = PAM_SUCCESS ) {
pam_err = pam_acct_mgmt ( pamh , 0 ) ;
}
if ( pam_err ! = PAM_SUCCESS ) {
printf ( " Auth failed: %s \n " , pam_strerror ( pamh , pam_err ) ) ;
// FIXME: count gets ignored because authentication service has
// a set amount of retries giving an error:
// Have exhausted maximum number of retries for service
pam_end ( pamh , pam_err ) ;
}
count + + ;
} while ( pam_err ! = PAM_SUCCESS & & count < 4 ) ;
} while ( pam_err ! = PAM_SUCCESS & & count < 3 ) ;
if ( pam_err ! = PAM_SUCCESS ) {
fprintf ( stderr , " better luck next time \n " ) ;
pam_end ( pamh , pam_err ) ;
return pam_err ;
}
// FIXME: check again for the validity of the login for more security