/* 
 * file:	 login.c
 * descripton:	 login into a user account
 * author:	 Alistair Riddoch
 * modification: David Murn <scuffer@hups.apana.org.au>
 *		 Added password entry
 * modification: Shane Kerr <kerr@wizard.net>
 *		 More work on password entry
 */

/* todo:  use a non-echoing input routine for password (i.e. getpass) */
/*	  needs a more robust tty first
/* todo:  add a timeout for serial and network logins */
/*	  need a signal mechanism (i.e. alarm() and SIGALRM) */

#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>

void login(pwd)
struct passwd *pwd;
{
	char *tmpstr;

	if ((tmpstr=ttyname(0)))
	{	if (chown(tmpstr,pwd->pw_uid,pwd->pw_gid)<0)
			perror("chown");
	}
	else
		write(STDERR_FILENO, "login: warning: could not locate tty\n", 37);

	if (setgid(pwd->pw_gid)<0)
	{	perror("setgid");
		exit(1);
	}
	if (setuid(pwd->pw_uid)<0)
	{	perror("setuid");
		exit(1);
	}

	tmpstr = malloc(strlen(pwd->pw_name)+6);
	strcpy(tmpstr,"USER=");
	strcpy(tmpstr+5,pwd->pw_name);
	putenv(tmpstr);

	tmpstr = malloc(strlen(pwd->pw_dir)+6);
	strcpy(tmpstr,"HOME=");
	strcpy(tmpstr+5,pwd->pw_dir);
	putenv(tmpstr);

	tmpstr = malloc(strlen(pwd->pw_shell)+7);
	strcpy(tmpstr,"SHELL=");
	strcpy(tmpstr+6,pwd->pw_shell);
	putenv(tmpstr);

	tmpstr = malloc(strlen(pwd->pw_shell)+2);
	*tmpstr = '-';
	strcpy(tmpstr+1,pwd->pw_shell);

	if (chdir(pwd->pw_dir)<0)
		perror("chdir");

	execl(pwd->pw_shell,tmpstr,(char*)0);

	perror("execve");
	exit(1);
}

void main(argc,argv)
int argc;
char ** argv;
{
	struct passwd *pwd;
	char lbuf[20], pbuf[20], salt[3];
	int n;
	
	for (;;) {
		write(STDOUT_FILENO,"login: ",7);
		if (fgets(lbuf, sizeof(lbuf), stdin) == NULL) {
		    exit(1);
		}
		n = strlen(lbuf)-1;
		if (lbuf[n] == '\n') {
		    lbuf[n] = 0;
		}
		pwd = getpwnam(lbuf);
		if ((pwd != NULL) && (pwd->pw_passwd[0] == 0)) {
			login(pwd);
		}
		write(STDOUT_FILENO,"Password: ",10);
		if (fgets(pbuf, sizeof(pbuf), stdin) == NULL) {
		    exit(1);
		}
		n = strlen(pbuf)-1;
		if (pbuf[n] == '\n') {
		    pbuf[n] = 0;
		}
		if (pwd != NULL) {
			salt[0]=pwd->pw_passwd[0];
			salt[1]=pwd->pw_passwd[1];
			salt[2]=0;
			if (!strcmp(crypt(pbuf,salt),pwd->pw_passwd)) {
				login(pwd);
			}
			free(pwd);
		}
		write(STDOUT_FILENO,"Login incorrect\n\n",17); 
	}
}
