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 >
C/C++ Source or Header  |  1998-06-16  |  8KB  |  329 lines

  1. /*  q2getty.c
  2.  *  Derived from /bin/login and...
  3.  *
  4.  *  mingetty.c
  5.  *
  6.  *  Copyright (C) 1996 Florian La Roche
  7.  *  florian@jurix.jura.uni-sb.de florian@suse.de
  8.  *
  9.  *  This program is free software; you can redistribute it and/or
  10.  *  modify it under the terms of the GNU General Public License
  11.  *  as published by the Free Software Foundation; either version
  12.  *  2 of the License, or (at your option) any later version.
  13.  *
  14.  */
  15.  
  16. #define DEBUG_THIS 0
  17.  
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <sys/ioctl.h>
  23. #include <sys/resource.h>
  24. #include <errno.h>
  25. #include <sys/stat.h>
  26. #include <sys/file.h>
  27. #include <signal.h>
  28. #include <pwd.h>
  29. #include <grp.h>
  30. #include <fcntl.h>
  31. #include <stdarg.h>
  32. #include <ctype.h>
  33. #include <getopt.h>
  34.  
  35. #ifdef linux
  36. #include <sys/param.h>
  37. #define USE_SYSLOG
  38. #define USE_TTY_GROUP
  39. #endif
  40.  
  41. #ifdef USE_TTY_GROUP
  42. #  define TTY_MODE 0620
  43. #else
  44. #  define TTY_MODE 0600
  45. #endif
  46.  
  47. #define    TTYGRPNAME    "tty"        /* name of group to own ttys */
  48.  
  49.  /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */
  50. #ifdef    USE_SYSLOG
  51. #include <sys/syslog.h>
  52. #endif
  53. #include <time.h>
  54.  
  55. /* name of this program (argv[0]) */
  56. static char *progname;
  57. /* on which tty line are we sitting? (e.g. tty1) */
  58. static char *tty;
  59. static pid_t pid;
  60. /* current time */
  61. static time_t cur_time;
  62. /* do not send a reset string to the terminal ? */
  63. static int noclear = 0;
  64.  
  65. static char ttyn[32], vcsn[32], vcsan[32];
  66.  
  67. /*
  68.  * output error messages
  69.  */
  70. static void error (const char *fmt, ...)
  71. {
  72.     va_list va_alist;
  73.     char buf[256], *bp;
  74. #ifndef    USE_SYSLOG
  75.     int fd;
  76. #endif
  77.  
  78. #ifdef USE_SYSLOG
  79.     buf[0] = '\0';
  80.     bp = buf;
  81. #else
  82.     strcpy (buf, progname);
  83.     strcat (buf, ": ");
  84.     bp = buf + strlen (buf);
  85. #endif
  86.  
  87.     va_start (va_alist, fmt);
  88.     vsprintf (bp, fmt, va_alist);
  89.     va_end (va_alist);
  90.  
  91. #ifdef    USE_SYSLOG
  92.     openlog (progname, LOG_PID, LOG_AUTH);
  93.     syslog (LOG_ERR, buf);
  94.     closelog ();
  95. #else
  96.     strcat (bp, "\r\n");
  97.     if ((fd = open ("/dev/console", 1)) >= 0) {
  98.         write (fd, buf, strlen (buf));
  99.         close (fd);
  100.     }
  101. #endif
  102.     chdir("/");
  103.     sleep(5);        /* avoid spinning */
  104.     exit (1);
  105. }
  106.  
  107. /* open_tty - set up tty as standard { input, output, error } */
  108. static void open_tty (void)
  109. {
  110.     struct sigaction sa;
  111.     char buf[20];
  112.     int fd;
  113.  
  114.     /* Set up new standard input. */
  115.     strcpy (buf, "/dev/");
  116.     strcat (buf, tty);
  117.     if (chown (buf, 0, 0) || chmod (buf, 0600))
  118.         error ("%s: %s", buf, strerror(errno));
  119.     strcpy(ttyn, buf);
  120.  
  121.     /* find names of Virtual Console devices, for later mode change */
  122.     {
  123.         char *p = ttyn;
  124.         /* find number of tty */
  125.         while (*p && !isdigit(*p)) p++;
  126.         strcpy(vcsn, "/dev/vcs"); strcat(vcsn, p);
  127.         strcpy(vcsan, "/dev/vcsa"); strcat(vcsan, p);
  128.     }
  129.  
  130.     sa.sa_handler = SIG_IGN;
  131.     sa.sa_flags = 0;
  132.     sigemptyset (&sa.sa_mask);
  133.     sigaction (SIGHUP, &sa, NULL);
  134.  
  135.     /* vhangup() will replace all open file descriptors that point to our
  136.        controlling tty by a dummy that will deny further reading/writing
  137.        to our device. It will also reset the tty to sane defaults, so we
  138.        don't have to modify the tty device for sane settings.
  139.        We also get a SIGHUP/SIGCONT.
  140.      */
  141.     if ((fd = open (buf, O_RDWR, 0)) < 0
  142.         || ioctl (fd, TIOCSCTTY, (void *)1) == -1)
  143.         error ("%s: cannot open tty: %s", buf, strerror(errno));
  144.     if (!isatty (fd))
  145.         error ("%s: not a tty", buf);
  146.  
  147.     vhangup ();
  148.     /* Get rid of the present stdout/stderr. */
  149.     close (2);
  150.     close (1);
  151.     close (0);
  152.     close (fd);
  153.     /* ioctl (0, TIOCNOTTY, (char *)1); */
  154.  
  155.     if (open (buf, O_RDWR, 0) != 0)
  156.         error ("%s: cannot open as standard input: %s", buf,
  157.                 strerror(errno));
  158.  
  159.     /* Set up standard output and standard error file descriptors. */
  160.     if (dup (0) != 1 || dup (0) != 2)
  161.         error ("%s: dup problem: %s", buf, strerror(errno));
  162.  
  163.     /* Write a reset string to the terminal. This is very linux-specific
  164.        and should be checked for other systems. */
  165.     if (! noclear)
  166.         write (0, "\033c", 2);
  167.  
  168.     sa.sa_handler = SIG_DFL;
  169.     sa.sa_flags = 0;
  170.     sigemptyset (&sa.sa_mask);
  171.     sigaction (SIGHUP, &sa, NULL);
  172.  
  173. #if    DEBUG_THIS
  174.     printf ("session=%d, pid=%d, pgid=%d\n", getsid (0), getpid (),
  175.             getpgid (0));
  176. #endif
  177. }
  178.  
  179. static void usage (void)
  180. {
  181.     error ("usage: '%s <tty> <username> <program> [<args> ...]'", progname);
  182. }
  183.  
  184. /*
  185.  * main program
  186.  */
  187. int main (int argc, char **argv)
  188. {
  189.     char *cp;
  190.     uid_t uid;
  191.     gid_t gid;
  192.     char *user;
  193.     struct passwd *pwp;
  194.     struct group *gr;
  195.     char prog[256];
  196.     char cwd[256];
  197.     extern char **environ;
  198.     int chdirhome = 0;
  199.  
  200.     progname = argv[0];
  201.     pid = getpid ();
  202.     time (&cur_time);
  203. #if 1
  204.     putenv ("TERM=linux");
  205. #endif
  206.  
  207.     if (argc < 4)
  208.         usage();
  209.  
  210.     tty = argv[1];
  211.     user = argv[2];
  212.     memset(prog, 0, sizeof(prog));
  213.     strncpy(prog, argv[3], sizeof(prog) - 1);
  214.  
  215.     if (strncmp(tty, "tty", 3) != 0)
  216.         usage();
  217.  
  218.     open_tty ();
  219.     /* Note:  now can use fprintf(), etc */
  220.  
  221.     if (isdigit(user[0])) {
  222.         uid = (uid_t) atoi(user);
  223.         pwp = getpwuid(uid);    /* Do this so we can get the gid to use. */
  224.         if (pwp == NULL) {
  225.             fprintf(stderr, "uid %d not registered in passwd file\n", (int) uid);
  226.             error ("%s: uid %d not registered in passwd file", tty, (int) uid);
  227.         }
  228.     } else {
  229.         pwp = getpwnam(user);
  230.         if (pwp == NULL) {
  231.             fprintf(stderr, "unknown user \"%s\"\n", user);
  232.             error ("%s: unknown user \"%s\"", tty, user);
  233.         }
  234.         uid = pwp->pw_uid;
  235.     }
  236.     gid = pwp->pw_gid;
  237.  
  238.     if (prog[0] != '/') {
  239.         fprintf(stderr, "Not an absolute pathname: %s\n", prog);
  240.         error("%s: Not an absolute pathname: %s", tty, prog);
  241.     } else if (access(prog, X_OK) < 0) {
  242.         fprintf(stderr, "cannot execute: %s: %s\n", prog, strerror(errno));
  243.         error("%s: cannot execute: %s: %s", tty, prog, strerror(errno));
  244.     }
  245.  
  246.     /* Do some stuff that /bin/login would do. */
  247.     setpriority(PRIO_PROCESS, 0, 0);
  248.  
  249.     chown(ttyn, pwp->pw_uid, (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwp->pw_gid);
  250.     chmod(ttyn, TTY_MODE);
  251.  
  252.     /* if tty is one of the VC's (yes) then change owner and mode of the special /dev/vcs devices as well */
  253.     chown(vcsn, pwp->pw_uid, (gr ? gr->gr_gid : pwp->pw_gid));
  254.     chown(vcsan, pwp->pw_uid, (gr ? gr->gr_gid : pwp->pw_gid));
  255.     chmod(vcsn, TTY_MODE);
  256.     chmod(vcsan, TTY_MODE);
  257.  
  258.     setpgrp();
  259.     setsid();
  260.  
  261.     /* Do what /bin/login would do and nuke the environment and
  262.      * build a new one.
  263.      */
  264.     environ = (char **) malloc(sizeof(char *));
  265.     memset(environ, 0, sizeof(char *));
  266.     setenv("HOME", pwp->pw_dir, 1);
  267.     setenv("SHELL", pwp->pw_shell, 1);
  268.     setenv("TERM", "linux", 0);
  269.     setenv("USER", pwp->pw_name, 1);
  270.     setenv("LOGNAME", pwp->pw_name, 1);
  271.     if (uid == 0) {
  272.         setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
  273.     } else {
  274.         setenv("PATH", "/usr/local/bin:/bin:/usr/bin:.", 1);
  275.     }
  276.  
  277.     /* Other stuff that /bin/login does. Try to do everything but manage utmp. */
  278.     signal(SIGALRM, SIG_DFL);
  279.     signal(SIGQUIT, SIG_DFL);
  280.     signal(SIGINT, SIG_DFL);
  281.     signal(SIGTSTP, SIG_IGN);
  282.     signal(SIGHUP, SIG_DFL);
  283.  
  284.     /* Sleep now to prevent spinning if an error occurs in the program
  285.      * right away.
  286.      */
  287.     sleep(5);
  288.  
  289.     /* Change to the directory the program is in, if not /bin.
  290.      * Generally this is not a good idea for daemon processes,
  291.      * since it could make unmounting filesystems difficult.
  292.      * (The sleep above helps.)
  293.      */
  294.     strncpy(cwd, prog, sizeof(cwd));
  295.     if (strncmp(cwd, "/bin/", 5) == 0)
  296.         chdirhome++;
  297.  
  298.     cp = strrchr(cwd, '/');
  299.     if (cp != cwd) {
  300.         *cp = '\0';
  301.         if (chdir(cwd) < 0)
  302.             chdirhome++;
  303.     }
  304.  
  305.     argv[3] = strrchr(prog, '/') + 1;
  306.  
  307. #if 0
  308. #ifdef linux
  309.     ioctl (0, TIOCSPGRP, &pid);
  310. #endif
  311. #endif
  312.     /* flush input and output queues, important for modems */
  313.     ioctl (0, TCFLSH, 2);
  314.  
  315.     /* Last, but not least... */
  316.     initgroups(user, gid);
  317.     (void) setgid(gid);
  318.     (void) setuid(uid);
  319.     if ((chdirhome > 0) && (chdir(pwp->pw_dir)) < 0)
  320.         (void) chdir("/");
  321.     endpwent();
  322.  
  323.     time(&cur_time);
  324.     fprintf(stderr, "Launching %s at %s\n", prog, ctime(&cur_time));
  325.     execv (prog, argv + 3);
  326.     error ("%s: can't exec %s: %s", tty, prog, strerror(errno));
  327.     exit (0);
  328. }
  329.