/*-------------------------------------------------------*/
/* xlogin.c ( NTHU CS MapleBBS Ver 2.36 ) */
/*-------------------------------------------------------*/
/* target : replace /bin/login for BBS */
/* create : 95/03/29 */
/* update : 95/12/15 */
/*-------------------------------------------------------*/
#include "config.h"
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/file.h>
#include <termios.h>
#ifdef HAS_UTMPX
#include <utmpx.h>
#else /* HAS_UTMPX */
#include <utmp.h>
#endif /* HAS_UTMPX */
#ifndef UT_NAMESIZE
#define UT_NAMESIZE sizeof(((struct UTMP_STRUCT *)0)->ut_name)
#endif /* UT_NAMESIZE */
#include <signal.h>
#include <errno.h>
#ifndef NO_TTYENT
#include <ttyent.h>
#endif /* NO_TTYENT */
#include <syslog.h>
#include <grp.h>
#include <pwd.h>
#include <setjmp.h>
#include <stdio.h>
#include <string.h>
#ifndef TIOCSWINSZ
#include <sys/ioctl.h>
#endif
#ifndef O_RDWR
#include <fcntl.h>
#endif
#define TTYGRPNAME "tty" /* name of group to own ttys */
/* HP-UX 9.0 termios doesn't define these */
#ifndef FLUSHO
#define FLUSHO 0
#define XTABS 0
#endif
#ifndef OXTABS
#define OXTABS XTABS
#endif
#define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin:"
/*
#define _PATH_UTMP "/etc/utmp"
*/
struct passwd *pwd;
char term[64], *hostname, *username, *tty;
char xuser[sizeof(BBSUSER)] = BBSUSER;
char xdir[sizeof(BBSHOME)] = BBSHOME;
char xshell[sizeof(BBSSHELL)] = BBSSHELL;
struct termios termios;
void
login(ut)
struct utmp *ut;
{
register int fd;
int tty;
off_t lseek();
tty = ttyslot();
if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY, 0)) >= 0)
{
(void) lseek(fd, (long) (tty * sizeof(struct utmp)), L_SET);
(void) write(fd, (char *) ut, sizeof(struct utmp));
(void) close(fd);
}
}
main(argc, argv)
int argc;
char **argv;
{
extern int optind;
extern char *optarg, **environ;
struct group *gr;
register int ch;
register char *p;
int hflag, pflag, cnt;
int ioctlval;
void hungup();
char *salt, *ttyn, *pp = 0;
char *ttyname(), *stypeof();
time_t time();
pwd = (struct passwd *) malloc(sizeof(struct passwd));
/* Do this before NIS+ or other library routines open files. */
for (cnt = getdtablesize(); cnt > 2; cnt--)
close(cnt);
(void) signal(SIGHUP, hungup);
(void) signal(SIGQUIT, SIG_IGN);
(void) signal(SIGINT, SIG_IGN);
(void) setpriority(PRIO_PROCESS, 0, 0);
/*
* -p is used by getty to tell login not to destroy the environment -h is
* used by other servers to pass the name of the remote host to login so
* that it may be placed in utmp and wtmp
*/
hflag = pflag = 0;
while ((ch = getopt(argc, argv, "h:p")) != EOF)
switch (ch)
{
case 'h':
if (getuid())
{
fprintf(stderr, "login: -h for super-user only.\n");
exit(1);
}
hflag = 1;
hostname = optarg;
break;
#ifndef SYSV_ENV /* System V login never preserves the
* environment. */
case 'p':
pflag = 1;
break;
#endif /* SYSV_ENV */
default:
if (getuid())
syslog(LOG_ERR, "invalid flag %c", ch);
fprintf(stderr, "usage: login [-h | -r] [username]\n");
exit(1);
}
argc -= optind;
argv += optind;
if (*argv)
{
username = *argv;
#ifdef SYSV_ENV /* Pick up additional environment stuff after
* logging in. */
argc--;
argv++;
#endif /* SYSV_ENV */
}
/*
* Finalize the terminal settings. Some systems default to 8 bits, others
* to 7, so we should leave that alone.
*/
tcgetattr(0, &termios);
termios.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON | IMAXBEL);
termios.c_iflag &= ~IXANY;
termios.c_lflag |= (ISIG | IEXTEN | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE);
termios.c_lflag &= ~(ECHOPRT | TOSTOP | FLUSHO);
termios.c_oflag |= (OPOST | ONLCR);
termios.c_oflag &= ~OXTABS;
termios.c_cc[VEOF] = 4;
(void) tcsetattr(0, TCSANOW, &termios);
/*
* Determine the tty name. BSD takes the basename, SYSV4 takes whatever
* remains after stripping the "/dev/" prefix. The code below should
* produce sensible results in either environment.
*/
ttyn = ttyname(0);
if (ttyn == NULL || *ttyn == '\0')
ttyn = "/dev/tty??";
if (tty = strchr(ttyn + 1, '/'))
++tty;
else
tty = ttyn;
/* setup pwd struct */
pwd->pw_name = xuser;
pwd->pw_uid = 9999;
pwd->pw_gid = 99;
pwd->pw_dir = xdir;
pwd->pw_shell = xshell;
/* Update the utmp files, either BSD or SYSV style. */
{
struct utmp utmp;
memset((char *) &utmp, 0, sizeof(utmp));
(void) time(&utmp.ut_time);
#if 0
strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
if (hostname)
strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
login(&utmp);
#endif
}
(void) chown(ttyn, pwd->pw_uid,
(gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
(void) chmod(ttyn, 0620);
/* Give up root privileges: no way back from here. */
if (setgid(pwd->pw_gid))
{
printf("login: bad gid: %d\n", pwd->pw_gid);
sleepexit(0);
}
#if 0
initgroups(username, pwd->pw_gid);
#endif
if (setuid(pwd->pw_uid))
{
printf("login: bad uid: %d\n", pwd->pw_uid);
sleepexit(0);
}
/*
* Now that we have given up root privilege do the stuff that must be done
* as the real user: Kerberos or Secure RPC authentication, entering the
* (possibly remote) home directory.
*/
/* Change to home directory */
if (chdir(pwd->pw_dir))
{
printf("No directory %s!\n", pwd->pw_dir);
sleepexit(0);
}
/*
* Set up a new environment. With SYSV, some variables are always
* preserved; some varables are never preserved, and some variables are
* always clobbered. With BSD, nothing is always preserved, and some
* variables are always clobbered. We add code to make sure that LD_* and
* IFS are never preserved.
*/
#ifdef SYSV_ENV
/* set up a somewhat censored environment. */
sysv_newenv(argc, argv, pwd, term);
#else /* SYSV_ENV */
/* destroy environment unless user has requested preservation */
if (!pflag)
environ[0] = 0;
else
fixenv(environ);
(void) setenv("HOME", pwd->pw_dir, 1);
(void) setenv("SHELL", pwd->pw_shell, 1);
(void) setenv("REMOTEHOST", hostname, 1);
#ifndef NO_TTYENT
if (!pflag || !getenv("TERM"))
{
if (term[0] == 0)
strncpy(term, stypeof(tty), sizeof(term));
(void) setenv("TERM", term, 0);
}
#endif /* NO_TTYENT */
(void) setenv("USER", pwd->pw_name, 1);
(void) setenv("PATH", _PATH_DEFPATH, 0);
#endif /* SYSV_ENV */
/*
* After dropping privileges and after cleaning up the environment,
* optionally run, as the user, /bin/passwd.
*/
(void) signal(SIGALRM, SIG_DFL);
(void) signal(SIGHUP, SIG_DFL);
(void) signal(SIGQUIT, SIG_DFL);
(void) signal(SIGINT, SIG_DFL);
(void) signal(SIGTSTP, SIG_IGN);
execl(BBSPROG, "bbs", hostname, ttyn, NULL);
fprintf(stderr, "login: no shell: ");
perror(BBSPROG);
sleepexit(0);
}
void
hungup()
{
close(0); /* force EOF */
}
#ifndef NO_TTYENT
/* get terminal type from ttytab file */
#undef UNKNOWN
#define UNKNOWN "su"
char *
stypeof(ttyid)
char *ttyid;
{
struct ttyent *t;
return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
}
#endif /* !NO_TTYENT */
sleepexit(eval)
int eval;
{
sleep((u_int) 5);
exit(eval);
}
setenv(name, value, overwrite)
#ifdef NETBSD
const char *name;
const char *value;
#else
char *name;
char *value;
#endif
int overwrite;
{
char *p;
if (overwrite == 0 && getenv(name) != 0)
return (0);
if ((p = malloc(strlen(name) + strlen(value) + 2)) == 0)
{
fprintf(stderr, "out of memory\n");
sleepexit(1);
}
sprintf(p, "%s=%s", name, value);
return (putenv(p));
}
fixenv(cpp)
char **cpp;
{
register char **xpp;
register char *cp;
while (cp = *cpp)
{
if (strncmp(cp, "LD_", 3) == 0 || strncmp(cp, "IFS=", 4) == 0)
{
for (xpp = cpp; xpp[0] = xpp[1]; xpp++);
/* void */ ;
}
else
{
cpp++;
}
}
}