home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.ncftp.com
/
ftp.ncftp.com.zip
/
ftp.ncftp.com
/
unixstuff
/
q2getty.tar.gz
/
q2getty.tar
/
q2getty
/
q2getty.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
8KB
|
329 lines
/* q2getty.c
* Derived from /bin/login and...
*
* mingetty.c
*
* Copyright (C) 1996 Florian La Roche
* florian@jurix.jura.uni-sb.de florian@suse.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#define DEBUG_THIS 0
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <fcntl.h>
#include <stdarg.h>
#include <ctype.h>
#include <getopt.h>
#ifdef linux
#include <sys/param.h>
#define USE_SYSLOG
#define USE_TTY_GROUP
#endif
#ifdef USE_TTY_GROUP
# define TTY_MODE 0620
#else
# define TTY_MODE 0600
#endif
#define TTYGRPNAME "tty" /* name of group to own ttys */
/* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */
#ifdef USE_SYSLOG
#include <sys/syslog.h>
#endif
#include <time.h>
/* name of this program (argv[0]) */
static char *progname;
/* on which tty line are we sitting? (e.g. tty1) */
static char *tty;
static pid_t pid;
/* current time */
static time_t cur_time;
/* do not send a reset string to the terminal ? */
static int noclear = 0;
static char ttyn[32], vcsn[32], vcsan[32];
/*
* output error messages
*/
static void error (const char *fmt, ...)
{
va_list va_alist;
char buf[256], *bp;
#ifndef USE_SYSLOG
int fd;
#endif
#ifdef USE_SYSLOG
buf[0] = '\0';
bp = buf;
#else
strcpy (buf, progname);
strcat (buf, ": ");
bp = buf + strlen (buf);
#endif
va_start (va_alist, fmt);
vsprintf (bp, fmt, va_alist);
va_end (va_alist);
#ifdef USE_SYSLOG
openlog (progname, LOG_PID, LOG_AUTH);
syslog (LOG_ERR, buf);
closelog ();
#else
strcat (bp, "\r\n");
if ((fd = open ("/dev/console", 1)) >= 0) {
write (fd, buf, strlen (buf));
close (fd);
}
#endif
chdir("/");
sleep(5); /* avoid spinning */
exit (1);
}
/* open_tty - set up tty as standard { input, output, error } */
static void open_tty (void)
{
struct sigaction sa;
char buf[20];
int fd;
/* Set up new standard input. */
strcpy (buf, "/dev/");
strcat (buf, tty);
if (chown (buf, 0, 0) || chmod (buf, 0600))
error ("%s: %s", buf, strerror(errno));
strcpy(ttyn, buf);
/* find names of Virtual Console devices, for later mode change */
{
char *p = ttyn;
/* find number of tty */
while (*p && !isdigit(*p)) p++;
strcpy(vcsn, "/dev/vcs"); strcat(vcsn, p);
strcpy(vcsan, "/dev/vcsa"); strcat(vcsan, p);
}
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigemptyset (&sa.sa_mask);
sigaction (SIGHUP, &sa, NULL);
/* vhangup() will replace all open file descriptors that point to our
controlling tty by a dummy that will deny further reading/writing
to our device. It will also reset the tty to sane defaults, so we
don't have to modify the tty device for sane settings.
We also get a SIGHUP/SIGCONT.
*/
if ((fd = open (buf, O_RDWR, 0)) < 0
|| ioctl (fd, TIOCSCTTY, (void *)1) == -1)
error ("%s: cannot open tty: %s", buf, strerror(errno));
if (!isatty (fd))
error ("%s: not a tty", buf);
vhangup ();
/* Get rid of the present stdout/stderr. */
close (2);
close (1);
close (0);
close (fd);
/* ioctl (0, TIOCNOTTY, (char *)1); */
if (open (buf, O_RDWR, 0) != 0)
error ("%s: cannot open as standard input: %s", buf,
strerror(errno));
/* Set up standard output and standard error file descriptors. */
if (dup (0) != 1 || dup (0) != 2)
error ("%s: dup problem: %s", buf, strerror(errno));
/* Write a reset string to the terminal. This is very linux-specific
and should be checked for other systems. */
if (! noclear)
write (0, "\033c", 2);
sa.sa_handler = SIG_DFL;
sa.sa_flags = 0;
sigemptyset (&sa.sa_mask);
sigaction (SIGHUP, &sa, NULL);
#if DEBUG_THIS
printf ("session=%d, pid=%d, pgid=%d\n", getsid (0), getpid (),
getpgid (0));
#endif
}
static void usage (void)
{
error ("usage: '%s <tty> <username> <program> [<args> ...]'", progname);
}
/*
* main program
*/
int main (int argc, char **argv)
{
char *cp;
uid_t uid;
gid_t gid;
char *user;
struct passwd *pwp;
struct group *gr;
char prog[256];
char cwd[256];
extern char **environ;
int chdirhome = 0;
progname = argv[0];
pid = getpid ();
time (&cur_time);
#if 1
putenv ("TERM=linux");
#endif
if (argc < 4)
usage();
tty = argv[1];
user = argv[2];
memset(prog, 0, sizeof(prog));
strncpy(prog, argv[3], sizeof(prog) - 1);
if (strncmp(tty, "tty", 3) != 0)
usage();
open_tty ();
/* Note: now can use fprintf(), etc */
if (isdigit(user[0])) {
uid = (uid_t) atoi(user);
pwp = getpwuid(uid); /* Do this so we can get the gid to use. */
if (pwp == NULL) {
fprintf(stderr, "uid %d not registered in passwd file\n", (int) uid);
error ("%s: uid %d not registered in passwd file", tty, (int) uid);
}
} else {
pwp = getpwnam(user);
if (pwp == NULL) {
fprintf(stderr, "unknown user \"%s\"\n", user);
error ("%s: unknown user \"%s\"", tty, user);
}
uid = pwp->pw_uid;
}
gid = pwp->pw_gid;
if (prog[0] != '/') {
fprintf(stderr, "Not an absolute pathname: %s\n", prog);
error("%s: Not an absolute pathname: %s", tty, prog);
} else if (access(prog, X_OK) < 0) {
fprintf(stderr, "cannot execute: %s: %s\n", prog, strerror(errno));
error("%s: cannot execute: %s: %s", tty, prog, strerror(errno));
}
/* Do some stuff that /bin/login would do. */
setpriority(PRIO_PROCESS, 0, 0);
chown(ttyn, pwp->pw_uid, (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwp->pw_gid);
chmod(ttyn, TTY_MODE);
/* if tty is one of the VC's (yes) then change owner and mode of the special /dev/vcs devices as well */
chown(vcsn, pwp->pw_uid, (gr ? gr->gr_gid : pwp->pw_gid));
chown(vcsan, pwp->pw_uid, (gr ? gr->gr_gid : pwp->pw_gid));
chmod(vcsn, TTY_MODE);
chmod(vcsan, TTY_MODE);
setpgrp();
setsid();
/* Do what /bin/login would do and nuke the environment and
* build a new one.
*/
environ = (char **) malloc(sizeof(char *));
memset(environ, 0, sizeof(char *));
setenv("HOME", pwp->pw_dir, 1);
setenv("SHELL", pwp->pw_shell, 1);
setenv("TERM", "linux", 0);
setenv("USER", pwp->pw_name, 1);
setenv("LOGNAME", pwp->pw_name, 1);
if (uid == 0) {
setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
} else {
setenv("PATH", "/usr/local/bin:/bin:/usr/bin:.", 1);
}
/* Other stuff that /bin/login does. Try to do everything but manage utmp. */
signal(SIGALRM, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGTSTP, SIG_IGN);
signal(SIGHUP, SIG_DFL);
/* Sleep now to prevent spinning if an error occurs in the program
* right away.
*/
sleep(5);
/* Change to the directory the program is in, if not /bin.
* Generally this is not a good idea for daemon processes,
* since it could make unmounting filesystems difficult.
* (The sleep above helps.)
*/
strncpy(cwd, prog, sizeof(cwd));
if (strncmp(cwd, "/bin/", 5) == 0)
chdirhome++;
cp = strrchr(cwd, '/');
if (cp != cwd) {
*cp = '\0';
if (chdir(cwd) < 0)
chdirhome++;
}
argv[3] = strrchr(prog, '/') + 1;
#if 0
#ifdef linux
ioctl (0, TIOCSPGRP, &pid);
#endif
#endif
/* flush input and output queues, important for modems */
ioctl (0, TCFLSH, 2);
/* Last, but not least... */
initgroups(user, gid);
(void) setgid(gid);
(void) setuid(uid);
if ((chdirhome > 0) && (chdir(pwp->pw_dir)) < 0)
(void) chdir("/");
endpwent();
time(&cur_time);
fprintf(stderr, "Launching %s at %s\n", prog, ctime(&cur_time));
execv (prog, argv + 3);
error ("%s: can't exec %s: %s", tty, prog, strerror(errno));
exit (0);
}